/**************************************************************** * * * Copyright 2001, 2012 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 #include #include #include #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 */ #include "buddy_list.h" /* needed for muprec.h */ #include "hashtab_int4.h" /* needed for muprec.h */ #include "hashtab_int8.h" /* needed for muprec.h */ #include "hashtab_mname.h" /* needed for muprec.h */ #include "muprec.h" #include "error.h" GBLREF jnlpool_addrs jnlpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF jnl_gbls_t jgbl; GBLREF uint4 mutex_per_process_init_pid; GBLREF uint4 process_id; GBLREF mur_gbls_t murgbl; LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; error_def(ERR_REPLACCSEM); error_def(ERR_REPLINSTOPEN); error_def(ERR_REPLPOOLINST); error_def(ERR_SYSCALL); error_def(ERR_TEXT); #define ISSUE_REPLPOOLINST(SAVE_ERRNO, SHM_ID, INSTFILENAME, FAILED_OP) \ { \ gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, SHM_ID, LEN_AND_STR(INSTFILENAME)); \ gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT(FAILED_OP), CALLFROM, SAVE_ERRNO); \ } #define ISSUE_REPLPOOLINST_AND_RETURN(SAVE_ERRNO, SHM_ID, INSTFILENAME, FAILED_OP) \ { \ ISSUE_REPLPOOLINST(SAVE_ERRNO, SHM_ID, INSTFILENAME, FAILED_OP) \ return -1; \ } #define DETACH_AND_RETURN(START_ADDR, SHM_ID, INSTFILENAME) \ { \ int lcl_save_errno; \ \ if (-1 == shmdt((void *)START_ADDR)) \ { \ lcl_save_errno = errno; \ ISSUE_REPLPOOLINST_AND_RETURN(lcl_save_errno, SHM_ID, INSTFILENAME, "shmdt()"); \ } \ return -1; \ } int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t repl_inst_filehdr, int shm_id, boolean_t *ipc_rmvd) { int semval, status, save_errno, nattch; 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; assert(INVALID_SHMID != shm_id); semarg.buf = &semstat; instfilename = replpool_id->instfilename; pool_type = replpool_id->pool_type; assert((JNLPOOL_SEGMENT == pool_type) || (RECVPOOL_SEGMENT == pool_type)); if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf)) { save_errno = errno; ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shmctl()"); } nattch = shm_buf.shm_nattch; if ((0 != nattch) && !jgbl.onlnrlbk) /* It must be zero before I attach to it (except online rollback) */ { util_out_print("Replpool segment (id = !UL) for replication instance !AD is in use by another process.", TRUE, shm_id, LEN_AND_STR(instfilename)); return -1; } if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shm_id, 0, 0))) { save_errno = errno; ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shmat()"); } ESTABLISH_RET(mu_rndwn_replpool_ch, -1); /* 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)); DETACH_AND_RETURN(start_addr, shm_id, instfilename); } 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)); DETACH_AND_RETURN(start_addr, shm_id, instfilename); } /* Assert that if we haven't yet attached to the journal pool yet, we have the corresponding global vars set to NULL */ assert((JNLPOOL_SEGMENT != pool_type) || ((NULL == jnlpool.jnlpool_ctl) && (NULL == jnlpool_ctl))); 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); csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE + SIZEOF(mutex_spin_parms_struct)); /* 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); if (0 == nattch) { /* No one attached. So, we can safely flush the journal pool so that the gtmsrc_lcl structures in the * jnlpool and disk are in sync with each other. More importantly we are about to remove the jnlpool * so we better get things in sync before that. */ /* If mu_rndwn_repl_instance created new semaphores (in mu_replpool_remove_sem), we need to flush those * to the instance file as well. So, override the jnlpool_semid and jnlpool_semid_ctime with the new * values. */ assert((INVALID_SEMID != repl_inst_filehdr->jnlpool_semid) && (0 != repl_inst_filehdr->jnlpool_semid_ctime)); jnlpool.repl_inst_filehdr->jnlpool_semid = repl_inst_filehdr->jnlpool_semid; jnlpool.repl_inst_filehdr->jnlpool_semid_ctime = repl_inst_filehdr->jnlpool_semid_ctime; repl_inst_flush_jnlpool(FALSE, TRUE); assert(!jnlpool.repl_inst_filehdr->crash); /* Refresh local copy (repl_inst_filehdr) with the copy that was just flushed (jnlpool.repl_inst_filehdr) */ memcpy(repl_inst_filehdr, jnlpool.repl_inst_filehdr, SIZEOF(repl_inst_hdr)); /* 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.gtmsrc_lcl_array = NULL; jnlpool.gtmsource_local_array = NULL; jnlpool.jnldata_base = NULL; jnlpool.repl_inst_filehdr = NULL; } /* else we are ONLINE ROLLBACK. repl_inst_flush_jnlpool will be done later after gvcst_init in mur_open_files */ } if (0 == nattch) { if (-1 == shmdt((caddr_t)start_addr)) { save_errno = errno; ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shmdt()"); } if (0 != shm_rmid(shm_id)) { save_errno = errno; ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shm_rmid()"); } if (JNLPOOL_SEGMENT == pool_type) { repl_inst_filehdr->jnlpool_shmid = INVALID_SHMID; repl_inst_filehdr->jnlpool_shmid_ctime = 0; assert((NULL == jnlpool.jnlpool_ctl) && (NULL == jnlpool_ctl)); *ipc_rmvd = TRUE; } else { repl_inst_filehdr->recvpool_shmid = INVALID_SHMID; repl_inst_filehdr->recvpool_shmid_ctime = 0; *ipc_rmvd = TRUE; } } else { /* else we are ONLINE ROLLBACK. Processes actively attached to the journal pool. Do not remove and/or reset the * fields in the file heade */ assert((JNLPOOL_SEGMENT != pool_type) || ((NULL != jnlpool.jnlpool_ctl) && (NULL != jnlpool_ctl))); if (JNLPOOL_SEGMENT == pool_type) *ipc_rmvd = FALSE; if (RECVPOOL_SEGMENT == pool_type) *ipc_rmvd = FALSE; } REVERT; return 0; } CONDITION_HANDLER(mu_rndwn_replpool_ch) { unix_db_info *udi; int save_errno; repl_inst_hdr_ptr_t inst_hdr; START_CH; PRN_ERROR; /* flush the error string */ if (SEVERITY == SEVERE) NEXTCH; if (NULL != jnlpool.jnlpool_ctl) { if (-1 == shmdt((caddr_t)jnlpool.jnlpool_ctl)) { save_errno = errno; inst_hdr = jnlpool.repl_inst_filehdr; assert(NULL != inst_hdr); assert(NULL != jnlpool.jnlpool_dummy_reg); udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); assert(ERR_REPLINSTOPEN == SIGNAL); /* only reason we know why mu_rndwn_replpool can fail */ assert(NULL != jnlpool.jnlpool_ctl); assert(INVALID_SHMID != inst_hdr->jnlpool_shmid); ISSUE_REPLPOOLINST(save_errno, inst_hdr->jnlpool_shmid, udi->fn, "shmdt()"); } jnlpool.jnlpool_ctl = jnlpool_ctl = NULL; jnlpool.gtmsrc_lcl_array = NULL; jnlpool.gtmsource_local_array = NULL; jnlpool.jnldata_base = NULL; jnlpool.repl_inst_filehdr = NULL; } UNWIND(NULL, NULL); }