265 lines
10 KiB
C
265 lines
10 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2001, 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 "gtm_unistd.h"
|
||
|
#include "gtm_inet.h"
|
||
|
#include "gtm_stdlib.h"
|
||
|
#include "gtm_string.h"
|
||
|
#include "gtm_stat.h"
|
||
|
#include "gtm_stdio.h"
|
||
|
#include "gtm_fcntl.h"
|
||
|
|
||
|
#include "gtm_ipc.h"
|
||
|
#include <sys/shm.h>
|
||
|
#include <errno.h>
|
||
|
#include <stddef.h>
|
||
|
#include <sys/sem.h>
|
||
|
|
||
|
#include "gdsroot.h"
|
||
|
#include "gdsblk.h"
|
||
|
#include "gtm_facility.h"
|
||
|
#include "fileinfo.h"
|
||
|
#include "gdsbt.h"
|
||
|
#include "gdsfhead.h"
|
||
|
#include "filestruct.h"
|
||
|
#include "iosp.h"
|
||
|
#include "gtmio.h"
|
||
|
#include "repl_instance.h"
|
||
|
#include "mutex.h"
|
||
|
#include "jnl.h"
|
||
|
#include "repl_sem.h"
|
||
|
#include "eintr_wrappers.h"
|
||
|
#include "mu_rndwn_file.h"
|
||
|
#include "repl_msg.h"
|
||
|
#include "gtmsource.h"
|
||
|
#include "gtmrecv.h"
|
||
|
#include "mu_rndwn_replpool.h"
|
||
|
#include "ipcrmid.h"
|
||
|
#include "do_semop.h"
|
||
|
#include "util.h"
|
||
|
#include "gtmmsg.h"
|
||
|
#include "gtm_sem.h"
|
||
|
#include "do_shmat.h" /* for do_shmat() prototype */
|
||
|
|
||
|
GBLREF jnlpool_addrs jnlpool;
|
||
|
GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
|
||
|
|
||
|
#define RELEASE_SEM(SEM_GRABBED, POOL_TYPE, STATUS, SEM_ID, INSTFILENAME) \
|
||
|
{ \
|
||
|
if (SEM_GRABBED) \
|
||
|
{ \
|
||
|
if (JNLPOOL_SEGMENT == POOL_TYPE) \
|
||
|
STATUS = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM); /* journal pool */ \
|
||
|
else \
|
||
|
STATUS = rel_sem(RECV, RECV_POOL_ACCESS_SEM); /* receive pool */ \
|
||
|
SEM_GRABBED = FALSE; \
|
||
|
if (STATUS) \
|
||
|
gtm_putmsg(VARLSTCNT(10) ERR_REPLACCSEM, 3, SEM_ID, RTS_ERROR_STRING(INSTFILENAME), \
|
||
|
ERR_TEXT, 2, LEN_AND_LIT("Error releasing semaphore"), errno); \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
#define CLNUP_REPLPOOL_ACC_SEM(SEM_ID, INSTFILENAME, SEM_GRABBED, SEM_CREATED, POOL_TYPE, STATUS) \
|
||
|
{ \
|
||
|
RELEASE_SEM(SEM_GRABBED ,POOL_TYPE, STATUS, SEM_ID, INSTFILENAME); \
|
||
|
if (SEM_CREATED) \
|
||
|
{ \
|
||
|
if (-1 == semctl(sem_id, 0, IPC_RMID)) \
|
||
|
gtm_putmsg(VARLSTCNT(10) ERR_REPLACCSEM, 3, SEM_ID, RTS_ERROR_STRING(INSTFILENAME), \
|
||
|
ERR_TEXT, 2, LEN_AND_LIT("Error removing semaphore"), errno); \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
#define MU_RNDWN_REPLPOOL_RETURN(RETVAL, SEM_ID, INSTFILENAME, SEM_GRABBED, SEM_CREATED, POOL_TYPE, STATUS) \
|
||
|
{ \
|
||
|
shmdt((void *)start_addr); \
|
||
|
CLNUP_REPLPOOL_ACC_SEM(SEM_ID, INSTFILENAME, SEM_GRABBED, SEM_CREATED, POOL_TYPE, STATUS); \
|
||
|
return RETVAL; \
|
||
|
}
|
||
|
|
||
|
LITREF char gtm_release_name[];
|
||
|
LITREF int4 gtm_release_name_len;
|
||
|
|
||
|
boolean_t mu_rndwn_replpool(replpool_identifier *replpool_id, int sem_id, int shm_id)
|
||
|
{
|
||
|
int semval, status, save_errno;
|
||
|
char *instfilename, pool_type;
|
||
|
boolean_t sem_created = FALSE, sem_grabbed = FALSE;
|
||
|
sm_uc_ptr_t start_addr;
|
||
|
struct semid_ds semstat;
|
||
|
struct shmid_ds shm_buf;
|
||
|
union semun semarg;
|
||
|
unix_db_info *udi;
|
||
|
sgmnt_addrs *csa;
|
||
|
|
||
|
error_def(ERR_REPLPOOLINST);
|
||
|
error_def(ERR_REPLACCSEM);
|
||
|
error_def(ERR_SYSCALL);
|
||
|
error_def(ERR_TEXT);
|
||
|
|
||
|
if (INVALID_SHMID == shm_id)
|
||
|
return TRUE;
|
||
|
semarg.buf = &semstat;
|
||
|
instfilename = replpool_id->instfilename;
|
||
|
pool_type = replpool_id->pool_type;
|
||
|
assert((JNLPOOL_SEGMENT == pool_type) || (RECVPOOL_SEGMENT == pool_type));
|
||
|
if (INVALID_SEMID == sem_id || (-1 == semctl(sem_id, 0, IPC_STAT, semarg)))
|
||
|
{
|
||
|
if (JNLPOOL_SEGMENT == pool_type)
|
||
|
sem_id = init_sem_set_source(IPC_PRIVATE, NUM_SRC_SEMS, RWDALL | IPC_CREAT);
|
||
|
else
|
||
|
sem_id = init_sem_set_recvr(IPC_PRIVATE, NUM_RECV_SEMS, RWDALL | IPC_CREAT);
|
||
|
if (INVALID_SEMID == sem_id)
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLACCSEM, 3, sem_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno);
|
||
|
return FALSE;
|
||
|
}
|
||
|
sem_created = TRUE;
|
||
|
} else if (JNLPOOL_SEGMENT == pool_type)
|
||
|
set_sem_set_src(sem_id);
|
||
|
else
|
||
|
set_sem_set_recvr(sem_id);
|
||
|
if (JNLPOOL_SEGMENT == pool_type)
|
||
|
status = grab_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); /* journal pool */
|
||
|
else
|
||
|
status = grab_sem_immediate(RECV, RECV_POOL_ACCESS_SEM); /* receive pool */
|
||
|
if (SS_NORMAL != status)
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLACCSEM, 3, sem_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno);
|
||
|
CLNUP_REPLPOOL_ACC_SEM(sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
sem_grabbed = TRUE;
|
||
|
if (JNLPOOL_SEGMENT == pool_type)
|
||
|
semval = semctl(sem_id, SRC_SERV_COUNT_SEM, GETVAL);
|
||
|
else
|
||
|
semval = semctl(sem_id, RECV_SERV_COUNT_SEM, GETVAL);
|
||
|
if (-1 == semval)
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLACCSEM, 3, sem_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno);
|
||
|
CLNUP_REPLPOOL_ACC_SEM(sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (0 < semval)
|
||
|
{
|
||
|
util_out_print("Replpool semaphore (id = !UL) for replication instance !AD is in use by another process.",
|
||
|
TRUE, sem_id, LEN_AND_STR(instfilename));
|
||
|
CLNUP_REPLPOOL_ACC_SEM(sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf))
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmctl()"), CALLFROM, save_errno);
|
||
|
CLNUP_REPLPOOL_ACC_SEM(sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (0 != shm_buf.shm_nattch) /* It must be zero before I attach to it */
|
||
|
{
|
||
|
util_out_print("Replpool segment (id = !UL) for replication instance !AD is in use by another process.",
|
||
|
TRUE, shm_id, LEN_AND_STR(instfilename));
|
||
|
CLNUP_REPLPOOL_ACC_SEM(sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shm_id, 0, 0)))
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmat()"), CALLFROM, save_errno);
|
||
|
CLNUP_REPLPOOL_ACC_SEM(sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
/* assert that the identifiers are at the top of replpool control structure */
|
||
|
assert(0 == offsetof(jnlpool_ctl_struct, jnlpool_id));
|
||
|
assert(0 == offsetof(recvpool_ctl_struct, recvpool_id));
|
||
|
memcpy((void *)replpool_id, (void *)start_addr, SIZEOF(replpool_identifier));
|
||
|
if (memcmp(replpool_id->label, GDS_RPL_LABEL, GDS_LABEL_SZ - 1))
|
||
|
{
|
||
|
if (!memcmp(replpool_id->label, GDS_RPL_LABEL, GDS_LABEL_SZ - 3))
|
||
|
util_out_print(
|
||
|
"Incorrect version for the replpool segment (id = !UL) belonging to replication instance !AD",
|
||
|
TRUE, shm_id, LEN_AND_STR(instfilename));
|
||
|
else
|
||
|
util_out_print("Incorrect replpool format for the segment (id = !UL) belonging to replication instance !AD",
|
||
|
TRUE, shm_id, LEN_AND_STR(instfilename));
|
||
|
MU_RNDWN_REPLPOOL_RETURN(FALSE, sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
}
|
||
|
if (memcmp(replpool_id->now_running, gtm_release_name, gtm_release_name_len + 1))
|
||
|
{
|
||
|
util_out_print("Attempt to access with version !AD, while already using !AD for replpool segment (id = !UL)"
|
||
|
" belonging to replication instance !AD.", TRUE, gtm_release_name_len, gtm_release_name,
|
||
|
LEN_AND_STR(replpool_id->now_running), shm_id, LEN_AND_STR(instfilename));
|
||
|
MU_RNDWN_REPLPOOL_RETURN(FALSE, sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
}
|
||
|
if (JNLPOOL_SEGMENT == pool_type)
|
||
|
{ /* Initialize variables to simulate a "jnlpool_init". This is required by "repl_inst_flush_jnlpool" called below */
|
||
|
jnlpool_ctl = jnlpool.jnlpool_ctl = (jnlpool_ctl_ptr_t)start_addr;
|
||
|
assert(NULL != jnlpool.jnlpool_dummy_reg);
|
||
|
udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
|
||
|
csa = &udi->s_addrs;
|
||
|
csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE);
|
||
|
/* secshr_db_clnup uses this relationship */
|
||
|
assert(jnlpool.jnlpool_ctl->filehdr_off);
|
||
|
assert(jnlpool.jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off);
|
||
|
assert(jnlpool.jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off);
|
||
|
/* Initialize "jnlpool.repl_inst_filehdr" and related fields as "repl_inst_flush_jnlpool" relies on that */
|
||
|
jnlpool.repl_inst_filehdr = (repl_inst_hdr_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl
|
||
|
+ jnlpool.jnlpool_ctl->filehdr_off);
|
||
|
jnlpool.gtmsrc_lcl_array = (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl
|
||
|
+ jnlpool.jnlpool_ctl->srclcl_array_off);
|
||
|
jnlpool.gtmsource_local_array = (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl
|
||
|
+ jnlpool.jnlpool_ctl->sourcelocal_array_off);
|
||
|
repl_inst_flush_jnlpool(FALSE); /* flush instance file header and gtmsrc_lcl structures from jnlpool to disk */
|
||
|
/* Now that jnlpool has been flushed and there is going to be no journal pool, reset "jnlpool.repl_inst_filehdr"
|
||
|
* as otherwise other routines (e.g. "repl_inst_recvpool_reset") are affected by whether this is NULL or not.
|
||
|
*/
|
||
|
jnlpool.jnlpool_ctl = NULL;
|
||
|
jnlpool_ctl = NULL;
|
||
|
jnlpool.repl_inst_filehdr = NULL;
|
||
|
jnlpool.gtmsrc_lcl_array = NULL;
|
||
|
jnlpool.gtmsource_local_array = NULL;
|
||
|
jnlpool.jnldata_base = NULL;
|
||
|
}
|
||
|
if (-1 == shmdt((caddr_t)start_addr))
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmdt()"), CALLFROM, save_errno);
|
||
|
CLNUP_REPLPOOL_ACC_SEM(sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (0 != shm_rmid(shm_id))
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shm_ctl()"), CALLFROM, save_errno);
|
||
|
MU_RNDWN_REPLPOOL_RETURN(FALSE, sem_id, instfilename, sem_grabbed, sem_created, pool_type, status);
|
||
|
}
|
||
|
RELEASE_SEM(sem_grabbed, pool_type, status, sem_id, instfilename);
|
||
|
if (0 != sem_rmid(sem_id))
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
gtm_putmsg(VARLSTCNT(5) ERR_REPLACCSEM, 3, sem_id, RTS_ERROR_STRING(instfilename));
|
||
|
gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno);
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|