fis-gtm/sr_unix/mu_all_version_standalone.c

186 lines
7.4 KiB
C

/****************************************************************
* *
* Copyright 2005, 2011 Fidelity Information Services, Inc *
* *
* 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 "mu_all_version_standalone.h"
#ifdef __MVS__
#include "gtm_zos_io.h"
#endif
static int ftok_ids[FTOK_ID_CNT] = {1, 43};
error_def(ERR_MUSTANDALONE);
error_def(ERR_DBOPNERR);
error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
ZOS_ONLY(error_def(ERR_BADTAG);)
/* 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, 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 */
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(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(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn));
else
rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno);
}
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(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn));
else
rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno);
}
}
/* 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, downgrade and dbcertify).
*/
shmid = shmget(sem_inf[0].ftok_key, 0, RWDALL);
if (-1 == shmid)
{ /* That failed, second check is if shmid stored in file-header (if any) exists */
fd = OPEN(db_fn, O_RDONLY);
if (FD_INVALID == fd)
{
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
rts_error(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(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 = shmget(v15_csd.shmid, 0, RWDALL);
}
if (-1 != shmid)
{
mu_all_version_release_standalone(sem_inf);
rts_error(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn));
}
}
/* 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; 2 > 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 && EIDRM != errno)
{ /* Don't care if semaphore already removed */
save_errno = errno;
send_msg(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 */
}
}
}