File: dsk_write_nocache.c

package info (click to toggle)
fis-gtm 6.3-007-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 36,284 kB
  • sloc: ansic: 328,861; asm: 5,182; csh: 5,102; sh: 1,918; awk: 291; makefile: 69; sed: 13
file content (161 lines) | stat: -rwxr-xr-x 6,918 bytes parent folder | download
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
/****************************************************************
 *								*
 * Copyright (c) 2005-2017 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 "gtm_fcntl.h"	/* needed for silly aix's expansion of open to open64 */
#include "gtm_unistd.h"
#include "gtm_stdio.h"
#include "gtm_signal.h"

#include <sys/types.h>
#include <errno.h>

#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "gdsblk.h"
#include "iosp.h"
#include "gtmio.h"
#include "gds_blk_downgrade.h"
#include "add_inter.h"
#include "anticipatory_freeze.h"
#include "gtmcrypt.h"
#include "min_max.h"
#include "jnl.h"

GBLREF	sm_uc_ptr_t	reformat_buffer;
GBLREF	int		reformat_buffer_len;
GBLREF	volatile int	reformat_buffer_in_use;	/* used only in DEBUG mode */
GBLREF	volatile int4	fast_lock_count;

/*
 * 1) We write direct from the given buffer to a block in the database file on disk rather than from a cache record's buffer.
 * 2) This routine takes care of the maint of blks_to_upgrd in the file-header for these non-cached writes.
 */
int	dsk_write_nocache(gd_region *reg, block_id blk, sm_uc_ptr_t buff, enum db_ver ondsk_blkver)
{
	unix_db_info		*udi;
	int4			size, save_errno;
	sgmnt_addrs		*csa;
	sgmnt_data_ptr_t	csd;
	int			in_len, this_blk_size, gtmcrypt_errno;
	char			*in;
	gd_segment		*seg;
	boolean_t		use_new_key;
#	ifdef DEBUG
	sm_uc_ptr_t		save_buff;
#	endif
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	udi = FILE_INFO(reg);
	csa = &udi->s_addrs;
	csd = csa->hdr;
	assert(NULL != csd);
	assert(((blk_hdr_ptr_t)buff)->bver);	/* GDSV4 (0) version uses this field as a block length so should always be > 0 */
	assert(0 == fast_lock_count); /* ensure the static reformat buffer is not being used currently */
	++fast_lock_count; 	/* Prevents interrupt from using reformat buffer while we have it */
	/* reformat_buffer_in_use should always be incremented only AFTER incrementing fast_lock_count
	 * as it is the latter that prevents interrupts from using the reformat buffer. Similarly
	 * the decrement of fast_lock_count should be done AFTER decrementing reformat_buffer_in_use.
	 */
	assert(0 == reformat_buffer_in_use);
	DEBUG_ONLY(reformat_buffer_in_use++;)
	if (IS_GDS_BLK_DOWNGRADE_NEEDED(ondsk_blkver))
	{	/* Need to downgrade/reformat this block back to the previous format */
		DEBUG_DYNGRD_ONLY(PRINTF("DSK_WRITE_NOCACHE: Block %d being dynamically downgraded on write\n", blk));
		if (csd->blk_size > reformat_buffer_len)
		{	/* Buffer not big enough (or does not exist) .. get a new one releasing old if it exists */
			if (reformat_buffer)
				free(reformat_buffer);	/* Different blksized databases in use .. keep only largest one */
			reformat_buffer = malloc(csd->blk_size);
			reformat_buffer_len = csd->blk_size;
		}
		gds_blk_downgrade((v15_blk_hdr_ptr_t)reformat_buffer, (blk_hdr_ptr_t)buff);
		buff = reformat_buffer;
		size = (((v15_blk_hdr_ptr_t)buff)->bsiz + 1) & ~1;
		/* Represents a block state change from V5 -> V4 */
		INCR_BLKS_TO_UPGRD(csa, csd, 1);
		assert(SIZEOF(v15_blk_hdr) <= size);
	} else DEBUG_ONLY(if (GDSV6 == ondsk_blkver))
	{
		size = (((blk_hdr_ptr_t)buff)->bsiz + 1) & ~1;
		assert(SIZEOF(blk_hdr) <= size);
		/* no adjustment to blks_to_upgrd counter is needed since the format we are going to write is GDSVCURR */
	}
#	ifdef DEBUG
	else
		assert(GDSV6 == ondsk_blkver);
#	endif
	if (csa->do_fullblockwrites) /* See similiar lobic in wcs_wtstart.c */
		size = (int)ROUND_UP(size, (FULL_DATABASE_WRITE == csa->do_fullblockwrites)
				? csd->blk_size : csa->fullblockwrite_len);
	assert(size <= csd->blk_size);
	assert(FALSE == reg->read_only);
	/* This function is called by "bml_init" which in turn can be called by "mucregini" or "gdsfilext". The former is
	 * a case where the region is not yet open. csa is usable to a limited extent in the former case but since shared
	 * memory is not set up yet, most of it (e.g. csa->nl etc.) are not usable in the former case. But it is usable
	 * completely in the latter case. Therefore take care using "csa" below. Hence the "reg->open" usages before csa access.
	 * The reg->open check was not necessary until statsdb support because the only caller of "mucregini" was MUPIP CREATE
	 * which would not anyways open the journal pool. But now that GT.M can call "mucregini" to create a statsdb while
	 * it has other basedbs open, it could have the jnlpool open which is why we need this safety check.
	 */
	assert(!reg->open || !csa->acc_meth.bg.cache_state->cache_array || buff != (sm_uc_ptr_t)csd);
	assert(size <= csd->blk_size);
	if (udi->raw)
		size = ROUND_UP(size, DISK_BLOCK_SIZE);	/* raw I/O must be a multiple of DISK_BLOCK_SIZE */
	use_new_key = USES_NEW_KEY(csd);
	if (IS_ENCRYPTED(csd->is_encrypted) || use_new_key)
	{
		this_blk_size = ((blk_hdr_ptr_t)buff)->bsiz;
		assert((this_blk_size <= csd->blk_size) && (this_blk_size >= SIZEOF(blk_hdr)));
		in_len = MIN(csd->blk_size, this_blk_size) - SIZEOF(blk_hdr);
		/* Make sure we do not end up encrypting a zero-length record */
		if (BLK_NEEDS_ENCRYPTION(((blk_hdr_ptr_t)buff)->levl, in_len))
		{
			ASSERT_ENCRYPTION_INITIALIZED;
			in = (char *)(buff + SIZEOF(blk_hdr));
			GTMCRYPT_ENCRYPT(csa, (use_new_key ? TRUE : csd->non_null_iv),
					(use_new_key ? csa->encr_key_handle2 : csa->encr_key_handle),
					in, in_len, NULL, buff, SIZEOF(blk_hdr), gtmcrypt_errno);
			if (0 != gtmcrypt_errno)
			{
				seg = reg->dyn.addr;
				GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname);
			}
		}
	}
	if (udi->fd_opened_with_o_direct)
	{
		assert(reg->open);	/* should be coming in through "gdsfilext" after having done a "gvcst_init" */
		/* This means dio_buff.aligned would already have been allocated to hold at least one GDS block. Use it. */
		size = ROUND_UP2(size, DIO_ALIGNSIZE(udi));
		assert(DIO_BUFF_NO_OVERFLOW((TREF(dio_buff)), size));
		assert(size <= csd->blk_size);
		memcpy((TREF(dio_buff)).aligned, buff, size);
		DEBUG_ONLY(save_buff = buff;)	/* for DBG purposes */
		buff = (sm_uc_ptr_t)(TREF(dio_buff)).aligned;
	}
	DB_LSEEKWRITE(reg->open ? csa : NULL, udi, udi->fn, udi->fd,
			(BLK_ZERO_OFF(csd->start_vbn) + (off_t)blk * csd->blk_size), buff, size, save_errno);
	DEBUG_ONLY(reformat_buffer_in_use--;)
	assert(0 == reformat_buffer_in_use);
	--fast_lock_count; 		/* reformat buffer is no longer necessary */
	assert(0 == fast_lock_count);
	if (0 != save_errno)		/* If it didn't work for whatever reason.. */
		return -1;
	return SS_NORMAL;
}