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
  
     | 
    
      /****************************************************************
 *								*
 * Copyright (c) 2003-2015 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 "min_max.h"
#include "gtm_fcntl.h"
#include "gtm_unistd.h"
#include "gtm_stat.h"
#include "gtm_string.h"
#include "gtm_aio.h"
#include "gtmio.h"
#ifdef __MVS__
#include "gtm_zos_io.h"
#endif
#include "gdsroot.h"
#include "gdsbt.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"
#include "buddy_list.h"
#include "hashtab_mname.h"	/* needed for muprec.h */
#include "hashtab_int4.h"	/* needed for muprec.h */
#include "hashtab_int8.h"	/* needed for muprec.h */
#include "muprec.h"
#include "mur_read_file.h"
#include "iosp.h"
#include "copy.h"
#include "gtmmsg.h"
#include "repl_sp.h"		/* for F_CLOSE used by the JNL_FD_CLOSE macro */
GBLREF	mur_opt_struct	mur_options;
GBLREF 	mur_gbls_t	murgbl;
error_def(ERR_JNLFILEOPNERR);
error_def(ERR_SYSCALL);
#ifdef MUR_USE_AIO
/****************************************************************************************
 * Function Name: mur_fread_start
 * Input: struct mur_buffer_desc * buff
 * Output : SS_NORMAL on successful
 *          error status on unsuccessful
 * This function starts an asynchronous read in a given buffer
 ****************************************************************************************/
/* #GTM_THREAD_SAFE : The below function (mur_fread_start) is thread-safe */
uint4 mur_fread_start(jnl_ctl_list *jctl, mur_buff_desc_t *buff)
{
	buff->aiocbp->aio_offset = buff->dskaddr;
	buff->aiocbp->aio_buf = (char *)buff->base;
	buff->blen = MIN(MUR_BUFF_SIZE, jctl->eof_addr - buff->dskaddr);
	buff->aiocbp->aio_nbytes = buff->blen;
	buff->rip_channel = jctl->channel;	/* store channel that issued the AIO in order to use later for aio_cancel() */
	assert(!buff->read_in_progress);
	buff->read_in_progress = TRUE;
	AIO_READ(buff->rip_channel, buff->aiocbp, jctl->status, jctl->status2);
	return jctl->status;
}
/************************************************************************************
 * Function name: mur_fread_wait
 * Input : struct mur_buffer_desc *buff
 * Output: SS_NORMAL on success
 *         error status on unsuccessful
 * Purpose: The purpose of this routine is to make sure that a previously issued asysnchronous read
 *          in a given buffer has completed
 **************************************************************************************/
/* #GTM_THREAD_SAFE : The below function (mur_fread_wait) is thread-safe */
uint4 mur_fread_wait(jnl_ctl_list *jctl, mur_buff_desc_t *buff)
{
	ssize_t	nbytes;
	assert(buff->read_in_progress);
	buff->read_in_progress = FALSE;
	/* The aio_error function returns the error status associated with the specified aiocbp. If the aio_error function returns
	 * anything but EINPROGRESS, the asynchronous I/O operation has completed. Subsequently, we can fetch the status of the
	 * operation from a call to aio_return.
	 */
	AIO_ERROR(buff->aiocbp, jctl->status);
	if (-1 != jctl->status)
	{
		AIO_RETURN(buff->aiocbp, nbytes); /* if successful jctl->status will contain number of bytes read */
		if (-1 != nbytes)
		{
			if (buff->blen == nbytes)
				return (jctl->status = SS_NORMAL);
			/* AIO_READ didn't fetch the requested size chunk */
			assert(buff->blen > nbytes);
			DO_FILE_READ(buff->rip_channel, buff->dskaddr + nbytes, buff->base + nbytes, buff->blen - nbytes,
					jctl->status, jctl->status2);
			return jctl->status;
		}
	}
	return (jctl->status = errno);
}
/* #GTM_THREAD_SAFE : The below function (mur_fread_cancel) is thread-safe */
/* cancel asynchronous read */
uint4 mur_fread_cancel(jnl_ctl_list *jctl)
{
	int			status, index, save_err;
	reg_ctl_list		*rctl;
	mur_read_desc_t		*mur_desc;
	mur_buff_desc_t		*seq_buff;
	rctl = jctl->reg_ctl;
	mur_desc = rctl->mur_desc;
	/* At most one buffer can have read_in_progress, not both */
	assert(!(mur_desc->seq_buff[0].read_in_progress && mur_desc->seq_buff[1].read_in_progress));
	for (index = 0, save_err = 0; index < ARRAYSIZE(mur_desc->seq_buff); index++)
	{
		seq_buff = &mur_desc->seq_buff[index];
		if (seq_buff->read_in_progress)
		{
			AIO_CANCEL(seq_buff->rip_channel, NULL, status);
			if (-1 == status)
				save_err = errno;
			else if (AIO_NOTCANCELED == status)	/* the OS cannot cancel the aio once it has actually started */
				jctl->status = mur_fread_wait(seq_buff);	/* wait for it to finish. */
			seq_buff->read_in_progress = FALSE;
		}
	}
	/* Note that although the cancellation errored out for rip_channel, we are storing the status in jctl which need not
	 * actually be the jctl corresponding to rip_channel
	 */
	return (jctl->status = ((0 == save_err) ? SS_NORMAL : save_err));
}
#endif /* MUR_USE_AIO */
/* #GTM_THREAD_SAFE : The below function (mur_fopen_sp) is thread-safe */
/* Returns 0 (SS_NORMAL) for success; Non-zero for failure */
uint4	mur_fopen_sp(jnl_ctl_list *jctl, reg_ctl_list *rctl)
{
	struct stat		stat_buf;
	int			status, perms;
	sgmnt_addrs		*csa;
	ZOS_ONLY(int		realfiletag;)
	perms = O_RDONLY;
	jctl->read_only = TRUE;
	jctl->reg_ctl = rctl;	/* fill in reg_ctl backpointer from jctl to rctl. Note: rctl could be NULL */
	/* Both for recover and rollback open in read/write mode. We do not need to write in journal file
	 * for mupip journal extract/show/verify or recover -forward.  So open it as read-only
	 */
	if (mur_options.update && !mur_options.forward)
	{
		perms = O_RDWR;
		jctl->read_only = FALSE;
	}
	jctl->channel = OPEN((char *)jctl->jnl_fn, perms);
	if (FD_INVALID != jctl->channel)
	{
		FSTAT_FILE(jctl->channel, &stat_buf, status);
		if (-1 != status)
		{
#			ifdef __MVS__
			if (-1 == gtm_zos_tag_to_policy(jctl->channel, TAG_BINARY, &realfiletag))
				TAG_POLICY_GTM_PUTMSG((char *)jctl->jnl_fn, errno, realfiletag, TAG_BINARY);
#			endif
			jctl->os_filesize = (off_jnl_t)stat_buf.st_size;
			return SS_NORMAL;
		}
		jctl->status = errno;
		JNL_FD_CLOSE(jctl->channel, status);	/* sets jctl->channel to NOJNL */
	} else
		jctl->status = errno;
	assert(NOJNL == jctl->channel);
	csa = JCTL2CSA(jctl);	/* need JCTL2CSA macro instead of jctl->reg_ctl->csa because rctl could be NULL */
	if (ENOENT == jctl->status)	/* File Not Found is a common error, so no need for SYSCALL */
		gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status);
	else
		gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn,
			ERR_SYSCALL, 5, LEN_AND_STR((-1 == jctl->channel) ? "open" : "fstat"), CALLFROM, jctl->status);
	return ERR_JNLFILEOPNERR;
}
 
     |