226 lines
6.6 KiB
C
226 lines
6.6 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 "gtmconfig.h"
|
|
#include "mdef.h"
|
|
#include "gtm_statvfs.h"
|
|
|
|
#include <errno.h>
|
|
#include "gtm_fcntl.h"
|
|
#include "gtm_unistd.h"
|
|
#include "gtm_stat.h"
|
|
#include "gtm_string.h"
|
|
#include "util.h"
|
|
|
|
#include "gtm_rename.h"
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "filestruct.h"
|
|
#include "jnl.h"
|
|
#include "eintr_wrappers.h"
|
|
#include "gtmmsg.h"
|
|
#include "iosp.h" /* for SS_NORMAL */
|
|
#include "gtmio.h"
|
|
#include "repl_sp.h" /* for F_CLOSE used by the JNL_FD_CLOSE macro */
|
|
#include "interlock.h"
|
|
#include "lockconst.h"
|
|
#include "aswp.h"
|
|
#include "is_file_identical.h"
|
|
#ifdef __MVS__
|
|
#include "gtm_zos_io.h"
|
|
#endif
|
|
|
|
#ifdef GTM_FD_TRACE
|
|
#include "gtm_dbjnl_dupfd_check.h"
|
|
#endif
|
|
|
|
#include "wbox_test_init.h"
|
|
|
|
GBLREF boolean_t is_src_server;
|
|
GBLREF boolean_t mupip_jnl_recover;
|
|
|
|
error_def(ERR_JNLFILOPN);
|
|
error_def(ERR_JNLMOVED);
|
|
error_def(ERR_JNLOPNERR);
|
|
error_def(ERR_JNLRDERR);
|
|
|
|
uint4 jnl_file_open(gd_region *reg, bool init, void *dummy) /* third argument for compatibility with VMS version */
|
|
{
|
|
sgmnt_addrs *csa;
|
|
sgmnt_data_ptr_t csd;
|
|
jnl_private_control *jpc;
|
|
jnl_buffer_ptr_t jb;
|
|
struct stat stat_buf;
|
|
uint4 sts;
|
|
sm_uc_ptr_t nameptr;
|
|
int fstat_res;
|
|
int close_res;
|
|
boolean_t switch_and_retry;
|
|
ZOS_ONLY(int realfiletag;)
|
|
|
|
csa = &FILE_INFO(reg)->s_addrs;
|
|
csd = csa->hdr;
|
|
jpc = csa->jnl;
|
|
jb = jpc->jnl_buff;
|
|
assert(NOJNL == jpc->channel);
|
|
sts = 0;
|
|
jpc->status = jpc->status2 = SS_NORMAL;
|
|
nameptr = csd->jnl_file_name;
|
|
assert('/' == csd->jnl_file_name[0]);
|
|
if (init)
|
|
{
|
|
assert(csd->jnl_file_len < JNL_NAME_SIZE);
|
|
nameptr[csd->jnl_file_len] = 0;
|
|
cre_jnl_file_intrpt_rename(((int)csd->jnl_file_len), csd->jnl_file_name);
|
|
/* although jnl_file_close() would have reset jnl_file.u.inode and device to 0 and incremented cycle, it
|
|
* might have got shot in the middle of executing those instructions. we redo it here just to be safe.
|
|
*/
|
|
csa->nl->jnl_file.u.inode = 0;
|
|
csa->nl->jnl_file.u.device = 0;
|
|
jb->cycle++;
|
|
/* Source Server only reads journal files so must never try to create and switch to a new journal file. */
|
|
switch_and_retry = (!is_src_server) ? TRUE : FALSE;
|
|
for (;;)
|
|
{
|
|
/* D9E04-002445 MUPIP RECOVER always open journal file without O_SYNC, ignoring jnl_sync_io */
|
|
if (csd->jnl_sync_io && !mupip_jnl_recover)
|
|
{
|
|
OPENFILE_SYNC((sm_c_ptr_t)csd->jnl_file_name, O_RDWR, jpc->channel);
|
|
jpc->sync_io = TRUE;
|
|
} else
|
|
{
|
|
OPENFILE((sm_c_ptr_t)csd->jnl_file_name, O_RDWR, jpc->channel);
|
|
jpc->sync_io = FALSE;
|
|
}
|
|
/* Check that if ever open errors out (i.e. return status is FD_INVALID=-1),
|
|
* jpc->channel will be already set to NOJNL (which is also defined to be -1).
|
|
*/
|
|
assert(FD_INVALID == NOJNL);
|
|
if (FD_INVALID == jpc->channel)
|
|
{
|
|
jpc->status = errno;
|
|
sts = ERR_JNLFILOPN;
|
|
if (EACCES == jpc->status || EROFS == jpc->status)
|
|
break;
|
|
} else
|
|
{
|
|
ZOS_ONLY(gtm_zos_tag_to_policy(jpc->channel, TAG_BINARY, &realfiletag);)
|
|
FSTAT_FILE(jpc->channel, &stat_buf, fstat_res);
|
|
if (-1 == fstat_res)
|
|
{
|
|
jpc->status = errno;
|
|
assert(FALSE);
|
|
sts = ERR_JNLRDERR;
|
|
JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */
|
|
break;
|
|
} else
|
|
sts = jnl_file_open_common(reg, (off_jnl_t) stat_buf.st_size);
|
|
}
|
|
DEBUG_ONLY(
|
|
/* Will fail if Source Server would need to switch journal files. */
|
|
assert((gtm_white_box_test_case_enabled && (WBTEST_JNL_SWITCH_EXPECTED ==
|
|
gtm_white_box_test_case_number)) || (0 == sts) || switch_and_retry);
|
|
)
|
|
if ((0 != sts) && switch_and_retry)
|
|
{ /* Switch to a new journal file and retry, but only once */
|
|
sts = jnl_file_open_switch(reg, sts);
|
|
if (0 == sts)
|
|
{
|
|
switch_and_retry = FALSE;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} else /* not init */
|
|
{
|
|
assert(0 == nameptr[csd->jnl_file_len]);
|
|
ASSERT_JNLFILEID_NOT_NULL(csa);
|
|
/* D9E04-002445 MUPIP RECOVER always open journal file without O_SYNC, ignoring jnl_sync_io */
|
|
if (csd->jnl_sync_io && !mupip_jnl_recover)
|
|
{
|
|
OPENFILE_SYNC((sm_c_ptr_t)nameptr, O_RDWR, jpc->channel);
|
|
jpc->sync_io = TRUE;
|
|
} else
|
|
{
|
|
OPENFILE((sm_c_ptr_t)nameptr, O_RDWR, jpc->channel);
|
|
jpc->sync_io = FALSE;
|
|
}
|
|
/* Check that if ever open errors out (i.e. return status is FD_INVALID=-1,
|
|
* jpc->channel will be already set to NOJNL (which is also defined to be -1).
|
|
*/
|
|
assert(FD_INVALID == NOJNL);
|
|
if (FD_INVALID == jpc->channel)
|
|
{
|
|
jpc->status = errno;
|
|
sts = ERR_JNLFILOPN;
|
|
} else
|
|
{
|
|
FSTAT_FILE(jpc->channel, &stat_buf, fstat_res);
|
|
ZOS_ONLY(gtm_zos_tag_to_policy(jpc->channel, TAG_BINARY, &realfiletag);)
|
|
}
|
|
} /* if init */
|
|
if (0 == sts)
|
|
{
|
|
if (0 == fstat_res)
|
|
{
|
|
if (init || is_gdid_stat_identical(&csa->nl->jnl_file.u, &stat_buf))
|
|
{
|
|
if (jnl_closed == csd->jnl_state)
|
|
{ /* Operator close came in while opening */
|
|
JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */
|
|
jpc->fileid.inode = 0;
|
|
jpc->fileid.device = 0;
|
|
jpc->pini_addr = 0;
|
|
} else
|
|
{
|
|
if (init)
|
|
{ /* Stash the file id in shared-memory for subsequent users */
|
|
set_gdid_from_stat(&csa->nl->jnl_file.u, &stat_buf);
|
|
}
|
|
GTM_WHITE_BOX_TEST(WBTEST_JNL_FILE_OPEN_FAIL, sts, ERR_JNLFILOPN);
|
|
DEBUG_ONLY(if (0 == sts))
|
|
jpc->cycle = jb->cycle; /* make private cycle and shared cycle in sync */
|
|
GTM_FD_TRACE_ONLY(
|
|
gtm_dbjnl_dupfd_check(); /* Check if db or jnl fds collide (D9I11-002714) */
|
|
if (NOJNL == jpc->channel)
|
|
{ /* The dupfd check above has reset our channel. No idea why. */
|
|
GTMASSERT;
|
|
}
|
|
)
|
|
} /* if jnl_state */
|
|
} else
|
|
{ /* not init and file moved */
|
|
jpc->status = ERR_JNLMOVED;
|
|
sts = ERR_JNLOPNERR;
|
|
assert(gtm_white_box_test_case_enabled
|
|
&& (WBTEST_JNLOPNERR_EXPECTED == gtm_white_box_test_case_number));
|
|
}
|
|
} else
|
|
{ /* stat failed */
|
|
jpc->status = errno;
|
|
sts = ERR_JNLFILOPN;
|
|
}
|
|
} /* sts == 0 when we started */
|
|
if (0 != sts)
|
|
{
|
|
if (NOJNL != jpc->channel)
|
|
JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */
|
|
assert(NOJNL == jpc->channel);
|
|
jnl_send_oper(jpc, sts);
|
|
}
|
|
assert((0 != sts) || (NOJNL != jpc->channel));
|
|
return sts;
|
|
}
|