| 1 | /***************************************************************************** | 
| 2 | Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. | 
| 3 | Copyright (c) 2015, 2017, MariaDB Corporation. | 
| 4 |  | 
| 5 | This program is free software; you can redistribute it and/or modify it under | 
| 6 | the terms of the GNU General Public License as published by the Free Software | 
| 7 | Foundation; version 2 of the License. | 
| 8 |  | 
| 9 | This program is distributed in the hope that it will be useful, but WITHOUT | 
| 10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
| 11 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | 
| 12 |  | 
| 13 | You should have received a copy of the GNU General Public License along with | 
| 14 | this program; if not, write to the Free Software Foundation, Inc., | 
| 15 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA | 
| 16 |  | 
| 17 | *****************************************************************************/ | 
| 18 |  | 
| 19 | /**************************************************//** | 
| 20 | @file include/fil0crypt.h | 
| 21 | The low-level file system encryption support functions | 
| 22 |  | 
| 23 | Created 04/01/2015 Jan Lindström | 
| 24 | *******************************************************/ | 
| 25 |  | 
| 26 | #ifndef fil0crypt_h | 
| 27 | #define fil0crypt_h | 
| 28 |  | 
| 29 | #ifndef UNIV_INNOCHECKSUM | 
| 30 | #include "os0event.h" | 
| 31 | #include "my_crypt.h" | 
| 32 | #include "fil0fil.h" | 
| 33 | #endif /*! UNIV_INNOCHECKSUM */ | 
| 34 |  | 
| 35 | /** | 
| 36 | * Magic pattern in start of crypt data on page 0 | 
| 37 | */ | 
| 38 | #define MAGIC_SZ 6 | 
| 39 |  | 
| 40 | static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = { | 
| 41 | 	's', 0xE, 0xC, 'R', 'E', 't' }; | 
| 42 |  | 
| 43 | /* This key will be used if nothing else is given */ | 
| 44 | #define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA | 
| 45 |  | 
| 46 | extern os_event_t fil_crypt_threads_event; | 
| 47 |  | 
| 48 | /** | 
| 49 |  * CRYPT_SCHEME_UNENCRYPTED | 
| 50 |  * | 
| 51 |  * Used as intermediate state when convering a space from unencrypted | 
| 52 |  * to encrypted | 
| 53 |  */ | 
| 54 | /** | 
| 55 |  * CRYPT_SCHEME_1 | 
| 56 |  * | 
| 57 |  * xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths) | 
| 58 |  *  L = AES_ECB(KEY, IV) | 
| 59 |  *  CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE) | 
| 60 |  */ | 
| 61 |  | 
| 62 | #define CRYPT_SCHEME_1 1 | 
| 63 | #define CRYPT_SCHEME_1_IV_LEN 16 | 
| 64 | #define CRYPT_SCHEME_UNENCRYPTED 0 | 
| 65 |  | 
| 66 | /* Cached L or key for given key_version */ | 
| 67 | struct key_struct | 
| 68 | { | 
| 69 | 	uint key_version;			/*!< Version of the key */ | 
| 70 | 	uint key_length;			/*!< Key length */ | 
| 71 | 	unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key | 
| 72 |                                                 (that is L in CRYPT_SCHEME_1) */ | 
| 73 | }; | 
| 74 |  | 
| 75 | /** is encryption enabled */ | 
| 76 | extern ulong	srv_encrypt_tables; | 
| 77 |  | 
| 78 | /** Mutex helper for crypt_data->scheme | 
| 79 | @param[in, out]	schme	encryption scheme | 
| 80 | @param[in]	exit	should we exit or enter mutex ? */ | 
| 81 | void | 
| 82 | crypt_data_scheme_locker( | 
| 83 | 	st_encryption_scheme*	scheme, | 
| 84 | 	int			exit); | 
| 85 |  | 
| 86 | struct fil_space_rotate_state_t | 
| 87 | { | 
| 88 | 	time_t start_time;	/*!< time when rotation started */ | 
| 89 | 	ulint active_threads;	/*!< active threads in space */ | 
| 90 | 	ulint next_offset;	/*!< next "free" offset */ | 
| 91 | 	ulint max_offset;	/*!< max offset needing to be rotated */ | 
| 92 | 	uint  min_key_version_found; /*!< min key version found but not | 
| 93 | 				     rotated */ | 
| 94 | 	lsn_t end_lsn;		/*!< max lsn created when rotating this | 
| 95 | 				space */ | 
| 96 | 	bool starting;		/*!< initial write of IV */ | 
| 97 | 	bool flushing;		/*!< space is being flushed at end of rotate */ | 
| 98 | 	struct { | 
| 99 | 		bool is_active; /*!< is scrubbing active in this space */ | 
| 100 | 		time_t last_scrub_completed; /*!< when was last scrub | 
| 101 | 					     completed */ | 
| 102 | 	} scrubbing; | 
| 103 | }; | 
| 104 |  | 
| 105 | #ifndef UNIV_INNOCHECKSUM | 
| 106 |  | 
| 107 | struct fil_space_crypt_t : st_encryption_scheme | 
| 108 | { | 
| 109 |  public: | 
| 110 | 	/** Constructor. Does not initialize the members! | 
| 111 | 	The object is expected to be placed in a buffer that | 
| 112 | 	has been zero-initialized. */ | 
| 113 | 	fil_space_crypt_t( | 
| 114 | 		uint new_type, | 
| 115 | 		uint new_min_key_version, | 
| 116 | 		uint new_key_id, | 
| 117 | 		fil_encryption_t new_encryption) | 
| 118 | 		: st_encryption_scheme(), | 
| 119 | 		min_key_version(new_min_key_version), | 
| 120 | 		page0_offset(0), | 
| 121 | 		encryption(new_encryption), | 
| 122 | 		key_found(0), | 
| 123 | 		rotate_state() | 
| 124 | 	{ | 
| 125 | 		key_id = new_key_id; | 
| 126 | 		my_random_bytes(iv, sizeof(iv)); | 
| 127 | 		mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex); | 
| 128 | 		locker = crypt_data_scheme_locker; | 
| 129 | 		type = new_type; | 
| 130 |  | 
| 131 | 		if (new_encryption == FIL_ENCRYPTION_OFF || | 
| 132 | 			(!srv_encrypt_tables && | 
| 133 | 			 new_encryption == FIL_ENCRYPTION_DEFAULT)) { | 
| 134 | 			type = CRYPT_SCHEME_UNENCRYPTED; | 
| 135 | 		} else { | 
| 136 | 			type = CRYPT_SCHEME_1; | 
| 137 | 			min_key_version = key_get_latest_version(); | 
| 138 | 		} | 
| 139 |  | 
| 140 | 		key_found = min_key_version; | 
| 141 | 	} | 
| 142 |  | 
| 143 | 	/** Destructor */ | 
| 144 | 	~fil_space_crypt_t() | 
| 145 | 	{ | 
| 146 | 		mutex_free(&mutex); | 
| 147 | 	} | 
| 148 |  | 
| 149 | 	/** Get latest key version from encryption plugin | 
| 150 | 	@retval key_version or | 
| 151 | 	@retval ENCRYPTION_KEY_VERSION_INVALID if used key_id | 
| 152 | 	is not found from encryption plugin. */ | 
| 153 | 	uint key_get_latest_version(void); | 
| 154 |  | 
| 155 | 	/** Returns true if key was found from encryption plugin | 
| 156 | 	and false if not. */ | 
| 157 | 	bool is_key_found() const { | 
| 158 | 		return key_found != ENCRYPTION_KEY_VERSION_INVALID; | 
| 159 | 	} | 
| 160 |  | 
| 161 | 	/** Returns true if tablespace should be encrypted */ | 
| 162 | 	bool should_encrypt() const { | 
| 163 | 		return ((encryption == FIL_ENCRYPTION_ON) || | 
| 164 | 			(srv_encrypt_tables && | 
| 165 | 				encryption == FIL_ENCRYPTION_DEFAULT)); | 
| 166 | 	} | 
| 167 |  | 
| 168 | 	/** Return true if tablespace is encrypted. */ | 
| 169 | 	bool is_encrypted() const { | 
| 170 | 		return (encryption != FIL_ENCRYPTION_OFF); | 
| 171 | 	} | 
| 172 |  | 
| 173 | 	/** Return true if default tablespace encryption is used, */ | 
| 174 | 	bool is_default_encryption() const { | 
| 175 | 		return (encryption == FIL_ENCRYPTION_DEFAULT); | 
| 176 | 	} | 
| 177 |  | 
| 178 | 	/** Return true if tablespace is not encrypted. */ | 
| 179 | 	bool not_encrypted() const { | 
| 180 | 		return (encryption == FIL_ENCRYPTION_OFF); | 
| 181 | 	} | 
| 182 |  | 
| 183 | 	/** Write crypt data to a page (0) | 
| 184 | 	@param[in]	space	tablespace | 
| 185 | 	@param[in,out]	page0	first page of the tablespace | 
| 186 | 	@param[in,out]	mtr	mini-transaction */ | 
| 187 | 	void write_page0(const fil_space_t* space, byte* page0, mtr_t* mtr); | 
| 188 |  | 
| 189 | 	uint min_key_version; // min key version for this space | 
| 190 | 	ulint page0_offset;   // byte offset on page 0 for crypt data | 
| 191 | 	fil_encryption_t encryption; // Encryption setup | 
| 192 |  | 
| 193 | 	ib_mutex_t mutex;   // mutex protecting following variables | 
| 194 |  | 
| 195 | 	/** Return code from encryption_key_get_latest_version. | 
| 196 |         If ENCRYPTION_KEY_VERSION_INVALID encryption plugin | 
| 197 | 	could not find the key and there is no need to call | 
| 198 | 	get_latest_key_version again as keys are read only | 
| 199 | 	at startup. */ | 
| 200 | 	uint key_found; | 
| 201 |  | 
| 202 | 	fil_space_rotate_state_t rotate_state; | 
| 203 | }; | 
| 204 |  | 
| 205 | /** Status info about encryption */ | 
| 206 | struct fil_space_crypt_status_t { | 
| 207 | 	ulint space;             /*!< tablespace id */ | 
| 208 | 	ulint scheme;            /*!< encryption scheme */ | 
| 209 | 	uint  min_key_version;   /*!< min key version */ | 
| 210 | 	uint  current_key_version;/*!< current key version */ | 
| 211 | 	uint  keyserver_requests;/*!< no of key requests to key server */ | 
| 212 | 	uint key_id;            /*!< current key_id */ | 
| 213 | 	bool rotating;           /*!< is key rotation ongoing */ | 
| 214 | 	bool flushing;           /*!< is flush at end of rotation ongoing */ | 
| 215 | 	ulint rotate_next_page_number; /*!< next page if key rotating */ | 
| 216 | 	ulint rotate_max_page_number;  /*!< max page if key rotating */ | 
| 217 | }; | 
| 218 |  | 
| 219 | /** Statistics about encryption key rotation */ | 
| 220 | struct fil_crypt_stat_t { | 
| 221 | 	ulint pages_read_from_cache; | 
| 222 | 	ulint pages_read_from_disk; | 
| 223 | 	ulint pages_modified; | 
| 224 | 	ulint pages_flushed; | 
| 225 | 	ulint estimated_iops; | 
| 226 | }; | 
| 227 |  | 
| 228 | /** Status info about scrubbing */ | 
| 229 | struct fil_space_scrub_status_t { | 
| 230 | 	ulint space;             /*!< tablespace id */ | 
| 231 | 	bool compressed;        /*!< is space compressed  */ | 
| 232 | 	time_t last_scrub_completed;  /*!< when was last scrub completed */ | 
| 233 | 	bool scrubbing;               /*!< is scrubbing ongoing */ | 
| 234 | 	time_t current_scrub_started; /*!< when started current scrubbing */ | 
| 235 | 	ulint current_scrub_active_threads; /*!< current scrub active threads */ | 
| 236 | 	ulint current_scrub_page_number; /*!< current scrub page no */ | 
| 237 | 	ulint current_scrub_max_page_number; /*!< current scrub max page no */ | 
| 238 | }; | 
| 239 |  | 
| 240 | /********************************************************************* | 
| 241 | Init space crypt */ | 
| 242 | UNIV_INTERN | 
| 243 | void | 
| 244 | fil_space_crypt_init(); | 
| 245 |  | 
| 246 | /********************************************************************* | 
| 247 | Cleanup space crypt */ | 
| 248 | UNIV_INTERN | 
| 249 | void | 
| 250 | fil_space_crypt_cleanup(); | 
| 251 |  | 
| 252 | /** | 
| 253 | Create a fil_space_crypt_t object | 
| 254 | @param[in]	encrypt_mode	FIL_ENCRYPTION_DEFAULT or | 
| 255 | 				FIL_ENCRYPTION_ON or | 
| 256 | 				FIL_ENCRYPTION_OFF | 
| 257 |  | 
| 258 | @param[in]	key_id		Encryption key id | 
| 259 | @return crypt object */ | 
| 260 | UNIV_INTERN | 
| 261 | fil_space_crypt_t* | 
| 262 | fil_space_create_crypt_data( | 
| 263 | 	fil_encryption_t	encrypt_mode, | 
| 264 | 	uint			key_id) | 
| 265 | 	MY_ATTRIBUTE((warn_unused_result)); | 
| 266 |  | 
| 267 | /****************************************************************** | 
| 268 | Merge fil_space_crypt_t object | 
| 269 | @param[in,out]	dst		Destination cryp data | 
| 270 | @param[in]	src		Source crypt data */ | 
| 271 | UNIV_INTERN | 
| 272 | void | 
| 273 | fil_space_merge_crypt_data( | 
| 274 | 	fil_space_crypt_t* dst, | 
| 275 | 	const fil_space_crypt_t* src); | 
| 276 |  | 
| 277 | /** Initialize encryption parameters from a tablespace header page. | 
| 278 | @param[in]	page_size	page size of the tablespace | 
| 279 | @param[in]	page		first page of the tablespace | 
| 280 | @return crypt data from page 0 | 
| 281 | @retval	NULL	if not present or not valid */ | 
| 282 | UNIV_INTERN | 
| 283 | fil_space_crypt_t* | 
| 284 | fil_space_read_crypt_data(const page_size_t& page_size, const byte* page) | 
| 285 | 	MY_ATTRIBUTE((nonnull, warn_unused_result)); | 
| 286 |  | 
| 287 | /** | 
| 288 | Free a crypt data object | 
| 289 | @param[in,out] crypt_data	crypt data to be freed */ | 
| 290 | UNIV_INTERN | 
| 291 | void | 
| 292 | fil_space_destroy_crypt_data( | 
| 293 | 	fil_space_crypt_t **crypt_data); | 
| 294 |  | 
| 295 | /****************************************************************** | 
| 296 | Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry | 
| 297 | @param[in]	ptr		Log entry start | 
| 298 | @param[in]	end_ptr		Log entry end | 
| 299 | @param[out]	err		DB_SUCCESS or DB_DECRYPTION_FAILED | 
| 300 | @return position on log buffer */ | 
| 301 | UNIV_INTERN | 
| 302 | byte* | 
| 303 | fil_parse_write_crypt_data( | 
| 304 | 	byte*			ptr, | 
| 305 | 	const byte*		end_ptr, | 
| 306 | 	dberr_t*		err) | 
| 307 | 	MY_ATTRIBUTE((warn_unused_result)); | 
| 308 |  | 
| 309 | /** Encrypt a buffer. | 
| 310 | @param[in,out]		crypt_data	Crypt data | 
| 311 | @param[in]		space		space_id | 
| 312 | @param[in]		offset		Page offset | 
| 313 | @param[in]		lsn		Log sequence number | 
| 314 | @param[in]		src_frame	Page to encrypt | 
| 315 | @param[in]		page_size	Page size | 
| 316 | @param[in,out]		dst_frame	Output buffer | 
| 317 | @return encrypted buffer or NULL */ | 
| 318 | byte* | 
| 319 | fil_encrypt_buf( | 
| 320 | 	fil_space_crypt_t*	crypt_data, | 
| 321 | 	ulint			space, | 
| 322 | 	ulint			offset, | 
| 323 | 	lsn_t			lsn, | 
| 324 | 	const byte*		src_frame, | 
| 325 | 	const page_size_t&	page_size, | 
| 326 | 	byte*			dst_frame) | 
| 327 | 	MY_ATTRIBUTE((warn_unused_result)); | 
| 328 |  | 
| 329 | /** | 
| 330 | Encrypt a page. | 
| 331 |  | 
| 332 | @param[in]		space		Tablespace | 
| 333 | @param[in]		offset		Page offset | 
| 334 | @param[in]		lsn		Log sequence number | 
| 335 | @param[in]		src_frame	Page to encrypt | 
| 336 | @param[in,out]		dst_frame	Output buffer | 
| 337 | @return encrypted buffer or NULL */ | 
| 338 | UNIV_INTERN | 
| 339 | byte* | 
| 340 | fil_space_encrypt( | 
| 341 | 	const fil_space_t* space, | 
| 342 | 	ulint		offset, | 
| 343 | 	lsn_t		lsn, | 
| 344 | 	byte*		src_frame, | 
| 345 | 	byte*		dst_frame) | 
| 346 | 	MY_ATTRIBUTE((warn_unused_result)); | 
| 347 |  | 
| 348 | /** | 
| 349 | Decrypt a page. | 
| 350 | @param[in,out]	crypt_data		crypt_data | 
| 351 | @param[in]	tmp_frame		Temporary buffer | 
| 352 | @param[in]	page_size		Page size | 
| 353 | @param[in,out]	src_frame		Page to decrypt | 
| 354 | @param[out]	err			DB_SUCCESS or error | 
| 355 | @return true if page decrypted, false if not.*/ | 
| 356 | UNIV_INTERN | 
| 357 | bool | 
| 358 | fil_space_decrypt( | 
| 359 | 	fil_space_crypt_t*	crypt_data, | 
| 360 | 	byte*			tmp_frame, | 
| 361 | 	const page_size_t&	page_size, | 
| 362 | 	byte*			src_frame, | 
| 363 | 	dberr_t*		err); | 
| 364 |  | 
| 365 | /****************************************************************** | 
| 366 | Decrypt a page | 
| 367 | @param[in]	space			Tablespace | 
| 368 | @param[in]	tmp_frame		Temporary buffer used for decrypting | 
| 369 | @param[in,out]	src_frame		Page to decrypt | 
| 370 | @param[out]	decrypted		true if page was decrypted | 
| 371 | @return decrypted page, or original not encrypted page if decryption is | 
| 372 | not needed.*/ | 
| 373 | UNIV_INTERN | 
| 374 | byte* | 
| 375 | fil_space_decrypt( | 
| 376 | 	const fil_space_t* space, | 
| 377 | 	byte*		tmp_frame, | 
| 378 | 	byte*		src_frame, | 
| 379 | 	bool*		decrypted) | 
| 380 | 	MY_ATTRIBUTE((warn_unused_result)); | 
| 381 |  | 
| 382 | /****************************************************************** | 
| 383 | Calculate post encryption checksum | 
| 384 | @param[in]	page_size	page size | 
| 385 | @param[in]	dst_frame	Block where checksum is calculated | 
| 386 | @return page checksum or BUF_NO_CHECKSUM_MAGIC | 
| 387 | not needed. */ | 
| 388 | UNIV_INTERN | 
| 389 | uint32_t | 
| 390 | fil_crypt_calculate_checksum( | 
| 391 | 	const page_size_t&	page_size, | 
| 392 | 	const byte*		dst_frame) | 
| 393 | 	MY_ATTRIBUTE((warn_unused_result)); | 
| 394 |  | 
| 395 | /********************************************************************* | 
| 396 | Adjust thread count for key rotation | 
| 397 | @param[in]	enw_cnt		Number of threads to be used */ | 
| 398 | UNIV_INTERN | 
| 399 | void | 
| 400 | fil_crypt_set_thread_cnt( | 
| 401 | 	uint	new_cnt); | 
| 402 |  | 
| 403 | /********************************************************************* | 
| 404 | Adjust max key age | 
| 405 | @param[in]	val		New max key age */ | 
| 406 | UNIV_INTERN | 
| 407 | void | 
| 408 | fil_crypt_set_rotate_key_age( | 
| 409 | 	uint	val); | 
| 410 |  | 
| 411 | /********************************************************************* | 
| 412 | Adjust rotation iops | 
| 413 | @param[in]	val		New max roation iops */ | 
| 414 | UNIV_INTERN | 
| 415 | void | 
| 416 | fil_crypt_set_rotation_iops( | 
| 417 | 	uint val); | 
| 418 |  | 
| 419 | /********************************************************************* | 
| 420 | Adjust encrypt tables | 
| 421 | @param[in]	val		New setting for innodb-encrypt-tables */ | 
| 422 | UNIV_INTERN | 
| 423 | void | 
| 424 | fil_crypt_set_encrypt_tables( | 
| 425 | 	uint val); | 
| 426 |  | 
| 427 | /********************************************************************* | 
| 428 | Init threads for key rotation */ | 
| 429 | UNIV_INTERN | 
| 430 | void | 
| 431 | fil_crypt_threads_init(); | 
| 432 |  | 
| 433 | /********************************************************************* | 
| 434 | Clean up key rotation threads resources */ | 
| 435 | UNIV_INTERN | 
| 436 | void | 
| 437 | fil_crypt_threads_cleanup(); | 
| 438 |  | 
| 439 | /********************************************************************* | 
| 440 | Wait for crypt threads to stop accessing space | 
| 441 | @param[in]	space		Tablespace */ | 
| 442 | UNIV_INTERN | 
| 443 | void | 
| 444 | fil_space_crypt_close_tablespace( | 
| 445 | 	const fil_space_t*	space); | 
| 446 |  | 
| 447 | /********************************************************************* | 
| 448 | Get crypt status for a space (used by information_schema) | 
| 449 | @param[in]	space		Tablespace | 
| 450 | @param[out]	status		Crypt status | 
| 451 | return 0 if crypt data present */ | 
| 452 | UNIV_INTERN | 
| 453 | void | 
| 454 | fil_space_crypt_get_status( | 
| 455 | 	const fil_space_t*			space, | 
| 456 | 	struct fil_space_crypt_status_t*	status); | 
| 457 |  | 
| 458 | /********************************************************************* | 
| 459 | Return crypt statistics | 
| 460 | @param[out]	stat		Crypt statistics */ | 
| 461 | UNIV_INTERN | 
| 462 | void | 
| 463 | fil_crypt_total_stat( | 
| 464 | 	fil_crypt_stat_t *stat); | 
| 465 |  | 
| 466 | /** | 
| 467 | Get scrub status for a space (used by information_schema) | 
| 468 |  | 
| 469 | @param[in]	space		Tablespace | 
| 470 | @param[out]	status		Scrub status | 
| 471 | return 0 if data found */ | 
| 472 | UNIV_INTERN | 
| 473 | void | 
| 474 | fil_space_get_scrub_status( | 
| 475 | 	const fil_space_t*		space, | 
| 476 | 	fil_space_scrub_status_t*	status); | 
| 477 |  | 
| 478 | #include "fil0crypt.ic" | 
| 479 | #endif /* !UNIV_INNOCHECKSUM */ | 
| 480 |  | 
| 481 | /** | 
| 482 | Verify that post encryption checksum match calculated checksum. | 
| 483 | This function should be called only if tablespace contains crypt_data | 
| 484 | metadata (this is strong indication that tablespace is encrypted). | 
| 485 | Function also verifies that traditional checksum does not match | 
| 486 | calculated checksum as if it does page could be valid unencrypted, | 
| 487 | encrypted, or corrupted. | 
| 488 |  | 
| 489 | @param[in,out]	page		page frame (checksum is temporarily modified) | 
| 490 | @param[in]	page_size	page size | 
| 491 | @param[in]	space		tablespace identifier | 
| 492 | @param[in]	offset		page number | 
| 493 | @return true if page is encrypted AND OK, false otherwise */ | 
| 494 | UNIV_INTERN | 
| 495 | bool | 
| 496 | fil_space_verify_crypt_checksum( | 
| 497 | 	byte* 			page, | 
| 498 | 	const page_size_t&	page_size, | 
| 499 | 	ulint			space, | 
| 500 | 	ulint			offset) | 
| 501 | 	MY_ATTRIBUTE((warn_unused_result)); | 
| 502 |  | 
| 503 | #endif /* fil0crypt_h */ | 
| 504 |  |