xref: /optee_os/core/tee/tee_ree_fs.c (revision e4302df3411aa05a45383413c488926e1af0f7eb)
1 /*
2  * Copyright (c) 2015, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include <kernel/thread.h>
30 #include <kernel/handle.h>
31 #include <kernel/mutex.h>
32 #include <kernel/panic.h>
33 #include <mm/core_memprot.h>
34 #include <optee_msg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <string_ext.h>
39 #include <sys/queue.h>
40 #include <tee/tee_cryp_provider.h>
41 #include <tee/tee_fs.h>
42 #include <tee/tee_fs_defs.h>
43 #include <tee/tee_fs_rpc.h>
44 #include <tee/tee_fs_key_manager.h>
45 #include <trace.h>
46 #include <utee_defines.h>
47 #include <util.h>
48 
49 #define BLOCK_FILE_SHIFT	12
50 
51 #define BLOCK_FILE_SIZE		(1 << BLOCK_FILE_SHIFT)
52 
53 #define MAX_NUM_CACHED_BLOCKS	1
54 
55 #define NUM_BLOCKS_PER_FILE	1024
56 
57 #define MAX_FILE_SIZE	(BLOCK_FILE_SIZE * NUM_BLOCKS_PER_FILE)
58 
59 struct tee_fs_file_info {
60 	size_t length;
61 	uint32_t backup_version_table[NUM_BLOCKS_PER_FILE / 32];
62 };
63 
64 struct tee_fs_file_meta {
65 	struct tee_fs_file_info info;
66 	uint8_t encrypted_fek[TEE_FS_KM_FEK_SIZE];
67 	uint8_t backup_version;
68 };
69 
70 TAILQ_HEAD(block_head, block);
71 
72 struct block {
73 	TAILQ_ENTRY(block) list;
74 	int block_num;
75 	uint8_t *data;
76 	size_t data_size;
77 };
78 
79 struct block_cache {
80 	struct block_head block_lru;
81 	uint8_t cached_block_num;
82 };
83 
84 struct tee_fs_fd {
85 	struct tee_fs_file_meta meta;
86 	tee_fs_off_t pos;
87 	uint32_t flags;
88 	int fd;
89 	bool is_new_file;
90 	char *filename;
91 	struct block_cache block_cache;
92 };
93 
94 static inline int pos_to_block_num(int position)
95 {
96 	return position >> BLOCK_FILE_SHIFT;
97 }
98 
99 static inline int get_last_block_num(size_t size)
100 {
101 	return pos_to_block_num(size - 1);
102 }
103 
104 static inline uint8_t get_backup_version_of_block(
105 		struct tee_fs_file_meta *meta,
106 		size_t block_num)
107 {
108 	uint32_t index = (block_num / 32);
109 	uint32_t block_mask = 1 << (block_num % 32);
110 
111 	return !!(meta->info.backup_version_table[index] & block_mask);
112 }
113 
114 static inline void toggle_backup_version_of_block(
115 		struct tee_fs_file_meta *meta,
116 		size_t block_num)
117 {
118 	uint32_t index = (block_num / 32);
119 	uint32_t block_mask = 1 << (block_num % 32);
120 
121 	meta->info.backup_version_table[index] ^= block_mask;
122 }
123 
124 struct block_operations {
125 
126 	/*
127 	 * Read a block from REE File System which is corresponding
128 	 * to the given block_num.
129 	 */
130 	struct block *(*read)(struct tee_fs_fd *fdp, int block_num);
131 
132 	/*
133 	 * Write the given block to REE File System
134 	 */
135 	int (*write)(struct tee_fs_fd *fdp, struct block *b,
136 			struct tee_fs_file_meta *new_meta);
137 };
138 
139 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER;
140 
141 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
142 
143 /*
144  * We split a TEE file into multiple blocks and store them
145  * on REE filesystem. A TEE file is represented by a REE file
146  * called meta and a number of REE files called blocks. Meta
147  * file is used for storing file information, e.g. file size
148  * and backup version of each block.
149  *
150  * REE files naming rule is as follows:
151  *
152  *   <tee_file_name>/meta.<backup_version>
153  *   <tee_file_name>/block0.<backup_version>
154  *   ...
155  *   <tee_file_name>/block15.<backup_version>
156  *
157  * Backup_version is used to support atomic update operation.
158  * Original file will not be updated, instead we create a new
159  * version of the same file and update the new file instead.
160  *
161  * The backup_version of each block file is stored in meta
162  * file, the meta file itself also has backup_version, the update is
163  * successful after new version of meta has been written.
164  */
165 #define REE_FS_NAME_MAX (TEE_FS_NAME_MAX + 20)
166 
167 
168 static int ree_fs_mkdir_rpc(const char *path, tee_fs_mode_t mode)
169 {
170 	return tee_fs_rpc_mkdir(OPTEE_MSG_RPC_CMD_FS, path, mode);
171 }
172 
173 static struct tee_fs_dir *ree_fs_opendir_rpc(const char *name)
174 {
175 	return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name);
176 }
177 
178 static int ree_fs_closedir_rpc(struct tee_fs_dir *d)
179 {
180 	return tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d);
181 }
182 
183 static struct tee_fs_dirent *ree_fs_readdir_rpc(struct tee_fs_dir *d)
184 {
185 	return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d);
186 }
187 
188 static int ree_fs_rmdir_rpc(const char *name)
189 {
190 	return tee_fs_rpc_rmdir(OPTEE_MSG_RPC_CMD_FS, name);
191 }
192 
193 static int ree_fs_access_rpc(const char *name, int mode)
194 {
195 	return tee_fs_rpc_access(OPTEE_MSG_RPC_CMD_FS, name, mode);
196 }
197 
198 static void get_meta_filepath(const char *file, int version,
199 				char *meta_path)
200 {
201 	snprintf(meta_path, REE_FS_NAME_MAX, "%s/meta.%d",
202 			file, version);
203 }
204 
205 static void get_block_filepath(const char *file, size_t block_num,
206 				int version, char *meta_path)
207 {
208 	snprintf(meta_path, REE_FS_NAME_MAX, "%s/block%zu.%d",
209 			file, block_num, version);
210 }
211 
212 static int __remove_block_file(struct tee_fs_fd *fdp, size_t block_num,
213 				bool toggle)
214 {
215 	TEE_Result res;
216 	char block_path[REE_FS_NAME_MAX];
217 	uint8_t version = get_backup_version_of_block(&fdp->meta, block_num);
218 
219 	if (toggle)
220 		version = !version;
221 
222 	get_block_filepath(fdp->filename, block_num, version, block_path);
223 	DMSG("%s", block_path);
224 
225 	res = tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, block_path);
226 	if (res == TEE_SUCCESS || res == TEE_ERROR_ITEM_NOT_FOUND)
227 		return 0; /* ignore it if file not found */
228 	return -1;
229 }
230 
231 static int remove_block_file(struct tee_fs_fd *fdp, size_t block_num)
232 {
233 	DMSG("remove block%zd", block_num);
234 	return __remove_block_file(fdp, block_num, false);
235 }
236 
237 static int remove_outdated_block(struct tee_fs_fd *fdp, size_t block_num)
238 {
239 	DMSG("remove outdated block%zd", block_num);
240 	return __remove_block_file(fdp, block_num, true);
241 }
242 
243 /*
244  * encrypted_fek: as input for META_FILE and BLOCK_FILE
245  */
246 static TEE_Result encrypt_and_write_file(const char *file_name,
247 		enum tee_fs_file_type file_type,
248 		void *data_in, size_t data_in_size,
249 		uint8_t *encrypted_fek)
250 {
251 	TEE_Result res;
252 	TEE_Result res2;
253 	struct tee_fs_rpc_operation op;
254 	void *ciphertext;
255 	size_t header_size = tee_fs_get_header_size(file_type);
256 	size_t ciphertext_size = header_size + data_in_size;
257 	int fd;
258 
259 	res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, file_name, &fd);
260 	if (res != TEE_SUCCESS) {
261 		if (res != TEE_ERROR_ITEM_NOT_FOUND)
262 			return res;
263 		res = tee_fs_rpc_new_create(OPTEE_MSG_RPC_CMD_FS, file_name,
264 					    &fd);
265 		if (res != TEE_SUCCESS)
266 			return res;
267 	}
268 
269 	res = tee_fs_rpc_new_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fd, 0,
270 					ciphertext_size, &ciphertext);
271 	if (res != TEE_SUCCESS)
272 		goto out;
273 
274 	res = tee_fs_encrypt_file(file_type, data_in, data_in_size,
275 				  ciphertext, &ciphertext_size, encrypted_fek);
276 	if (res != TEE_SUCCESS)
277 		goto out;
278 
279 	res = tee_fs_rpc_new_write_final(&op);
280 out:
281 	res2 = tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fd);
282 	if (res == TEE_SUCCESS)
283 		return res2;
284 	return res;
285 }
286 
287 /*
288  * encrypted_fek: as output for META_FILE
289  *                as input for BLOCK_FILE
290  */
291 static TEE_Result read_and_decrypt_file(const char *file_name,
292 		enum tee_fs_file_type file_type,
293 		void *data_out, size_t *data_out_size,
294 		uint8_t *encrypted_fek)
295 {
296 	TEE_Result res;
297 	TEE_Result res2;
298 	struct tee_fs_rpc_operation op;
299 	size_t bytes;
300 	void *ciphertext;
301 	int fd;
302 
303 	res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, file_name, &fd);
304 	if (res != TEE_SUCCESS)
305 		return res;
306 
307 	bytes = *data_out_size + tee_fs_get_header_size(file_type);
308 	res = tee_fs_rpc_new_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fd, 0,
309 				       bytes, &ciphertext);
310 	if (res != TEE_SUCCESS)
311 		goto out;
312 
313 	res = tee_fs_rpc_new_read_final(&op, &bytes);
314 	if (res != TEE_SUCCESS)
315 		goto out;
316 
317 	res = tee_fs_decrypt_file(file_type, ciphertext, bytes, data_out,
318 				  data_out_size, encrypted_fek);
319 	if (res != TEE_SUCCESS)
320 		res = TEE_ERROR_CORRUPT_OBJECT;
321 out:
322 	res2 = tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fd);
323 	if (res == TEE_SUCCESS)
324 		return res2;
325 	return res;
326 }
327 
328 static TEE_Result write_meta_file(const char *filename,
329 		struct tee_fs_file_meta *meta)
330 {
331 	char meta_path[REE_FS_NAME_MAX];
332 
333 	get_meta_filepath(filename, meta->backup_version, meta_path);
334 
335 	return encrypt_and_write_file(meta_path, META_FILE,
336 			(void *)&meta->info, sizeof(meta->info),
337 			meta->encrypted_fek);
338 
339 }
340 
341 static TEE_Result create_meta(struct tee_fs_fd *fdp)
342 {
343 	TEE_Result res;
344 
345 	memset(fdp->meta.info.backup_version_table, 0xff,
346 		sizeof(fdp->meta.info.backup_version_table));
347 	fdp->meta.info.length = 0;
348 
349 	res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE);
350 	if (res != TEE_SUCCESS)
351 		return res;
352 
353 	fdp->meta.backup_version = 0;
354 
355 	return write_meta_file(fdp->filename, &fdp->meta);
356 }
357 
358 static int commit_meta_file(struct tee_fs_fd *fdp,
359 		struct tee_fs_file_meta *new_meta)
360 {
361 	int res;
362 	uint8_t old_version;
363 	char meta_path[REE_FS_NAME_MAX];
364 
365 	old_version = new_meta->backup_version;
366 	new_meta->backup_version = !new_meta->backup_version;
367 
368 	res = write_meta_file(fdp->filename, new_meta);
369 
370 	if (res < 0)
371 		return res;
372 
373 	/*
374 	 * From now on the new meta is successfully committed,
375 	 * change tee_fs_fd accordingly
376 	 */
377 	fdp->meta = *new_meta;
378 
379 	/*
380 	 * Remove outdated meta file, there is nothing we can
381 	 * do if we fail here, but that is OK because both
382 	 * new & old version of block files are kept. The context
383 	 * of the file is still consistent.
384 	 */
385 	get_meta_filepath(fdp->filename, old_version, meta_path);
386 	tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, meta_path);
387 
388 	return res;
389 }
390 
391 static TEE_Result read_meta_file(const char *meta_path,
392 		struct tee_fs_file_meta *meta)
393 {
394 	size_t meta_info_size = sizeof(struct tee_fs_file_info);
395 
396 	return read_and_decrypt_file(meta_path, META_FILE,
397 				     &meta->info, &meta_info_size,
398 				     meta->encrypted_fek);
399 }
400 
401 static TEE_Result read_meta(struct tee_fs_fd *fdp)
402 {
403 	TEE_Result res;
404 	char meta_path[REE_FS_NAME_MAX];
405 
406 	get_meta_filepath(fdp->filename, fdp->meta.backup_version, meta_path);
407 	res = read_meta_file(meta_path, &fdp->meta);
408 	if (res != TEE_SUCCESS) {
409 		TEE_Result res2;
410 
411 		fdp->meta.backup_version = !fdp->meta.backup_version;
412 		get_meta_filepath(fdp->filename, fdp->meta.backup_version,
413 				  meta_path);
414 		res2 = read_meta_file(meta_path, &fdp->meta);
415 		if (res2 != TEE_ERROR_ITEM_NOT_FOUND)
416 			return res2;
417 	}
418 
419 	return res;
420 }
421 
422 static bool is_block_file_exist(struct tee_fs_file_meta *meta,
423 					size_t block_num)
424 {
425 	size_t file_size = meta->info.length;
426 
427 	if (file_size == 0)
428 		return false;
429 
430 	return (block_num <= (size_t)get_last_block_num(file_size));
431 }
432 
433 static TEE_Result read_block_from_storage(struct tee_fs_fd *fdp,
434 					  struct block *b)
435 {
436 	TEE_Result res = TEE_SUCCESS;
437 	uint8_t *plaintext = b->data;
438 	char block_path[REE_FS_NAME_MAX];
439 	size_t block_file_size = BLOCK_FILE_SIZE;
440 	uint8_t version = get_backup_version_of_block(&fdp->meta, b->block_num);
441 
442 	if (!is_block_file_exist(&fdp->meta, b->block_num))
443 		goto exit;
444 
445 	get_block_filepath(fdp->filename, b->block_num, version,
446 			block_path);
447 
448 	res = read_and_decrypt_file(block_path, BLOCK_FILE,
449 			plaintext, &block_file_size,
450 			fdp->meta.encrypted_fek);
451 	if (res != TEE_SUCCESS) {
452 		EMSG("Failed to read and decrypt file");
453 		goto exit;
454 	}
455 	b->data_size = block_file_size;
456 	DMSG("Successfully read and decrypt block%d from storage, size=%zd",
457 		b->block_num, b->data_size);
458 exit:
459 	return res;
460 }
461 
462 static int flush_block_to_storage(struct tee_fs_fd *fdp, struct block *b,
463 					 struct tee_fs_file_meta *new_meta)
464 {
465 	TEE_Result res;
466 	size_t block_num = b->block_num;
467 	char block_path[REE_FS_NAME_MAX];
468 	uint8_t new_version =
469 		!get_backup_version_of_block(&fdp->meta, block_num);
470 
471 	get_block_filepath(fdp->filename, block_num, new_version, block_path);
472 
473 	res = encrypt_and_write_file(block_path, BLOCK_FILE, b->data,
474 				     b->data_size, new_meta->encrypted_fek);
475 	if (res != TEE_SUCCESS) {
476 		EMSG("Failed to encrypt and write block file");
477 		goto fail;
478 	}
479 
480 	DMSG("Successfully encrypt and write block%d to storage, size=%zd",
481 		b->block_num, b->data_size);
482 	toggle_backup_version_of_block(new_meta, block_num);
483 
484 	return 0;
485 fail:
486 	return -1;
487 }
488 
489 static struct block *alloc_block(void)
490 {
491 	struct block *c;
492 
493 	c = malloc(sizeof(struct block));
494 	if (!c)
495 		return NULL;
496 
497 	c->data = malloc(BLOCK_FILE_SIZE);
498 	if (!c->data) {
499 		EMSG("unable to alloc memory for block data");
500 		goto exit;
501 	}
502 
503 	c->block_num = -1;
504 	c->data_size = 0;
505 
506 	return c;
507 
508 exit:
509 	free(c);
510 	return NULL;
511 }
512 
513 #ifdef CFG_FS_BLOCK_CACHE
514 static void free_block(struct block *b)
515 {
516 	if (b) {
517 		free(b->data);
518 		free(b);
519 	}
520 }
521 
522 static inline bool is_block_data_invalid(struct block *b)
523 {
524 	return (b->data_size == 0);
525 }
526 
527 static void get_block_from_cache(struct block_cache *cache,
528 			int block_num, struct block **out_block)
529 {
530 	struct block *b, *found = NULL;
531 
532 	DMSG("Try to find block%d in cache", block_num);
533 	TAILQ_FOREACH(b, &cache->block_lru, list) {
534 		if (b->block_num == block_num) {
535 			DMSG("Found in cache");
536 			found = b;
537 			break;
538 		}
539 	}
540 
541 	if (found) {
542 		TAILQ_REMOVE(&cache->block_lru, found, list);
543 		TAILQ_INSERT_HEAD(&cache->block_lru, found, list);
544 		*out_block = found;
545 		return;
546 	}
547 
548 	DMSG("Not found, reuse oldest block on LRU list");
549 	b = TAILQ_LAST(&cache->block_lru, block_head);
550 	TAILQ_REMOVE(&cache->block_lru, b, list);
551 	TAILQ_INSERT_HEAD(&cache->block_lru, b, list);
552 	b->block_num = block_num;
553 	b->data_size = 0;
554 	*out_block = b;
555 }
556 
557 static int init_block_cache(struct block_cache *cache)
558 {
559 	struct block *b;
560 
561 	TAILQ_INIT(&cache->block_lru);
562 	cache->cached_block_num = 0;
563 
564 	while (cache->cached_block_num < MAX_NUM_CACHED_BLOCKS) {
565 
566 		b = alloc_block();
567 		if (!b) {
568 			EMSG("Failed to alloc block");
569 			goto fail;
570 		} else {
571 			TAILQ_INSERT_HEAD(&cache->block_lru, b, list);
572 			cache->cached_block_num++;
573 		}
574 	}
575 	return 0;
576 
577 fail:
578 	TAILQ_FOREACH(b, &cache->block_lru, list)
579 		free_block(b);
580 	return -1;
581 }
582 
583 static void destroy_block_cache(struct block_cache *cache)
584 {
585 	struct block *b, *next;
586 
587 	TAILQ_FOREACH_SAFE(b, &cache->block_lru, list, next) {
588 		TAILQ_REMOVE(&cache->block_lru, b, list);
589 		free_block(b);
590 	}
591 }
592 #else
593 static int init_block_cache(struct block_cache *cache __unused)
594 {
595 	return 0;
596 }
597 
598 static void destroy_block_cache(struct block_cache *cache __unused)
599 {
600 }
601 #endif
602 
603 static void write_data_to_block(struct block *b, int offset,
604 				void *buf, size_t len)
605 {
606 	DMSG("Write %zd bytes to block%d", len, b->block_num);
607 	memcpy(b->data + offset, buf, len);
608 	if (offset + len > b->data_size) {
609 		b->data_size = offset + len;
610 		DMSG("Extend block%d size to %zd bytes",
611 				b->block_num, b->data_size);
612 	}
613 }
614 
615 static void read_data_from_block(struct block *b, int offset,
616 				void *buf, size_t len)
617 {
618 	DMSG("Read %zd bytes from block%d", len, b->block_num);
619 	if (offset + len > b->data_size)
620 		panic("Exceeding block size");
621 	memcpy(buf, b->data + offset, len);
622 }
623 
624 #ifdef CFG_FS_BLOCK_CACHE
625 static struct block *read_block_with_cache(struct tee_fs_fd *fdp, int block_num)
626 {
627 	struct block *b;
628 
629 	get_block_from_cache(&fdp->block_cache, block_num, &b);
630 	if (is_block_data_invalid(b))
631 		if (read_block_from_storage(fdp, b)) {
632 			EMSG("Unable to read block%d from storage",
633 					block_num);
634 			return NULL;
635 		}
636 
637 	return b;
638 }
639 #else
640 
641 static struct block *read_block_no_cache(struct tee_fs_fd *fdp, int block_num)
642 {
643 	static struct block *b;
644 	TEE_Result res;
645 
646 	if (!b)
647 		b = alloc_block();
648 	b->block_num = block_num;
649 
650 	res = read_block_from_storage(fdp, b);
651 	if (res != TEE_SUCCESS)
652 		EMSG("Unable to read block%d from storage",
653 				block_num);
654 
655 	return res != TEE_SUCCESS ? NULL : b;
656 }
657 #endif
658 
659 static struct block_operations block_ops = {
660 #ifdef CFG_FS_BLOCK_CACHE
661 	.read = read_block_with_cache,
662 #else
663 	.read = read_block_no_cache,
664 #endif
665 	.write = flush_block_to_storage,
666 };
667 
668 static int out_of_place_write(struct tee_fs_fd *fdp, const void *buf,
669 		size_t len, struct tee_fs_file_meta *new_meta)
670 {
671 	int start_block_num = pos_to_block_num(fdp->pos);
672 	int end_block_num = pos_to_block_num(fdp->pos + len - 1);
673 	size_t remain_bytes = len;
674 	uint8_t *data_ptr = (uint8_t *)buf;
675 	int orig_pos = fdp->pos;
676 
677 	while (start_block_num <= end_block_num) {
678 		int offset = fdp->pos % BLOCK_FILE_SIZE;
679 		struct block *b;
680 		size_t size_to_write = (remain_bytes > BLOCK_FILE_SIZE) ?
681 			BLOCK_FILE_SIZE : remain_bytes;
682 
683 		if (size_to_write + offset > BLOCK_FILE_SIZE)
684 			size_to_write = BLOCK_FILE_SIZE - offset;
685 
686 		b = block_ops.read(fdp, start_block_num);
687 		if (!b)
688 			goto failed;
689 
690 		DMSG("Write data, offset: %d, size_to_write: %zd",
691 			offset, size_to_write);
692 		write_data_to_block(b, offset, data_ptr, size_to_write);
693 
694 		if (block_ops.write(fdp, b, new_meta)) {
695 			EMSG("Unable to wrtie block%d to storage",
696 					b->block_num);
697 			goto failed;
698 		}
699 
700 		data_ptr += size_to_write;
701 		remain_bytes -= size_to_write;
702 		start_block_num++;
703 		fdp->pos += size_to_write;
704 	}
705 
706 	if (fdp->pos > (tee_fs_off_t)new_meta->info.length)
707 		new_meta->info.length = fdp->pos;
708 
709 	return 0;
710 failed:
711 	fdp->pos = orig_pos;
712 	return -1;
713 }
714 
715 static inline int create_hard_link(const char *old_dir,
716 			const char *new_dir,
717 			const char *filename)
718 {
719 	char old_path[REE_FS_NAME_MAX];
720 	char new_path[REE_FS_NAME_MAX];
721 
722 	snprintf(old_path, REE_FS_NAME_MAX, "%s/%s",
723 			old_dir, filename);
724 	snprintf(new_path, REE_FS_NAME_MAX, "%s/%s",
725 			new_dir, filename);
726 
727 	DMSG("%s -> %s", old_path, new_path);
728 	return tee_fs_rpc_link(OPTEE_MSG_RPC_CMD_FS, old_path, new_path);
729 }
730 
731 static int unlink_tee_file(const char *file)
732 {
733 	int res = -1;
734 	size_t len = strlen(file) + 1;
735 	struct tee_fs_dirent *dirent;
736 	struct tee_fs_dir *dir;
737 
738 	DMSG("file=%s", file);
739 
740 	if (len > TEE_FS_NAME_MAX)
741 		goto exit;
742 
743 	dir = ree_fs_opendir_rpc(file);
744 	if (!dir)
745 		goto exit;
746 
747 	dirent = ree_fs_readdir_rpc(dir);
748 	while (dirent) {
749 		char path[REE_FS_NAME_MAX];
750 
751 		snprintf(path, REE_FS_NAME_MAX, "%s/%s",
752 			file, dirent->d_name);
753 
754 		DMSG("unlink %s", path);
755 		if (tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, path) !=
756 			TEE_SUCCESS) {
757 			ree_fs_closedir_rpc(dir);
758 			res = -1;
759 			goto exit;
760 		}
761 		dirent = ree_fs_readdir_rpc(dir);
762 	}
763 
764 	res = ree_fs_closedir_rpc(dir);
765 	if (res)
766 		goto exit;
767 
768 	res = ree_fs_rmdir_rpc(file);
769 exit:
770 	return res;
771 }
772 
773 static int ree_fs_ftruncate_internal(TEE_Result *errno, struct tee_fs_fd *fdp,
774 				   tee_fs_off_t new_file_len);
775 
776 static int ree_fs_open(TEE_Result *errno, const char *file, int flags, ...)
777 {
778 	TEE_Result res;
779 	int rc = -1;
780 	size_t len;
781 	struct tee_fs_fd *fdp = NULL;
782 
783 	mutex_lock(&ree_fs_mutex);
784 
785 	assert(errno);
786 	*errno = TEE_SUCCESS;
787 
788 	if (!file) {
789 		*errno = TEE_ERROR_BAD_PARAMETERS;
790 		goto exit;
791 	}
792 
793 	len = strlen(file) + 1;
794 	if (len > TEE_FS_NAME_MAX) {
795 		*errno = TEE_ERROR_BAD_PARAMETERS;
796 		goto exit;
797 	}
798 
799 	fdp = calloc(1, sizeof(struct tee_fs_fd));
800 	if (!fdp) {
801 		*errno = TEE_ERROR_OUT_OF_MEMORY;
802 		goto exit;
803 	}
804 
805 	/* init internal status */
806 	fdp->flags = flags;
807 	if (init_block_cache(&fdp->block_cache)) {
808 		*errno = TEE_ERROR_OUT_OF_MEMORY;
809 		goto exit_free_fd;
810 	}
811 
812 	fdp->filename = malloc(len);
813 	if (!fdp->filename) {
814 		rc = -1;
815 		*errno = TEE_ERROR_OUT_OF_MEMORY;
816 		goto exit_destroy_block_cache;
817 	}
818 	memcpy(fdp->filename, file, len);
819 
820 	res = read_meta(fdp);
821 	if (res == TEE_SUCCESS) {
822 		if (flags & TEE_FS_O_EXCL) {
823 			*errno = TEE_ERROR_ACCESS_CONFLICT;
824 			goto exit_free_filename;
825 		}
826 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
827 		if (!(flags & TEE_FS_O_CREATE)) {
828 			*errno = res;
829 			goto exit_free_filename;
830 		}
831 		res = create_meta(fdp);
832 		if (res != TEE_SUCCESS) {
833 			*errno = res;
834 			goto exit_free_filename;
835 		}
836 	} else {
837 		*errno = res;
838 		goto exit_free_filename;
839 	}
840 
841 	/* return fd */
842 	rc = handle_get(&fs_handle_db, fdp);
843 	if (rc < 0)
844 		goto exit_free_filename;
845 	fdp->fd = rc;
846 	goto exit;
847 
848 exit_free_filename:
849 	free(fdp->filename);
850 exit_destroy_block_cache:
851 	destroy_block_cache(&fdp->block_cache);
852 exit_free_fd:
853 	free(fdp);
854 exit:
855 	mutex_unlock(&ree_fs_mutex);
856 	return rc;
857 }
858 
859 static int ree_fs_close(int fd)
860 {
861 	int res = -1;
862 	struct tee_fs_fd *fdp;
863 
864 	mutex_lock(&ree_fs_mutex);
865 
866 	fdp = handle_lookup(&fs_handle_db, fd);
867 	if (!fdp)
868 		goto exit;
869 
870 	handle_put(&fs_handle_db, fdp->fd);
871 
872 	destroy_block_cache(&fdp->block_cache);
873 	free(fdp->filename);
874 	free(fdp);
875 
876 exit:
877 	mutex_unlock(&ree_fs_mutex);
878 	return res;
879 }
880 
881 static tee_fs_off_t ree_fs_lseek(TEE_Result *errno, int fd,
882 				 tee_fs_off_t offset, int whence)
883 {
884 	tee_fs_off_t res = -1;
885 	tee_fs_off_t new_pos;
886 	size_t filelen;
887 	struct tee_fs_fd *fdp;
888 
889 	mutex_lock(&ree_fs_mutex);
890 
891 	assert(errno);
892 	*errno = TEE_SUCCESS;
893 
894 	fdp = handle_lookup(&fs_handle_db, fd);
895 	if (!fdp) {
896 		*errno = TEE_ERROR_BAD_PARAMETERS;
897 		goto exit;
898 	}
899 
900 	DMSG("offset=%d, whence=%d", (int)offset, whence);
901 
902 	filelen = fdp->meta.info.length;
903 
904 	switch (whence) {
905 	case TEE_FS_SEEK_SET:
906 		new_pos = offset;
907 		break;
908 
909 	case TEE_FS_SEEK_CUR:
910 		new_pos = fdp->pos + offset;
911 		break;
912 
913 	case TEE_FS_SEEK_END:
914 		new_pos = filelen + offset;
915 		break;
916 
917 	default:
918 		*errno = TEE_ERROR_BAD_PARAMETERS;
919 		goto exit;
920 	}
921 
922 	if (new_pos < 0)
923 		new_pos = 0;
924 
925 	if (new_pos > TEE_DATA_MAX_POSITION) {
926 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
927 		*errno = TEE_ERROR_BAD_PARAMETERS;
928 		goto exit;
929 	}
930 
931 	res = fdp->pos = new_pos;
932 exit:
933 	mutex_unlock(&ree_fs_mutex);
934 	return res;
935 }
936 
937 /*
938  * To ensure atomic truncate operation, we can:
939  *
940  *  - update file length to new length
941  *  - commit new meta
942  *  - free unused blocks
943  *
944  * To ensure atomic extend operation, we can:
945  *
946  *  - update file length to new length
947  *  - allocate and fill zero data to new blocks
948  *  - commit new meta
949  *
950  * Any failure before committing new meta is considered as
951  * update failed, and the file content will not be updated
952  */
953 static int ree_fs_ftruncate_internal(TEE_Result *errno, struct tee_fs_fd *fdp,
954 				   tee_fs_off_t new_file_len)
955 {
956 	int res = -1;
957 	size_t old_file_len = fdp->meta.info.length;
958 	struct tee_fs_file_meta new_meta;
959 	uint8_t *buf = NULL;
960 
961 	assert(errno);
962 	*errno = TEE_SUCCESS;
963 
964 	if (!fdp) {
965 		*errno = TEE_ERROR_BAD_PARAMETERS;
966 		res = -1;
967 		goto exit;
968 	}
969 
970 	if (fdp->flags & TEE_FS_O_RDONLY) {
971 		*errno = TEE_ERROR_BAD_PARAMETERS;
972 		EMSG("Read only");
973 		res = -1;
974 		goto exit;
975 	}
976 
977 	if ((size_t)new_file_len == old_file_len) {
978 		DMSG("Ignore due to file length does not changed");
979 		res = 0;
980 		goto exit;
981 	}
982 
983 	if (new_file_len > MAX_FILE_SIZE) {
984 		*errno = TEE_ERROR_BAD_PARAMETERS;
985 		EMSG("Over maximum file size(%d)", MAX_FILE_SIZE);
986 		res = -1;
987 		goto exit;
988 	}
989 
990 	new_meta = fdp->meta;
991 	new_meta.info.length = new_file_len;
992 
993 	if ((size_t)new_file_len < old_file_len) {
994 		int old_block_num = get_last_block_num(old_file_len);
995 		int new_block_num = get_last_block_num(new_file_len);
996 
997 		DMSG("Truncate file length to %zu", (size_t)new_file_len);
998 
999 		res = commit_meta_file(fdp, &new_meta);
1000 		if (res < 0) {
1001 			*errno = TEE_ERROR_CORRUPT_OBJECT;
1002 			EMSG("Failed to commit meta file");
1003 			goto free;
1004 		}
1005 
1006 		/* now we are safe to free unused blocks */
1007 		while (old_block_num > new_block_num) {
1008 			if (remove_block_file(fdp, old_block_num)) {
1009 				IMSG("Warning: Failed to free block: %d",
1010 						old_block_num);
1011 			}
1012 
1013 			old_block_num--;
1014 		}
1015 
1016 	} else {
1017 		size_t ext_len = new_file_len - old_file_len;
1018 		int orig_pos = fdp->pos;
1019 
1020 		buf = malloc(BLOCK_FILE_SIZE);
1021 		if (!buf) {
1022 			*errno = TEE_ERROR_OUT_OF_MEMORY;
1023 			EMSG("Failed to allocate buffer, size=%d",
1024 					BLOCK_FILE_SIZE);
1025 			res = -1;
1026 			goto free;
1027 		}
1028 
1029 		memset(buf, 0x0, BLOCK_FILE_SIZE);
1030 
1031 		DMSG("Extend file length to %zu", (size_t)new_file_len);
1032 
1033 		fdp->pos = old_file_len;
1034 
1035 		res = 0;
1036 		while (ext_len > 0) {
1037 			size_t data_len = (ext_len > BLOCK_FILE_SIZE) ?
1038 					BLOCK_FILE_SIZE : ext_len;
1039 
1040 			DMSG("fill len=%zu", data_len);
1041 			res = out_of_place_write(fdp, (void *)buf,
1042 					data_len, &new_meta);
1043 			if (res < 0) {
1044 				*errno = TEE_ERROR_CORRUPT_OBJECT;
1045 				EMSG("Failed to fill data");
1046 				break;
1047 			}
1048 
1049 			ext_len -= data_len;
1050 		}
1051 
1052 		fdp->pos = orig_pos;
1053 
1054 		if (res == 0) {
1055 			res = commit_meta_file(fdp, &new_meta);
1056 			if (res < 0) {
1057 				*errno = TEE_ERROR_CORRUPT_OBJECT;
1058 				EMSG("Failed to commit meta file");
1059 			}
1060 		}
1061 	}
1062 
1063 free:
1064 	free(buf);
1065 
1066 exit:
1067 	return res;
1068 }
1069 
1070 static int ree_fs_read(TEE_Result *errno, int fd, void *buf, size_t len)
1071 {
1072 	int res = -1;
1073 	int start_block_num;
1074 	int end_block_num;
1075 	size_t remain_bytes = len;
1076 	uint8_t *data_ptr = buf;
1077 	struct tee_fs_fd *fdp;
1078 
1079 	mutex_lock(&ree_fs_mutex);
1080 
1081 	assert(errno);
1082 	*errno = TEE_SUCCESS;
1083 
1084 	fdp = handle_lookup(&fs_handle_db, fd);
1085 	if (!fdp) {
1086 		*errno = TEE_ERROR_BAD_PARAMETERS;
1087 		goto exit;
1088 	}
1089 
1090 	if ((fdp->pos + len) < len ||
1091 	    fdp->pos > (tee_fs_off_t)fdp->meta.info.length)
1092 		len = 0;
1093 	else if (fdp->pos + len > fdp->meta.info.length)
1094 		len = fdp->meta.info.length - fdp->pos;
1095 
1096 	if (!len) {
1097 		res = 0;
1098 		goto exit;
1099 	}
1100 
1101 	if (!buf) {
1102 		*errno = TEE_ERROR_BAD_PARAMETERS;
1103 		goto exit;
1104 	}
1105 
1106 	if (fdp->flags & TEE_FS_O_WRONLY) {
1107 		*errno = TEE_ERROR_ACCESS_CONFLICT;
1108 		goto exit;
1109 	}
1110 
1111 	DMSG("%s, data len=%zu", fdp->filename, len);
1112 
1113 	start_block_num = pos_to_block_num(fdp->pos);
1114 	end_block_num = pos_to_block_num(fdp->pos + len - 1);
1115 	DMSG("start_block_num:%d, end_block_num:%d",
1116 		start_block_num, end_block_num);
1117 
1118 	while (start_block_num <= end_block_num) {
1119 		struct block *b;
1120 		int offset = fdp->pos % BLOCK_FILE_SIZE;
1121 		size_t size_to_read = remain_bytes > BLOCK_FILE_SIZE ?
1122 			BLOCK_FILE_SIZE : remain_bytes;
1123 
1124 		if (size_to_read + offset > BLOCK_FILE_SIZE)
1125 			size_to_read = BLOCK_FILE_SIZE - offset;
1126 
1127 		DMSG("block_num:%d, offset:%d, size_to_read: %zd",
1128 			start_block_num, offset, size_to_read);
1129 
1130 		b = block_ops.read(fdp, start_block_num);
1131 		if (!b) {
1132 			*errno = TEE_ERROR_CORRUPT_OBJECT;
1133 			goto exit;
1134 		}
1135 
1136 		read_data_from_block(b, offset, data_ptr, size_to_read);
1137 		data_ptr += size_to_read;
1138 		remain_bytes -= size_to_read;
1139 		fdp->pos += size_to_read;
1140 
1141 		start_block_num++;
1142 	}
1143 	res = 0;
1144 exit:
1145 	mutex_unlock(&ree_fs_mutex);
1146 	return (res < 0) ? res : (int)len;
1147 }
1148 
1149 /*
1150  * To ensure atomicity of write operation, we need to
1151  * do the following steps:
1152  * (The sequence of operations is very important)
1153  *
1154  *  - Create a new backup version of meta file as a copy
1155  *    of current meta file.
1156  *  - For each blocks to write:
1157  *    - Create new backup version for current block.
1158  *    - Write data to new backup version.
1159  *    - Update the new meta file accordingly.
1160  *  - Write the new meta file.
1161  *
1162  * (Any failure in above steps is considered as update failed,
1163  *  and the file content will not be updated)
1164  *
1165  * After previous step the update is considered complete, but
1166  * we should do the following clean-up step(s):
1167  *
1168  *  - Delete old meta file.
1169  *  - Remove old block files.
1170  *
1171  * (Any failure in above steps is considered as a successfully
1172  *  update)
1173  */
1174 static int ree_fs_write(TEE_Result *errno, int fd, const void *buf, size_t len)
1175 {
1176 	int res = -1;
1177 	struct tee_fs_file_meta new_meta;
1178 	struct tee_fs_fd *fdp;
1179 	size_t file_size;
1180 	int orig_pos;
1181 
1182 	mutex_lock(&ree_fs_mutex);
1183 
1184 	assert(errno);
1185 	*errno = TEE_SUCCESS;
1186 
1187 	fdp = handle_lookup(&fs_handle_db, fd);
1188 	if (!fdp) {
1189 		*errno = TEE_ERROR_BAD_PARAMETERS;
1190 		goto exit;
1191 	}
1192 	if (!len) {
1193 		res = 0;
1194 		goto exit;
1195 	}
1196 	if (!buf) {
1197 		*errno = TEE_ERROR_BAD_PARAMETERS;
1198 		goto exit;
1199 	}
1200 
1201 	file_size = fdp->meta.info.length;
1202 	orig_pos = fdp->pos;
1203 
1204 	if (fdp->flags & TEE_FS_O_RDONLY) {
1205 		EMSG("Write to a read-only file, denied");
1206 		*errno = TEE_ERROR_ACCESS_CONFLICT;
1207 		goto exit;
1208 	}
1209 
1210 	if ((fdp->pos + len) > MAX_FILE_SIZE) {
1211 		EMSG("Over maximum file size(%d)", MAX_FILE_SIZE);
1212 		*errno = TEE_ERROR_BAD_PARAMETERS;
1213 		goto exit;
1214 	}
1215 
1216 	DMSG("%s, data len=%zu", fdp->filename, len);
1217 	if (file_size < (size_t)fdp->pos) {
1218 		DMSG("File hole detected, try to extend file size");
1219 		res = ree_fs_ftruncate_internal(errno, fdp, fdp->pos);
1220 		if (res < 0)
1221 			goto exit;
1222 	}
1223 
1224 	new_meta = fdp->meta;
1225 	res = out_of_place_write(fdp, buf, len, &new_meta);
1226 	if (res < 0) {
1227 		*errno = TEE_ERROR_CORRUPT_OBJECT;
1228 	} else {
1229 		int r;
1230 		int start_block_num;
1231 		int end_block_num;
1232 
1233 		r = commit_meta_file(fdp, &new_meta);
1234 		if (r < 0) {
1235 			*errno = TEE_ERROR_CORRUPT_OBJECT;
1236 			res = -1;
1237 		}
1238 
1239 		/* we are safe to free old blocks */
1240 		start_block_num = pos_to_block_num(orig_pos);
1241 		end_block_num = pos_to_block_num(fdp->pos - 1);
1242 		while (start_block_num <= end_block_num) {
1243 			if (remove_outdated_block(fdp, start_block_num))
1244 				IMSG("Warning: Failed to free old block: %d",
1245 					start_block_num);
1246 
1247 			start_block_num++;
1248 		}
1249 	}
1250 exit:
1251 	mutex_unlock(&ree_fs_mutex);
1252 	return (res < 0) ? res : (int)len;
1253 }
1254 
1255 /*
1256  * To ensure atomicity of rename operation, we need to
1257  * do the following steps:
1258  *
1259  *  - Create a new folder that represents the renamed TEE file
1260  *  - For each REE block files, create a hard link under the just
1261  *    created folder (new TEE file)
1262  *  - Now we are ready to commit meta, create hard link for the
1263  *    meta file
1264  *
1265  * (Any failure in above steps is considered as update failed,
1266  *  and the file content will not be updated)
1267  *
1268  * After previous step the update is considered complete, but
1269  * we should do the following clean-up step(s):
1270  *
1271  *  - Unlink all REE files represents the old TEE file (including
1272  *    meta and block files)
1273  *
1274  * (Any failure in above steps is considered as a successfully
1275  *  update)
1276  */
1277 static int ree_fs_rename_internal(const char *old, const char *new)
1278 {
1279 	int res = -1;
1280 	size_t old_len;
1281 	size_t new_len;
1282 	size_t meta_count = 0;
1283 	struct tee_fs_dir *old_dir;
1284 	struct tee_fs_dirent *dirent;
1285 	char *meta_filename = NULL;
1286 
1287 	if (!old || !new)
1288 		return -1;
1289 
1290 	DMSG("old=%s, new=%s", old, new);
1291 
1292 	old_len = strlen(old) + 1;
1293 	new_len = strlen(new) + 1;
1294 
1295 	if (old_len > TEE_FS_NAME_MAX || new_len > TEE_FS_NAME_MAX)
1296 		goto exit;
1297 
1298 	res = ree_fs_mkdir_rpc(new,
1299 			TEE_FS_S_IRUSR | TEE_FS_S_IWUSR);
1300 	if (res)
1301 		goto exit;
1302 
1303 	old_dir = ree_fs_opendir_rpc(old);
1304 	if (!old_dir)
1305 		goto exit;
1306 
1307 	dirent = ree_fs_readdir_rpc(old_dir);
1308 	while (dirent) {
1309 		if (!strncmp(dirent->d_name, "meta.", 5)) {
1310 			meta_filename = strdup(dirent->d_name);
1311 			meta_count++;
1312 		} else {
1313 			res = create_hard_link(old, new, dirent->d_name);
1314 			if (res)
1315 				goto exit_close_old_dir;
1316 		}
1317 
1318 		dirent = ree_fs_readdir_rpc(old_dir);
1319 	}
1320 
1321 	/* finally, link the meta file, rename operation completed */
1322 	if (!meta_filename)
1323 		panic("no meta file");
1324 
1325 	/*
1326 	 * TODO: This will cause memory leakage at previous strdup()
1327 	 * if we accidently have two meta files in a TEE file.
1328 	 *
1329 	 * It's not easy to handle the case above (e.g. Which meta file
1330 	 * should be linked first? What to do if a power cut happened
1331 	 * during creating links for the two meta files?)
1332 	 *
1333 	 * We will solve this issue using another approach: merging
1334 	 * both meta and block files into a single REE file. This approach
1335 	 * can completely remove ree_fs_rename(). We can simply
1336 	 * rename TEE file using REE rename() system call, which is also
1337 	 * atomic.
1338 	 */
1339 	if (meta_count > 1)
1340 		EMSG("Warning: more than one meta file in your TEE file\n"
1341 		     "This will cause memory leakage.");
1342 
1343 	res = create_hard_link(old, new, meta_filename);
1344 	if (res)
1345 		goto exit_close_old_dir;
1346 
1347 	/* we are safe now, remove old TEE file */
1348 	unlink_tee_file(old);
1349 
1350 exit_close_old_dir:
1351 	ree_fs_closedir_rpc(old_dir);
1352 exit:
1353 	free(meta_filename);
1354 	return res;
1355 }
1356 
1357 static int ree_fs_rename(const char *old, const char *new)
1358 {
1359 	int res;
1360 
1361 	mutex_lock(&ree_fs_mutex);
1362 	res = ree_fs_rename_internal(old, new);
1363 	mutex_unlock(&ree_fs_mutex);
1364 
1365 	return res;
1366 }
1367 
1368 /*
1369  * To ensure atomic unlink operation, we can simply
1370  * split the unlink operation into:
1371  *
1372  *  - rename("file", "file.trash");
1373  *
1374  * (Any failure in above steps is considered as update failed,
1375  *  and the file content will not be updated)
1376  *
1377  * After previous step the update is considered complete, but
1378  * we should do the following clean-up step(s):
1379  *
1380  *  - unlink("file.trash");
1381  *
1382  * (Any failure in above steps is considered as a successfully
1383  *  update)
1384  */
1385 static int ree_fs_unlink(const char *file)
1386 {
1387 	int res = -1;
1388 	char trash_file[TEE_FS_NAME_MAX + 6];
1389 
1390 	if (!file)
1391 		return -1;
1392 
1393 	snprintf(trash_file, TEE_FS_NAME_MAX + 6, "%s.trash",
1394 		file);
1395 
1396 	mutex_lock(&ree_fs_mutex);
1397 
1398 	res = ree_fs_rename_internal(file, trash_file);
1399 	if (res < 0)
1400 		goto exit;
1401 
1402 	unlink_tee_file(trash_file);
1403 
1404 exit:
1405 	mutex_unlock(&ree_fs_mutex);
1406 	return res;
1407 }
1408 
1409 static int ree_fs_ftruncate(TEE_Result *errno, int fd, tee_fs_off_t length)
1410 {
1411 	struct tee_fs_fd *fdp;
1412 	int res;
1413 
1414 	mutex_lock(&ree_fs_mutex);
1415 	fdp = handle_lookup(&fs_handle_db, fd);
1416 	res = ree_fs_ftruncate_internal(errno, fdp, length);
1417 	mutex_unlock(&ree_fs_mutex);
1418 
1419 	return res;
1420 }
1421 
1422 const struct tee_file_operations ree_fs_ops = {
1423 	.open = ree_fs_open,
1424 	.close = ree_fs_close,
1425 	.read = ree_fs_read,
1426 	.write = ree_fs_write,
1427 	.lseek = ree_fs_lseek,
1428 	.ftruncate = ree_fs_ftruncate,
1429 	.rename = ree_fs_rename,
1430 	.unlink = ree_fs_unlink,
1431 	.mkdir = ree_fs_mkdir_rpc,
1432 	.opendir = ree_fs_opendir_rpc,
1433 	.closedir = ree_fs_closedir_rpc,
1434 	.readdir = ree_fs_readdir_rpc,
1435 	.rmdir = ree_fs_rmdir_rpc,
1436 	.access = ree_fs_access_rpc
1437 };
1438