xref: /optee_os/core/tee/tee_ree_fs.c (revision 04e46975d8f02e25209af552aaea4acb4d70c7f9)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
27c3ebaa8SJerome Forissier /*
37c3ebaa8SJerome Forissier  * Copyright (c) 2015, Linaro Limited
47c3ebaa8SJerome Forissier  */
57c3ebaa8SJerome Forissier 
67c3ebaa8SJerome Forissier #include <assert.h>
7300faa62SEtienne Carriere #include <config.h>
8233da534SJerome Forissier #include <kernel/mutex.h>
9623b9bd4SJens Wiklander #include <kernel/nv_counter.h>
10d13278b8SEtienne Carriere #include <kernel/panic.h>
11a238b744SJens Wiklander #include <kernel/thread.h>
12b2284b11SJens Wiklander #include <kernel/user_access.h>
1302d869c9SJens Wiklander #include <mempool.h>
147c3ebaa8SJerome Forissier #include <mm/core_memprot.h>
150e3f6d6bSJens Wiklander #include <mm/tee_pager.h>
166009538cSJens Wiklander #include <optee_rpc_cmd.h>
177c3ebaa8SJerome Forissier #include <stdlib.h>
18a238b744SJens Wiklander #include <string.h>
19233da534SJerome Forissier #include <sys/queue.h>
20ac0bab7fSJens Wiklander #include <tee/fs_dirfile.h>
21a238b744SJens Wiklander #include <tee/fs_htree.h>
22c8016054SJens Wiklander #include <tee/tee_fs.h>
23c8016054SJens Wiklander #include <tee/tee_fs_rpc.h>
2473ea1cdeSJens Wiklander #include <tee/tee_pobj.h>
257c3ebaa8SJerome Forissier #include <trace.h>
26233da534SJerome Forissier #include <utee_defines.h>
27233da534SJerome Forissier #include <util.h>
287c3ebaa8SJerome Forissier 
2906d858d5SJens Wiklander #define BLOCK_SHIFT	12
307c3ebaa8SJerome Forissier 
3106d858d5SJens Wiklander #define BLOCK_SIZE	(1 << BLOCK_SHIFT)
327c3ebaa8SJerome Forissier 
337c3ebaa8SJerome Forissier struct tee_fs_fd {
34a238b744SJens Wiklander 	struct tee_fs_htree *ht;
35361fb3e3SJens Wiklander 	int fd;
36ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_fileh dfh;
37ac0bab7fSJens Wiklander 	const TEE_UUID *uuid;
38ac0bab7fSJens Wiklander };
39ac0bab7fSJens Wiklander 
40ac0bab7fSJens Wiklander struct tee_fs_dir {
41ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_dirh *dirh;
42ac0bab7fSJens Wiklander 	int idx;
43ac0bab7fSJens Wiklander 	struct tee_fs_dirent d;
44fd108c3eSJens Wiklander 	const TEE_UUID *uuid;
457c3ebaa8SJerome Forissier };
467c3ebaa8SJerome Forissier 
pos_to_block_num(int position)47a238b744SJens Wiklander static int pos_to_block_num(int position)
487c3ebaa8SJerome Forissier {
4906d858d5SJens Wiklander 	return position >> BLOCK_SHIFT;
507c3ebaa8SJerome Forissier }
517c3ebaa8SJerome Forissier 
5215ace8d3SJerome Forissier static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
5315ace8d3SJerome Forissier 
get_tmp_block(void)540e3f6d6bSJens Wiklander static void *get_tmp_block(void)
550e3f6d6bSJens Wiklander {
5602d869c9SJens Wiklander 	return mempool_alloc(mempool_default, BLOCK_SIZE);
570e3f6d6bSJens Wiklander }
580e3f6d6bSJens Wiklander 
put_tmp_block(void * tmp_block)590e3f6d6bSJens Wiklander static void put_tmp_block(void *tmp_block)
600e3f6d6bSJens Wiklander {
6102d869c9SJens Wiklander 	mempool_free(mempool_default, tmp_block);
620e3f6d6bSJens Wiklander }
63ace6039fSJens Wiklander 
out_of_place_write(struct tee_fs_fd * fdp,size_t pos,const void * buf_core,const void * buf_user,size_t len)64879237aeSJens Wiklander static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos,
65b2284b11SJens Wiklander 				     const void *buf_core,
66b2284b11SJens Wiklander 				     const void *buf_user, size_t len)
677c3ebaa8SJerome Forissier {
6806d858d5SJens Wiklander 	TEE_Result res;
69879237aeSJens Wiklander 	size_t start_block_num = pos_to_block_num(pos);
70879237aeSJens Wiklander 	size_t end_block_num = pos_to_block_num(pos + len - 1);
717c3ebaa8SJerome Forissier 	size_t remain_bytes = len;
72b2284b11SJens Wiklander 	uint8_t *data_core_ptr = (uint8_t *)buf_core;
73b2284b11SJens Wiklander 	uint8_t *data_user_ptr = (uint8_t *)buf_user;
7406d858d5SJens Wiklander 	uint8_t *block;
75a238b744SJens Wiklander 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
767c3ebaa8SJerome Forissier 
778f58cdbeSJens Wiklander 	/*
788f58cdbeSJens Wiklander 	 * It doesn't make sense to call this function if nothing is to be
798f58cdbeSJens Wiklander 	 * written. This also guards against end_block_num getting an
808f58cdbeSJens Wiklander 	 * unexpected value when pos == 0 and len == 0.
818f58cdbeSJens Wiklander 	 */
828f58cdbeSJens Wiklander 	if (!len)
838f58cdbeSJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
848f58cdbeSJens Wiklander 
850e3f6d6bSJens Wiklander 	block = get_tmp_block();
8606d858d5SJens Wiklander 	if (!block)
8706d858d5SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
8806d858d5SJens Wiklander 
897c3ebaa8SJerome Forissier 	while (start_block_num <= end_block_num) {
90879237aeSJens Wiklander 		size_t offset = pos % BLOCK_SIZE;
9106d858d5SJens Wiklander 		size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
927c3ebaa8SJerome Forissier 
9306d858d5SJens Wiklander 		if (size_to_write + offset > BLOCK_SIZE)
9406d858d5SJens Wiklander 			size_to_write = BLOCK_SIZE - offset;
957c3ebaa8SJerome Forissier 
96a238b744SJens Wiklander 		if (start_block_num * BLOCK_SIZE <
97a238b744SJens Wiklander 		    ROUNDUP(meta->length, BLOCK_SIZE)) {
98a238b744SJens Wiklander 			res = tee_fs_htree_read_block(&fdp->ht,
99a238b744SJens Wiklander 						      start_block_num, block);
100a238b744SJens Wiklander 			if (res != TEE_SUCCESS)
10106d858d5SJens Wiklander 				goto exit;
102a238b744SJens Wiklander 		} else {
103a238b744SJens Wiklander 			memset(block, 0, BLOCK_SIZE);
104a238b744SJens Wiklander 		}
1057c3ebaa8SJerome Forissier 
106b2284b11SJens Wiklander 		if (data_core_ptr) {
107b2284b11SJens Wiklander 			memcpy(block + offset, data_core_ptr, size_to_write);
108b2284b11SJens Wiklander 		} else if (data_user_ptr) {
109b2284b11SJens Wiklander 			res = copy_from_user(block + offset, data_user_ptr,
110b2284b11SJens Wiklander 					     size_to_write);
111b2284b11SJens Wiklander 			if (res)
112b2284b11SJens Wiklander 				return res;
113b2284b11SJens Wiklander 		} else {
11406d858d5SJens Wiklander 			memset(block + offset, 0, size_to_write);
115b2284b11SJens Wiklander 		}
1167c3ebaa8SJerome Forissier 
117a238b744SJens Wiklander 		res = tee_fs_htree_write_block(&fdp->ht, start_block_num,
118a238b744SJens Wiklander 					       block);
11906d858d5SJens Wiklander 		if (res != TEE_SUCCESS)
12006d858d5SJens Wiklander 			goto exit;
1217c3ebaa8SJerome Forissier 
122b2284b11SJens Wiklander 		if (data_core_ptr)
123b2284b11SJens Wiklander 			data_core_ptr += size_to_write;
124b2284b11SJens Wiklander 		if (data_user_ptr)
125b2284b11SJens Wiklander 			data_user_ptr += size_to_write;
1267c3ebaa8SJerome Forissier 		remain_bytes -= size_to_write;
1277c3ebaa8SJerome Forissier 		start_block_num++;
128879237aeSJens Wiklander 		pos += size_to_write;
1297c3ebaa8SJerome Forissier 	}
1307c3ebaa8SJerome Forissier 
13133e4def6SJerome Forissier 	if (pos > meta->length) {
132879237aeSJens Wiklander 		meta->length = pos;
13333e4def6SJerome Forissier 		tee_fs_htree_meta_set_dirty(fdp->ht);
13433e4def6SJerome Forissier 	}
1357c3ebaa8SJerome Forissier 
13606d858d5SJens Wiklander exit:
1370e3f6d6bSJens Wiklander 	if (block)
1380e3f6d6bSJens Wiklander 		put_tmp_block(block);
13906d858d5SJens Wiklander 	return res;
1407c3ebaa8SJerome Forissier }
1417c3ebaa8SJerome Forissier 
get_offs_size(enum tee_fs_htree_type type,size_t idx,uint8_t vers,size_t * offs,size_t * size)142a238b744SJens Wiklander static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
143a238b744SJens Wiklander 				uint8_t vers, size_t *offs, size_t *size)
144a238b744SJens Wiklander {
145a238b744SJens Wiklander 	const size_t node_size = sizeof(struct tee_fs_htree_node_image);
146a238b744SJens Wiklander 	const size_t block_nodes = BLOCK_SIZE / (node_size * 2);
147a238b744SJens Wiklander 	size_t pbn;
148a238b744SJens Wiklander 	size_t bidx;
149a238b744SJens Wiklander 
150a238b744SJens Wiklander 	assert(vers == 0 || vers == 1);
151a238b744SJens Wiklander 
152a238b744SJens Wiklander 	/*
153a238b744SJens Wiklander 	 * File layout
1548c6a8affSwellsleep 	 * [demo with input:
1558c6a8affSwellsleep 	 * BLOCK_SIZE = 4096,
1568c6a8affSwellsleep 	 * node_size = 66,
1578c6a8affSwellsleep 	 * block_nodes = 4096/(66*2) = 31 ]
158a238b744SJens Wiklander 	 *
159a238b744SJens Wiklander 	 * phys block 0:
160a238b744SJens Wiklander 	 * tee_fs_htree_image vers 0 @ offs = 0
161a238b744SJens Wiklander 	 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image)
162a238b744SJens Wiklander 	 *
163a238b744SJens Wiklander 	 * phys block 1:
164a238b744SJens Wiklander 	 * tee_fs_htree_node_image 0  vers 0 @ offs = 0
165a238b744SJens Wiklander 	 * tee_fs_htree_node_image 0  vers 1 @ offs = node_size
166a238b744SJens Wiklander 	 * tee_fs_htree_node_image 1  vers 0 @ offs = node_size * 2
167a238b744SJens Wiklander 	 * tee_fs_htree_node_image 1  vers 1 @ offs = node_size * 3
168a238b744SJens Wiklander 	 * ...
1698c6a8affSwellsleep 	 * tee_fs_htree_node_image 30 vers 0 @ offs = node_size * 60
1708c6a8affSwellsleep 	 * tee_fs_htree_node_image 30 vers 1 @ offs = node_size * 61
171a238b744SJens Wiklander 	 *
172a238b744SJens Wiklander 	 * phys block 2:
173a238b744SJens Wiklander 	 * data block 0 vers 0
174a238b744SJens Wiklander 	 *
175a238b744SJens Wiklander 	 * phys block 3:
176a238b744SJens Wiklander 	 * data block 0 vers 1
177a238b744SJens Wiklander 	 *
178a238b744SJens Wiklander 	 * ...
1798c6a8affSwellsleep 	 * phys block 62:
1808c6a8affSwellsleep 	 * data block 30 vers 0
1818c6a8affSwellsleep 	 *
182a238b744SJens Wiklander 	 * phys block 63:
1838c6a8affSwellsleep 	 * data block 30 vers 1
184a238b744SJens Wiklander 	 *
185a238b744SJens Wiklander 	 * phys block 64:
1868c6a8affSwellsleep 	 * tee_fs_htree_node_image 31  vers 0 @ offs = 0
1878c6a8affSwellsleep 	 * tee_fs_htree_node_image 31  vers 1 @ offs = node_size
1888c6a8affSwellsleep 	 * tee_fs_htree_node_image 32  vers 0 @ offs = node_size * 2
1898c6a8affSwellsleep 	 * tee_fs_htree_node_image 32  vers 1 @ offs = node_size * 3
1908c6a8affSwellsleep 	 * ...
1918c6a8affSwellsleep 	 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 60
1928c6a8affSwellsleep 	 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 61
193a238b744SJens Wiklander 	 *
194a238b744SJens Wiklander 	 * phys block 65:
1958c6a8affSwellsleep 	 * data block 31 vers 0
196a238b744SJens Wiklander 	 *
1978c6a8affSwellsleep 	 * phys block 66:
1988c6a8affSwellsleep 	 * data block 31 vers 1
199a238b744SJens Wiklander 	 * ...
200a238b744SJens Wiklander 	 */
201a238b744SJens Wiklander 
202a238b744SJens Wiklander 	switch (type) {
203a238b744SJens Wiklander 	case TEE_FS_HTREE_TYPE_HEAD:
204a238b744SJens Wiklander 		*offs = sizeof(struct tee_fs_htree_image) * vers;
205a238b744SJens Wiklander 		*size = sizeof(struct tee_fs_htree_image);
206a238b744SJens Wiklander 		return TEE_SUCCESS;
207a238b744SJens Wiklander 	case TEE_FS_HTREE_TYPE_NODE:
208a238b744SJens Wiklander 		pbn = 1 + ((idx / block_nodes) * block_nodes * 2);
209a238b744SJens Wiklander 		*offs = pbn * BLOCK_SIZE +
210a238b744SJens Wiklander 			2 * node_size * (idx % block_nodes) +
211a238b744SJens Wiklander 			node_size * vers;
212a238b744SJens Wiklander 		*size = node_size;
213a238b744SJens Wiklander 		return TEE_SUCCESS;
214a238b744SJens Wiklander 	case TEE_FS_HTREE_TYPE_BLOCK:
215a238b744SJens Wiklander 		bidx = 2 * idx + vers;
216a238b744SJens Wiklander 		pbn = 2 + bidx + bidx / (block_nodes * 2 - 1);
217a238b744SJens Wiklander 		*offs = pbn * BLOCK_SIZE;
218a238b744SJens Wiklander 		*size = BLOCK_SIZE;
219a238b744SJens Wiklander 		return TEE_SUCCESS;
220a238b744SJens Wiklander 	default:
221a238b744SJens Wiklander 		return TEE_ERROR_GENERIC;
222a238b744SJens Wiklander 	}
223a238b744SJens Wiklander }
224a238b744SJens Wiklander 
ree_fs_rpc_read_init(void * aux,struct tee_fs_rpc_operation * op,enum tee_fs_htree_type type,size_t idx,uint8_t vers,void ** data)225a238b744SJens Wiklander static TEE_Result ree_fs_rpc_read_init(void *aux,
226a238b744SJens Wiklander 				       struct tee_fs_rpc_operation *op,
227a238b744SJens Wiklander 				       enum tee_fs_htree_type type, size_t idx,
228a238b744SJens Wiklander 				       uint8_t vers, void **data)
229a238b744SJens Wiklander {
230a238b744SJens Wiklander 	struct tee_fs_fd *fdp = aux;
231a238b744SJens Wiklander 	TEE_Result res;
232a238b744SJens Wiklander 	size_t offs;
233a238b744SJens Wiklander 	size_t size;
234a238b744SJens Wiklander 
235a238b744SJens Wiklander 	res = get_offs_size(type, idx, vers, &offs, &size);
236a238b744SJens Wiklander 	if (res != TEE_SUCCESS)
237a238b744SJens Wiklander 		return res;
238a238b744SJens Wiklander 
2396009538cSJens Wiklander 	return tee_fs_rpc_read_init(op, OPTEE_RPC_CMD_FS, fdp->fd,
240a238b744SJens Wiklander 				    offs, size, data);
241a238b744SJens Wiklander }
242a238b744SJens Wiklander 
ree_fs_rpc_write_init(void * aux,struct tee_fs_rpc_operation * op,enum tee_fs_htree_type type,size_t idx,uint8_t vers,void ** data)243a238b744SJens Wiklander static TEE_Result ree_fs_rpc_write_init(void *aux,
244a238b744SJens Wiklander 					struct tee_fs_rpc_operation *op,
245a238b744SJens Wiklander 					enum tee_fs_htree_type type, size_t idx,
246a238b744SJens Wiklander 					uint8_t vers, void **data)
247a238b744SJens Wiklander {
248a238b744SJens Wiklander 	struct tee_fs_fd *fdp = aux;
249a238b744SJens Wiklander 	TEE_Result res;
250a238b744SJens Wiklander 	size_t offs;
251a238b744SJens Wiklander 	size_t size;
252a238b744SJens Wiklander 
253a238b744SJens Wiklander 	res = get_offs_size(type, idx, vers, &offs, &size);
254a238b744SJens Wiklander 	if (res != TEE_SUCCESS)
255a238b744SJens Wiklander 		return res;
256a238b744SJens Wiklander 
2576009538cSJens Wiklander 	return tee_fs_rpc_write_init(op, OPTEE_RPC_CMD_FS, fdp->fd,
258a238b744SJens Wiklander 				     offs, size, data);
259a238b744SJens Wiklander }
260a238b744SJens Wiklander 
261a238b744SJens Wiklander static const struct tee_fs_htree_storage ree_fs_storage_ops = {
262a238b744SJens Wiklander 	.block_size = BLOCK_SIZE,
263a238b744SJens Wiklander 	.rpc_read_init = ree_fs_rpc_read_init,
26464fa6c0aSJens Wiklander 	.rpc_read_final = tee_fs_rpc_read_final,
265a238b744SJens Wiklander 	.rpc_write_init = ree_fs_rpc_write_init,
26664fa6c0aSJens Wiklander 	.rpc_write_final = tee_fs_rpc_write_final,
267a238b744SJens Wiklander };
268a238b744SJens Wiklander 
ree_fs_ftruncate_internal(struct tee_fs_fd * fdp,tee_fs_off_t new_file_len)269c8016054SJens Wiklander static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
2707c3ebaa8SJerome Forissier 					    tee_fs_off_t new_file_len)
2717c3ebaa8SJerome Forissier {
272c8016054SJens Wiklander 	TEE_Result res;
273a238b744SJens Wiklander 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
2747c3ebaa8SJerome Forissier 
275a238b744SJens Wiklander 	if ((size_t)new_file_len > meta->length) {
276a238b744SJens Wiklander 		size_t ext_len = new_file_len - meta->length;
2777c3ebaa8SJerome Forissier 
278b2284b11SJens Wiklander 		res = out_of_place_write(fdp, meta->length, NULL, NULL,
279b2284b11SJens Wiklander 					 ext_len);
280c8016054SJens Wiklander 		if (res != TEE_SUCCESS)
28106d858d5SJens Wiklander 			return res;
282a238b744SJens Wiklander 	} else {
283a238b744SJens Wiklander 		size_t offs;
284a238b744SJens Wiklander 		size_t sz;
285a238b744SJens Wiklander 
286a238b744SJens Wiklander 		res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
287*04e46975SEtienne Carriere 				    ROUNDUP_DIV(new_file_len, BLOCK_SIZE), 1,
288*04e46975SEtienne Carriere 				    &offs, &sz);
289a238b744SJens Wiklander 		if (res != TEE_SUCCESS)
290a238b744SJens Wiklander 			return res;
291a238b744SJens Wiklander 
292a238b744SJens Wiklander 		res = tee_fs_htree_truncate(&fdp->ht,
293a238b744SJens Wiklander 					    new_file_len / BLOCK_SIZE);
294a238b744SJens Wiklander 		if (res != TEE_SUCCESS)
295a238b744SJens Wiklander 			return res;
296a238b744SJens Wiklander 
2976009538cSJens Wiklander 		res = tee_fs_rpc_truncate(OPTEE_RPC_CMD_FS, fdp->fd,
298a238b744SJens Wiklander 					  offs + sz);
299a238b744SJens Wiklander 		if (res != TEE_SUCCESS)
300a238b744SJens Wiklander 			return res;
301a238b744SJens Wiklander 
302a238b744SJens Wiklander 		meta->length = new_file_len;
30333e4def6SJerome Forissier 		tee_fs_htree_meta_set_dirty(fdp->ht);
3047c3ebaa8SJerome Forissier 	}
3057c3ebaa8SJerome Forissier 
306ac0bab7fSJens Wiklander 	return TEE_SUCCESS;
3077c3ebaa8SJerome Forissier }
3087c3ebaa8SJerome Forissier 
ree_fs_read_primitive(struct tee_file_handle * fh,size_t pos,void * buf_core,void * buf_user,size_t * len)309ac0bab7fSJens Wiklander static TEE_Result ree_fs_read_primitive(struct tee_file_handle *fh, size_t pos,
310b2284b11SJens Wiklander 					void *buf_core, void *buf_user,
311b2284b11SJens Wiklander 					size_t *len)
3127c3ebaa8SJerome Forissier {
313c8016054SJens Wiklander 	TEE_Result res;
3147c3ebaa8SJerome Forissier 	int start_block_num;
3157c3ebaa8SJerome Forissier 	int end_block_num;
316c8016054SJens Wiklander 	size_t remain_bytes;
317b2284b11SJens Wiklander 	uint8_t *data_core_ptr = buf_core;
318b2284b11SJens Wiklander 	uint8_t *data_user_ptr = buf_user;
31906d858d5SJens Wiklander 	uint8_t *block = NULL;
320c8016054SJens Wiklander 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
321a238b744SJens Wiklander 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
32215ace8d3SJerome Forissier 
323b2284b11SJens Wiklander 	/* One of buf_core and buf_user must be NULL */
324b2284b11SJens Wiklander 	assert(!buf_core || !buf_user);
325b2284b11SJens Wiklander 
326c8016054SJens Wiklander 	remain_bytes = *len;
327879237aeSJens Wiklander 	if ((pos + remain_bytes) < remain_bytes || pos > meta->length)
328c8016054SJens Wiklander 		remain_bytes = 0;
329879237aeSJens Wiklander 	else if (pos + remain_bytes > meta->length)
330879237aeSJens Wiklander 		remain_bytes = meta->length - pos;
3317c3ebaa8SJerome Forissier 
332c8016054SJens Wiklander 	*len = remain_bytes;
333c8016054SJens Wiklander 
334c8016054SJens Wiklander 	if (!remain_bytes) {
335c8016054SJens Wiklander 		res = TEE_SUCCESS;
3367c3ebaa8SJerome Forissier 		goto exit;
3377c3ebaa8SJerome Forissier 	}
3387c3ebaa8SJerome Forissier 
339879237aeSJens Wiklander 	start_block_num = pos_to_block_num(pos);
340879237aeSJens Wiklander 	end_block_num = pos_to_block_num(pos + remain_bytes - 1);
3417c3ebaa8SJerome Forissier 
3420e3f6d6bSJens Wiklander 	block = get_tmp_block();
34306d858d5SJens Wiklander 	if (!block) {
34406d858d5SJens Wiklander 		res = TEE_ERROR_OUT_OF_MEMORY;
34506d858d5SJens Wiklander 		goto exit;
34606d858d5SJens Wiklander 	}
34706d858d5SJens Wiklander 
3487c3ebaa8SJerome Forissier 	while (start_block_num <= end_block_num) {
349879237aeSJens Wiklander 		size_t offset = pos % BLOCK_SIZE;
35006d858d5SJens Wiklander 		size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
3517c3ebaa8SJerome Forissier 
35206d858d5SJens Wiklander 		if (size_to_read + offset > BLOCK_SIZE)
35306d858d5SJens Wiklander 			size_to_read = BLOCK_SIZE - offset;
3547c3ebaa8SJerome Forissier 
355a238b744SJens Wiklander 		res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
356a238b744SJens Wiklander 		if (res != TEE_SUCCESS)
3577c3ebaa8SJerome Forissier 			goto exit;
3587c3ebaa8SJerome Forissier 
359b2284b11SJens Wiklander 		if (data_core_ptr) {
360b2284b11SJens Wiklander 			memcpy(data_core_ptr, block + offset, size_to_read);
361b2284b11SJens Wiklander 			data_core_ptr += size_to_read;
362b2284b11SJens Wiklander 		} else if (data_user_ptr) {
363b2284b11SJens Wiklander 			res = copy_to_user(data_user_ptr, block + offset,
364b2284b11SJens Wiklander 					   size_to_read);
365b2284b11SJens Wiklander 			if (res)
366b2284b11SJens Wiklander 				goto exit;
367b2284b11SJens Wiklander 			data_user_ptr += size_to_read;
368b2284b11SJens Wiklander 		}
36906d858d5SJens Wiklander 
3707c3ebaa8SJerome Forissier 		remain_bytes -= size_to_read;
371879237aeSJens Wiklander 		pos += size_to_read;
3727c3ebaa8SJerome Forissier 
3737c3ebaa8SJerome Forissier 		start_block_num++;
3747c3ebaa8SJerome Forissier 	}
375c8016054SJens Wiklander 	res = TEE_SUCCESS;
3767c3ebaa8SJerome Forissier exit:
3770e3f6d6bSJens Wiklander 	if (block)
3780e3f6d6bSJens Wiklander 		put_tmp_block(block);
379c8016054SJens Wiklander 	return res;
3807c3ebaa8SJerome Forissier }
3817c3ebaa8SJerome Forissier 
ree_fs_read(struct tee_file_handle * fh,size_t pos,void * buf_core,void * buf_user,size_t * len)382ac0bab7fSJens Wiklander static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos,
383b2284b11SJens Wiklander 			      void *buf_core, void *buf_user, size_t *len)
384ac0bab7fSJens Wiklander {
385ac0bab7fSJens Wiklander 	TEE_Result res;
386ac0bab7fSJens Wiklander 
387ac0bab7fSJens Wiklander 	mutex_lock(&ree_fs_mutex);
388b2284b11SJens Wiklander 	res = ree_fs_read_primitive(fh, pos, buf_core, buf_user, len);
389ac0bab7fSJens Wiklander 	mutex_unlock(&ree_fs_mutex);
390ac0bab7fSJens Wiklander 
391ac0bab7fSJens Wiklander 	return res;
392ac0bab7fSJens Wiklander }
393ac0bab7fSJens Wiklander 
ree_fs_write_primitive(struct tee_file_handle * fh,size_t pos,const void * buf_core,const void * buf_user,size_t len)39473ea1cdeSJens Wiklander static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos,
395b2284b11SJens Wiklander 					 const void *buf_core,
396b2284b11SJens Wiklander 					 const void *buf_user, size_t len)
3977c3ebaa8SJerome Forissier {
398c8016054SJens Wiklander 	TEE_Result res;
399c8016054SJens Wiklander 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
400233da534SJerome Forissier 	size_t file_size;
401c8016054SJens Wiklander 
402b2284b11SJens Wiklander 	/* One of buf_core and buf_user must be NULL */
403b2284b11SJens Wiklander 	assert(!buf_core || !buf_user);
404b2284b11SJens Wiklander 
405c8016054SJens Wiklander 	if (!len)
406c8016054SJens Wiklander 		return TEE_SUCCESS;
4077c3ebaa8SJerome Forissier 
408a238b744SJens Wiklander 	file_size = tee_fs_htree_get_meta(fdp->ht)->length;
409233da534SJerome Forissier 
41073ea1cdeSJens Wiklander 	if ((pos + len) < len)
41173ea1cdeSJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
4127c3ebaa8SJerome Forissier 
413879237aeSJens Wiklander 	if (file_size < pos) {
414879237aeSJens Wiklander 		res = ree_fs_ftruncate_internal(fdp, pos);
415c8016054SJens Wiklander 		if (res != TEE_SUCCESS)
41673ea1cdeSJens Wiklander 			return res;
4177c3ebaa8SJerome Forissier 	}
4187c3ebaa8SJerome Forissier 
419b2284b11SJens Wiklander 	return out_of_place_write(fdp, pos, buf_core, buf_user, len);
42073ea1cdeSJens Wiklander }
4217c3ebaa8SJerome Forissier 
ree_fs_open_primitive(bool create,uint8_t * hash,uint32_t min_counter,const TEE_UUID * uuid,struct tee_fs_dirfile_fileh * dfh,struct tee_file_handle ** fh)422a4ed7bafSJens Wiklander static TEE_Result ree_fs_open_primitive(bool create, uint8_t *hash,
423623b9bd4SJens Wiklander 					uint32_t min_counter,
424a4ed7bafSJens Wiklander 					const TEE_UUID *uuid,
425ac0bab7fSJens Wiklander 					struct tee_fs_dirfile_fileh *dfh,
42673ea1cdeSJens Wiklander 					struct tee_file_handle **fh)
42773ea1cdeSJens Wiklander {
42873ea1cdeSJens Wiklander 	TEE_Result res;
429ac0bab7fSJens Wiklander 	struct tee_fs_fd *fdp;
43073ea1cdeSJens Wiklander 
43173ea1cdeSJens Wiklander 	fdp = calloc(1, sizeof(struct tee_fs_fd));
43273ea1cdeSJens Wiklander 	if (!fdp)
43373ea1cdeSJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
43473ea1cdeSJens Wiklander 	fdp->fd = -1;
435ac0bab7fSJens Wiklander 	fdp->uuid = uuid;
43673ea1cdeSJens Wiklander 
43773ea1cdeSJens Wiklander 	if (create)
4386009538cSJens Wiklander 		res = tee_fs_rpc_create_dfh(OPTEE_RPC_CMD_FS,
439ac0bab7fSJens Wiklander 					    dfh, &fdp->fd);
44073ea1cdeSJens Wiklander 	else
4416009538cSJens Wiklander 		res = tee_fs_rpc_open_dfh(OPTEE_RPC_CMD_FS, dfh, &fdp->fd);
44273ea1cdeSJens Wiklander 
44373ea1cdeSJens Wiklander 	if (res != TEE_SUCCESS)
44473ea1cdeSJens Wiklander 		goto out;
44573ea1cdeSJens Wiklander 
446623b9bd4SJens Wiklander 	res = tee_fs_htree_open(create, hash, min_counter, uuid,
447623b9bd4SJens Wiklander 				&ree_fs_storage_ops, fdp, &fdp->ht);
44873ea1cdeSJens Wiklander out:
44973ea1cdeSJens Wiklander 	if (res == TEE_SUCCESS) {
450ac0bab7fSJens Wiklander 		if (dfh)
451ac0bab7fSJens Wiklander 			fdp->dfh = *dfh;
452ac0bab7fSJens Wiklander 		else
453ac0bab7fSJens Wiklander 			fdp->dfh.idx = -1;
45473ea1cdeSJens Wiklander 		*fh = (struct tee_file_handle *)fdp;
45573ea1cdeSJens Wiklander 	} else {
4567446af61SJerome Forissier 		if (res == TEE_ERROR_SECURITY)
4577446af61SJerome Forissier 			DMSG("Secure storage corruption detected");
45873ea1cdeSJens Wiklander 		if (fdp->fd != -1)
4596009538cSJens Wiklander 			tee_fs_rpc_close(OPTEE_RPC_CMD_FS, fdp->fd);
46073ea1cdeSJens Wiklander 		if (create)
4616009538cSJens Wiklander 			tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, dfh);
46273ea1cdeSJens Wiklander 		free(fdp);
46373ea1cdeSJens Wiklander 	}
46473ea1cdeSJens Wiklander 
46573ea1cdeSJens Wiklander 	return res;
46673ea1cdeSJens Wiklander }
46773ea1cdeSJens Wiklander 
ree_fs_close_primitive(struct tee_file_handle * fh)468ac0bab7fSJens Wiklander static void ree_fs_close_primitive(struct tee_file_handle *fh)
46973ea1cdeSJens Wiklander {
470ac0bab7fSJens Wiklander 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
47173ea1cdeSJens Wiklander 
47273ea1cdeSJens Wiklander 	if (fdp) {
47373ea1cdeSJens Wiklander 		tee_fs_htree_close(&fdp->ht);
4746009538cSJens Wiklander 		tee_fs_rpc_close(OPTEE_RPC_CMD_FS, fdp->fd);
47573ea1cdeSJens Wiklander 		free(fdp);
47673ea1cdeSJens Wiklander 	}
47773ea1cdeSJens Wiklander }
47873ea1cdeSJens Wiklander 
ree_dirf_commit_writes(struct tee_file_handle * fh,uint8_t * hash,uint32_t * counter)479ac0bab7fSJens Wiklander static TEE_Result ree_dirf_commit_writes(struct tee_file_handle *fh,
480623b9bd4SJens Wiklander 					 uint8_t *hash, uint32_t *counter)
481ac0bab7fSJens Wiklander {
482ac0bab7fSJens Wiklander 	TEE_Result res;
483ac0bab7fSJens Wiklander 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
484ac0bab7fSJens Wiklander 
485623b9bd4SJens Wiklander 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, counter);
486ac0bab7fSJens Wiklander 
487ac0bab7fSJens Wiklander 	if (!res && hash)
488ac0bab7fSJens Wiklander 		memcpy(hash, fdp->dfh.hash, sizeof(fdp->dfh.hash));
489ac0bab7fSJens Wiklander 
490ac0bab7fSJens Wiklander 	return res;
491ac0bab7fSJens Wiklander }
492ac0bab7fSJens Wiklander 
dirf_read(struct tee_file_handle * fh,size_t pos,void * buf,size_t * len)493b2284b11SJens Wiklander static TEE_Result dirf_read(struct tee_file_handle *fh, size_t pos, void *buf,
494b2284b11SJens Wiklander 			    size_t *len)
495b2284b11SJens Wiklander {
496b2284b11SJens Wiklander 	return ree_fs_read_primitive(fh, pos, buf, NULL, len);
497b2284b11SJens Wiklander }
498b2284b11SJens Wiklander 
dirf_write(struct tee_file_handle * fh,size_t pos,const void * buf,size_t len)499b2284b11SJens Wiklander static TEE_Result dirf_write(struct tee_file_handle *fh, size_t pos,
500b2284b11SJens Wiklander 			     const void *buf, size_t len)
501b2284b11SJens Wiklander {
502b2284b11SJens Wiklander 	return ree_fs_write_primitive(fh, pos, buf, NULL, len);
503b2284b11SJens Wiklander }
504b2284b11SJens Wiklander 
505ac0bab7fSJens Wiklander static const struct tee_fs_dirfile_operations ree_dirf_ops = {
506ac0bab7fSJens Wiklander 	.open = ree_fs_open_primitive,
507ac0bab7fSJens Wiklander 	.close = ree_fs_close_primitive,
508b2284b11SJens Wiklander 	.read = dirf_read,
509b2284b11SJens Wiklander 	.write = dirf_write,
510ac0bab7fSJens Wiklander 	.commit_writes = ree_dirf_commit_writes,
511ac0bab7fSJens Wiklander };
512ac0bab7fSJens Wiklander 
5137ae15736SJens Wiklander /*
5147ae15736SJens Wiklander  * ree_fs_dirh is caching the dirfile handle to avoid frequent opening and
5157ae15736SJens Wiklander  * closing of that handle. When ree_fs_dirh_refcount reaches 0, ree_fs_dirh
5167ae15736SJens Wiklander  * will be freed. However, ree_fs_dirh_refcount > 0 is not a guarantee that
5177ae15736SJens Wiklander  * ree_fs_dirh will not be freed, it may very well be freed earlier in an
5187ae15736SJens Wiklander  * error path. get_dirh() must be used to get the ree_fs_dirh pointer each
5197ae15736SJens Wiklander  * time it's needed if ree_fs_mutex has been unlocked in between.
5207ae15736SJens Wiklander  */
521ace6039fSJens Wiklander static struct tee_fs_dirfile_dirh *ree_fs_dirh;
522ace6039fSJens Wiklander static size_t ree_fs_dirh_refcount;
523ace6039fSJens Wiklander 
524f5411aafSJudy Wang #ifdef CFG_REE_FS_INTEGRITY_RPMB
525b4b1a20cSJens Wiklander static struct tee_file_handle *ree_fs_rpmb_fh;
526b4b1a20cSJens Wiklander 
open_dirh(struct tee_fs_dirfile_dirh ** dirh)527b4b1a20cSJens Wiklander static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh)
528b4b1a20cSJens Wiklander {
529b4b1a20cSJens Wiklander 	TEE_Result res;
530b4b1a20cSJens Wiklander 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
531b4b1a20cSJens Wiklander 	uint8_t *hashp = NULL;
532b4b1a20cSJens Wiklander 	const char fname[] = "dirfile.db.hash";
533b4b1a20cSJens Wiklander 
534b4b1a20cSJens Wiklander 	res = tee_rpmb_fs_raw_open(fname, false, &ree_fs_rpmb_fh);
535b4b1a20cSJens Wiklander 	if (!res) {
536b4b1a20cSJens Wiklander 		size_t l = sizeof(hash);
537b4b1a20cSJens Wiklander 
538b2284b11SJens Wiklander 		res = rpmb_fs_ops.read(ree_fs_rpmb_fh, 0, hash, NULL, &l);
539b4b1a20cSJens Wiklander 		if (res)
540b4b1a20cSJens Wiklander 			return res;
541b4b1a20cSJens Wiklander 		if (l == sizeof(hash))
542b4b1a20cSJens Wiklander 			hashp = hash;
543b4b1a20cSJens Wiklander 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
544b4b1a20cSJens Wiklander 		res = tee_rpmb_fs_raw_open(fname, true, &ree_fs_rpmb_fh);
545b4b1a20cSJens Wiklander 	}
546b4b1a20cSJens Wiklander 	if (res)
547b4b1a20cSJens Wiklander 		return res;
548b4b1a20cSJens Wiklander 
549623b9bd4SJens Wiklander 	res = tee_fs_dirfile_open(false, hashp, 0, &ree_dirf_ops, dirh);
550e76fe068SEtienne Carriere 
551300faa62SEtienne Carriere 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
552e76fe068SEtienne Carriere 		if (hashp) {
553e76fe068SEtienne Carriere 			if (IS_ENABLED(CFG_REE_FS_ALLOW_RESET)) {
554e76fe068SEtienne Carriere 				DMSG("dirf.db not found, clear hash in RPMB");
555300faa62SEtienne Carriere 				res = rpmb_fs_ops.truncate(ree_fs_rpmb_fh, 0);
556300faa62SEtienne Carriere 				if (res) {
557e76fe068SEtienne Carriere 					DMSG("Can't clear hash: %#"PRIx32, res);
558e76fe068SEtienne Carriere 					res = TEE_ERROR_SECURITY;
559e76fe068SEtienne Carriere 					goto out;
560e76fe068SEtienne Carriere 				}
561e76fe068SEtienne Carriere 			} else {
562e76fe068SEtienne Carriere 				DMSG("dirf.db file not found");
563300faa62SEtienne Carriere 				res = TEE_ERROR_SECURITY;
564300faa62SEtienne Carriere 				goto out;
565300faa62SEtienne Carriere 			}
566300faa62SEtienne Carriere 		}
567667b10f6SFangsuo Wu 
568623b9bd4SJens Wiklander 		res = tee_fs_dirfile_open(true, NULL, 0, &ree_dirf_ops, dirh);
569300faa62SEtienne Carriere 	}
570300faa62SEtienne Carriere 
571300faa62SEtienne Carriere out:
572b4b1a20cSJens Wiklander 	if (res)
573b4b1a20cSJens Wiklander 		rpmb_fs_ops.close(&ree_fs_rpmb_fh);
574667b10f6SFangsuo Wu 
575b4b1a20cSJens Wiklander 	return res;
576b4b1a20cSJens Wiklander }
577b4b1a20cSJens Wiklander 
commit_dirh_writes(struct tee_fs_dirfile_dirh * dirh)578b4b1a20cSJens Wiklander static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh)
579b4b1a20cSJens Wiklander {
580b4b1a20cSJens Wiklander 	TEE_Result res;
581b4b1a20cSJens Wiklander 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
582b4b1a20cSJens Wiklander 
583623b9bd4SJens Wiklander 	res = tee_fs_dirfile_commit_writes(dirh, hash, NULL);
584b4b1a20cSJens Wiklander 	if (res)
585b4b1a20cSJens Wiklander 		return res;
586b2284b11SJens Wiklander 	return rpmb_fs_ops.write(ree_fs_rpmb_fh, 0, hash, NULL, sizeof(hash));
587b4b1a20cSJens Wiklander }
588b4b1a20cSJens Wiklander 
close_dirh(struct tee_fs_dirfile_dirh ** dirh)589b4b1a20cSJens Wiklander static void close_dirh(struct tee_fs_dirfile_dirh **dirh)
590b4b1a20cSJens Wiklander {
591b4b1a20cSJens Wiklander 	tee_fs_dirfile_close(*dirh);
592b4b1a20cSJens Wiklander 	*dirh = NULL;
593b4b1a20cSJens Wiklander 	rpmb_fs_ops.close(&ree_fs_rpmb_fh);
594b4b1a20cSJens Wiklander }
595b4b1a20cSJens Wiklander 
596f5411aafSJudy Wang #else /*!CFG_REE_FS_INTEGRITY_RPMB*/
open_dirh(struct tee_fs_dirfile_dirh ** dirh)59724f24f84SJens Wiklander static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh)
598ace6039fSJens Wiklander {
599623b9bd4SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
600623b9bd4SJens Wiklander 	uint32_t min_counter = 0;
601667b10f6SFangsuo Wu 
602623b9bd4SJens Wiklander 	res = nv_counter_get_ree_fs(&min_counter);
603623b9bd4SJens Wiklander 	if (res) {
604623b9bd4SJens Wiklander 		static bool once;
605623b9bd4SJens Wiklander 
606623b9bd4SJens Wiklander 		if (res != TEE_ERROR_NOT_IMPLEMENTED ||
6079ea709a7SEtienne Carriere 		    !IS_ENABLED(CFG_INSECURE))
608623b9bd4SJens Wiklander 			return res;
609623b9bd4SJens Wiklander 
610623b9bd4SJens Wiklander 		if (!once) {
611623b9bd4SJens Wiklander 			IMSG("WARNING (insecure configuration): Failed to get monotonic counter for REE FS, using 0");
612623b9bd4SJens Wiklander 			once = true;
613623b9bd4SJens Wiklander 		}
614623b9bd4SJens Wiklander 		min_counter = 0;
615623b9bd4SJens Wiklander 	}
616623b9bd4SJens Wiklander 	res = tee_fs_dirfile_open(false, NULL, min_counter, &ree_dirf_ops,
617623b9bd4SJens Wiklander 				  dirh);
618623b9bd4SJens Wiklander 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
619623b9bd4SJens Wiklander 		if (min_counter) {
620623b9bd4SJens Wiklander 			if (!IS_ENABLED(CFG_REE_FS_ALLOW_RESET)) {
621623b9bd4SJens Wiklander 				DMSG("dirf.db file not found");
622623b9bd4SJens Wiklander 				return TEE_ERROR_SECURITY;
623623b9bd4SJens Wiklander 			}
624623b9bd4SJens Wiklander 			DMSG("dirf.db not found, initializing with a non-zero monotonic counter");
625623b9bd4SJens Wiklander 		}
626623b9bd4SJens Wiklander 		return tee_fs_dirfile_open(true, NULL, min_counter,
627623b9bd4SJens Wiklander 					   &ree_dirf_ops, dirh);
628623b9bd4SJens Wiklander 	}
629667b10f6SFangsuo Wu 
630667b10f6SFangsuo Wu 	return res;
631ace6039fSJens Wiklander }
632ace6039fSJens Wiklander 
commit_dirh_writes(struct tee_fs_dirfile_dirh * dirh)633a4ed7bafSJens Wiklander static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh)
634a4ed7bafSJens Wiklander {
635623b9bd4SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
636623b9bd4SJens Wiklander 	uint32_t counter = 0;
637623b9bd4SJens Wiklander 
638623b9bd4SJens Wiklander 	res = tee_fs_dirfile_commit_writes(dirh, NULL, &counter);
639623b9bd4SJens Wiklander 	if (res)
640623b9bd4SJens Wiklander 		return res;
641623b9bd4SJens Wiklander 	res = nv_counter_incr_ree_fs_to(counter);
6429ea709a7SEtienne Carriere 	if (res == TEE_ERROR_NOT_IMPLEMENTED && IS_ENABLED(CFG_INSECURE)) {
643623b9bd4SJens Wiklander 		static bool once;
644623b9bd4SJens Wiklander 
645623b9bd4SJens Wiklander 		if (!once) {
646623b9bd4SJens Wiklander 			IMSG("WARNING (insecure configuration): Failed to commit dirh counter %"PRIu32, counter);
647623b9bd4SJens Wiklander 			once = true;
648623b9bd4SJens Wiklander 		}
649623b9bd4SJens Wiklander 		return TEE_SUCCESS;
650623b9bd4SJens Wiklander 	}
651623b9bd4SJens Wiklander 	return res;
652a4ed7bafSJens Wiklander }
653a4ed7bafSJens Wiklander 
close_dirh(struct tee_fs_dirfile_dirh ** dirh)65424f24f84SJens Wiklander static void close_dirh(struct tee_fs_dirfile_dirh **dirh)
65524f24f84SJens Wiklander {
65624f24f84SJens Wiklander 	tee_fs_dirfile_close(*dirh);
65724f24f84SJens Wiklander 	*dirh = NULL;
65824f24f84SJens Wiklander }
659f5411aafSJudy Wang #endif /*!CFG_REE_FS_INTEGRITY_RPMB*/
66024f24f84SJens Wiklander 
get_dirh(struct tee_fs_dirfile_dirh ** dirh)66124f24f84SJens Wiklander static TEE_Result get_dirh(struct tee_fs_dirfile_dirh **dirh)
66224f24f84SJens Wiklander {
66324f24f84SJens Wiklander 	if (!ree_fs_dirh) {
66424f24f84SJens Wiklander 		TEE_Result res = open_dirh(&ree_fs_dirh);
66524f24f84SJens Wiklander 
66624f24f84SJens Wiklander 		if (res) {
66724f24f84SJens Wiklander 			*dirh = NULL;
66824f24f84SJens Wiklander 			return res;
66924f24f84SJens Wiklander 		}
67024f24f84SJens Wiklander 	}
67124f24f84SJens Wiklander 	ree_fs_dirh_refcount++;
67224f24f84SJens Wiklander 	assert(ree_fs_dirh);
67324f24f84SJens Wiklander 	assert(ree_fs_dirh_refcount);
67424f24f84SJens Wiklander 	*dirh = ree_fs_dirh;
67524f24f84SJens Wiklander 	return TEE_SUCCESS;
67624f24f84SJens Wiklander }
67724f24f84SJens Wiklander 
put_dirh_primitive(bool close)67824f24f84SJens Wiklander static void put_dirh_primitive(bool close)
679ace6039fSJens Wiklander {
680ace6039fSJens Wiklander 	assert(ree_fs_dirh_refcount);
681ace6039fSJens Wiklander 
682b6568717SJens Wiklander 	/*
683b6568717SJens Wiklander 	 * During the execution of one of the ree_fs_ops ree_fs_dirh is
684b6568717SJens Wiklander 	 * guareteed to be a valid pointer. But when the fop has returned
685b6568717SJens Wiklander 	 * another thread may get an error or something causing that fop
686b6568717SJens Wiklander 	 * to do a put with close=1.
687b6568717SJens Wiklander 	 *
688b6568717SJens Wiklander 	 * For all fops but ree_fs_close() there's a call to get_dirh() to
689b6568717SJens Wiklander 	 * get a new dirh which will open it again if it was closed before.
690b6568717SJens Wiklander 	 * But in the ree_fs_close() case there's no call to get_dirh()
691b6568717SJens Wiklander 	 * only to this function, put_dirh_primitive(), and in this case
692b6568717SJens Wiklander 	 * ree_fs_dirh may actually be NULL.
693b6568717SJens Wiklander 	 */
694ace6039fSJens Wiklander 	ree_fs_dirh_refcount--;
695b6568717SJens Wiklander 	if (ree_fs_dirh && (!ree_fs_dirh_refcount || close))
69624f24f84SJens Wiklander 		close_dirh(&ree_fs_dirh);
697ace6039fSJens Wiklander }
698ace6039fSJens Wiklander 
put_dirh(struct tee_fs_dirfile_dirh * dirh,bool close)69924f24f84SJens Wiklander static void put_dirh(struct tee_fs_dirfile_dirh *dirh, bool close)
700ace6039fSJens Wiklander {
701ace6039fSJens Wiklander 	if (dirh) {
702ace6039fSJens Wiklander 		assert(dirh == ree_fs_dirh);
70324f24f84SJens Wiklander 		put_dirh_primitive(close);
704ace6039fSJens Wiklander 	}
705ace6039fSJens Wiklander }
706ace6039fSJens Wiklander 
ree_fs_open(struct tee_pobj * po,size_t * size,struct tee_file_handle ** fh)707ac0bab7fSJens Wiklander static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size,
708ac0bab7fSJens Wiklander 			      struct tee_file_handle **fh)
709ac0bab7fSJens Wiklander {
710ac0bab7fSJens Wiklander 	TEE_Result res;
711ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
712ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_fileh dfh;
713ac0bab7fSJens Wiklander 
714ac0bab7fSJens Wiklander 	mutex_lock(&ree_fs_mutex);
715ac0bab7fSJens Wiklander 
716ace6039fSJens Wiklander 	res = get_dirh(&dirh);
717ac0bab7fSJens Wiklander 	if (res != TEE_SUCCESS)
718ac0bab7fSJens Wiklander 		goto out;
719ac0bab7fSJens Wiklander 
720fd108c3eSJens Wiklander 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
721fd108c3eSJens Wiklander 				  &dfh);
722ac0bab7fSJens Wiklander 	if (res != TEE_SUCCESS)
723ac0bab7fSJens Wiklander 		goto out;
724ac0bab7fSJens Wiklander 
725623b9bd4SJens Wiklander 	res = ree_fs_open_primitive(false, dfh.hash, 0, &po->uuid, &dfh, fh);
726ac0bab7fSJens Wiklander 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
727ac0bab7fSJens Wiklander 		/*
728ac0bab7fSJens Wiklander 		 * If the object isn't found someone has tampered with it,
729ac0bab7fSJens Wiklander 		 * treat it as corrupt.
730ac0bab7fSJens Wiklander 		 */
731ac0bab7fSJens Wiklander 		res = TEE_ERROR_CORRUPT_OBJECT;
732ac0bab7fSJens Wiklander 	} else if (!res && size) {
733ac0bab7fSJens Wiklander 		struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
734ac0bab7fSJens Wiklander 
735ac0bab7fSJens Wiklander 		*size = tee_fs_htree_get_meta(fdp->ht)->length;
736ac0bab7fSJens Wiklander 	}
737ac0bab7fSJens Wiklander 
738ac0bab7fSJens Wiklander out:
739ace6039fSJens Wiklander 	if (res)
740b1deb157SJens Wiklander 		put_dirh(dirh, true);
741ac0bab7fSJens Wiklander 	mutex_unlock(&ree_fs_mutex);
742ac0bab7fSJens Wiklander 
743ac0bab7fSJens Wiklander 	return res;
744ac0bab7fSJens Wiklander }
745ac0bab7fSJens Wiklander 
set_name(struct tee_fs_dirfile_dirh * dirh,struct tee_fs_fd * fdp,struct tee_pobj * po,bool overwrite)746ac0bab7fSJens Wiklander static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh,
747ac0bab7fSJens Wiklander 			   struct tee_fs_fd *fdp, struct tee_pobj *po,
748ac0bab7fSJens Wiklander 			   bool overwrite)
749ac0bab7fSJens Wiklander {
750ac0bab7fSJens Wiklander 	TEE_Result res;
751ac0bab7fSJens Wiklander 	bool have_old_dfh = false;
752ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 };
753ac0bab7fSJens Wiklander 
754fd108c3eSJens Wiklander 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
755fd108c3eSJens Wiklander 				  &old_dfh);
756ac0bab7fSJens Wiklander 	if (!overwrite && !res)
757ac0bab7fSJens Wiklander 		return TEE_ERROR_ACCESS_CONFLICT;
758ac0bab7fSJens Wiklander 
759ac0bab7fSJens Wiklander 	if (!res)
760ac0bab7fSJens Wiklander 		have_old_dfh = true;
761ac0bab7fSJens Wiklander 
762ac0bab7fSJens Wiklander 	/*
763ac0bab7fSJens Wiklander 	 * If old_dfh wasn't found, the idx will be -1 and
764ac0bab7fSJens Wiklander 	 * tee_fs_dirfile_rename() will allocate a new index.
765ac0bab7fSJens Wiklander 	 */
766ac0bab7fSJens Wiklander 	fdp->dfh.idx = old_dfh.idx;
767ac0bab7fSJens Wiklander 	old_dfh.idx = -1;
768fd108c3eSJens Wiklander 	res = tee_fs_dirfile_rename(dirh, &po->uuid, &fdp->dfh,
769ac0bab7fSJens Wiklander 				    po->obj_id, po->obj_id_len);
770ac0bab7fSJens Wiklander 	if (res)
771ac0bab7fSJens Wiklander 		return res;
772ac0bab7fSJens Wiklander 
773a4ed7bafSJens Wiklander 	res = commit_dirh_writes(dirh);
774ac0bab7fSJens Wiklander 	if (res)
775ac0bab7fSJens Wiklander 		return res;
776ac0bab7fSJens Wiklander 
777ac0bab7fSJens Wiklander 	if (have_old_dfh)
7786009538cSJens Wiklander 		tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &old_dfh);
779ac0bab7fSJens Wiklander 
780ac0bab7fSJens Wiklander 	return TEE_SUCCESS;
781ac0bab7fSJens Wiklander }
782ac0bab7fSJens Wiklander 
ree_fs_close(struct tee_file_handle ** fh)783ac0bab7fSJens Wiklander static void ree_fs_close(struct tee_file_handle **fh)
784ac0bab7fSJens Wiklander {
785ace6039fSJens Wiklander 	if (*fh) {
786ace6039fSJens Wiklander 		mutex_lock(&ree_fs_mutex);
78724f24f84SJens Wiklander 		put_dirh_primitive(false);
788ac0bab7fSJens Wiklander 		ree_fs_close_primitive(*fh);
789ac0bab7fSJens Wiklander 		*fh = NULL;
79045e286b0SVolodymyr Babchuk 		mutex_unlock(&ree_fs_mutex);
79145e286b0SVolodymyr Babchuk 
792ac0bab7fSJens Wiklander 	}
793ace6039fSJens Wiklander }
794ac0bab7fSJens Wiklander 
ree_fs_create(struct tee_pobj * po,bool overwrite,const void * head,size_t head_size,const void * attr,size_t attr_size,const void * data_core,const void * data_user,size_t data_size,struct tee_file_handle ** fh)79573ea1cdeSJens Wiklander static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite,
79673ea1cdeSJens Wiklander 				const void *head, size_t head_size,
79773ea1cdeSJens Wiklander 				const void *attr, size_t attr_size,
798b2284b11SJens Wiklander 				const void *data_core, const void *data_user,
799b2284b11SJens Wiklander 				size_t data_size, struct tee_file_handle **fh)
80073ea1cdeSJens Wiklander {
80173ea1cdeSJens Wiklander 	struct tee_fs_fd *fdp;
802ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
803ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_fileh dfh;
80473ea1cdeSJens Wiklander 	TEE_Result res;
80573ea1cdeSJens Wiklander 	size_t pos = 0;
80673ea1cdeSJens Wiklander 
807b2284b11SJens Wiklander 	/* One of data_core and data_user must be NULL */
808b2284b11SJens Wiklander 	assert(!data_core || !data_user);
809b2284b11SJens Wiklander 
81073ea1cdeSJens Wiklander 	*fh = NULL;
81173ea1cdeSJens Wiklander 	mutex_lock(&ree_fs_mutex);
81273ea1cdeSJens Wiklander 
813ace6039fSJens Wiklander 	res = get_dirh(&dirh);
814ac0bab7fSJens Wiklander 	if (res)
815ac0bab7fSJens Wiklander 		goto out;
816ac0bab7fSJens Wiklander 
817ac0bab7fSJens Wiklander 	res = tee_fs_dirfile_get_tmp(dirh, &dfh);
818ac0bab7fSJens Wiklander 	if (res)
819ac0bab7fSJens Wiklander 		goto out;
820ac0bab7fSJens Wiklander 
821623b9bd4SJens Wiklander 	res = ree_fs_open_primitive(true, dfh.hash, 0, &po->uuid, &dfh, fh);
82273ea1cdeSJens Wiklander 	if (res)
82373ea1cdeSJens Wiklander 		goto out;
82473ea1cdeSJens Wiklander 
82573ea1cdeSJens Wiklander 	if (head && head_size) {
826b2284b11SJens Wiklander 		res = ree_fs_write_primitive(*fh, pos, head, NULL, head_size);
82773ea1cdeSJens Wiklander 		if (res)
82873ea1cdeSJens Wiklander 			goto out;
82973ea1cdeSJens Wiklander 		pos += head_size;
83073ea1cdeSJens Wiklander 	}
83173ea1cdeSJens Wiklander 
83273ea1cdeSJens Wiklander 	if (attr && attr_size) {
833b2284b11SJens Wiklander 		res = ree_fs_write_primitive(*fh, pos, attr, NULL, attr_size);
83473ea1cdeSJens Wiklander 		if (res)
83573ea1cdeSJens Wiklander 			goto out;
83673ea1cdeSJens Wiklander 		pos += attr_size;
83773ea1cdeSJens Wiklander 	}
83873ea1cdeSJens Wiklander 
839b2284b11SJens Wiklander 	if ((data_core || data_user) && data_size) {
840b2284b11SJens Wiklander 		res = ree_fs_write_primitive(*fh, pos, data_core, data_user,
841b2284b11SJens Wiklander 					     data_size);
84273ea1cdeSJens Wiklander 		if (res)
84373ea1cdeSJens Wiklander 			goto out;
84473ea1cdeSJens Wiklander 	}
84573ea1cdeSJens Wiklander 
84673ea1cdeSJens Wiklander 	fdp = (struct tee_fs_fd *)*fh;
847623b9bd4SJens Wiklander 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, NULL);
84873ea1cdeSJens Wiklander 	if (res)
84973ea1cdeSJens Wiklander 		goto out;
85073ea1cdeSJens Wiklander 
851ac0bab7fSJens Wiklander 	res = set_name(dirh, fdp, po, overwrite);
85273ea1cdeSJens Wiklander out:
853ace6039fSJens Wiklander 	if (res) {
85424f24f84SJens Wiklander 		put_dirh(dirh, true);
855ace6039fSJens Wiklander 		if (*fh) {
85658c83eb5SJens Wiklander 			ree_fs_close_primitive(*fh);
85758c83eb5SJens Wiklander 			*fh = NULL;
8586009538cSJens Wiklander 			tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh);
859ac0bab7fSJens Wiklander 		}
860ace6039fSJens Wiklander 	}
861ac0bab7fSJens Wiklander 	mutex_unlock(&ree_fs_mutex);
862ac0bab7fSJens Wiklander 
863ac0bab7fSJens Wiklander 	return res;
86473ea1cdeSJens Wiklander }
86573ea1cdeSJens Wiklander 
ree_fs_write(struct tee_file_handle * fh,size_t pos,const void * buf_core,const void * buf_user,size_t len)866ac0bab7fSJens Wiklander static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos,
867b2284b11SJens Wiklander 			       const void *buf_core, const void *buf_user,
868b2284b11SJens Wiklander 			       size_t len)
869ac0bab7fSJens Wiklander {
870ac0bab7fSJens Wiklander 	TEE_Result res;
871ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
872ac0bab7fSJens Wiklander 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
873ac0bab7fSJens Wiklander 
874b2284b11SJens Wiklander 	/* One of buf_core and buf_user must be NULL */
875b2284b11SJens Wiklander 	assert(!buf_core || !buf_user);
876b2284b11SJens Wiklander 
877ac0bab7fSJens Wiklander 	mutex_lock(&ree_fs_mutex);
878ac0bab7fSJens Wiklander 
879ace6039fSJens Wiklander 	res = get_dirh(&dirh);
880ac0bab7fSJens Wiklander 	if (res)
881ac0bab7fSJens Wiklander 		goto out;
882ac0bab7fSJens Wiklander 
883b2284b11SJens Wiklander 	res = ree_fs_write_primitive(fh, pos, buf_core, buf_user, len);
884ac0bab7fSJens Wiklander 	if (res)
885ac0bab7fSJens Wiklander 		goto out;
886ac0bab7fSJens Wiklander 
887623b9bd4SJens Wiklander 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, NULL);
888ac0bab7fSJens Wiklander 	if (res)
889ac0bab7fSJens Wiklander 		goto out;
890ac0bab7fSJens Wiklander 
891ac0bab7fSJens Wiklander 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
892ac0bab7fSJens Wiklander 	if (res)
893ac0bab7fSJens Wiklander 		goto out;
894a4ed7bafSJens Wiklander 	res = commit_dirh_writes(dirh);
895ac0bab7fSJens Wiklander out:
89624f24f84SJens Wiklander 	put_dirh(dirh, res);
89773ea1cdeSJens Wiklander 	mutex_unlock(&ree_fs_mutex);
89873ea1cdeSJens Wiklander 
899c8016054SJens Wiklander 	return res;
9007c3ebaa8SJerome Forissier }
9017c3ebaa8SJerome Forissier 
ree_fs_rename(struct tee_pobj * old,struct tee_pobj * new,bool overwrite)902b2215adfSJens Wiklander static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new,
903822203a8SJens Wiklander 				bool overwrite)
90415ace8d3SJerome Forissier {
905c8016054SJens Wiklander 	TEE_Result res;
906ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
907ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_fileh dfh;
908ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 };
909ac0bab7fSJens Wiklander 
910ac0bab7fSJens Wiklander 	if (!new)
911ac0bab7fSJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
91215ace8d3SJerome Forissier 
91315ace8d3SJerome Forissier 	mutex_lock(&ree_fs_mutex);
914ace6039fSJens Wiklander 	res = get_dirh(&dirh);
915ac0bab7fSJens Wiklander 	if (res)
916ac0bab7fSJens Wiklander 		goto out;
917ac0bab7fSJens Wiklander 
918fd108c3eSJens Wiklander 	res = tee_fs_dirfile_find(dirh, &new->uuid, new->obj_id,
919fd108c3eSJens Wiklander 				  new->obj_id_len, &remove_dfh);
920ac0bab7fSJens Wiklander 	if (!res && !overwrite) {
921ac0bab7fSJens Wiklander 		res = TEE_ERROR_ACCESS_CONFLICT;
922ac0bab7fSJens Wiklander 		goto out;
923ac0bab7fSJens Wiklander 	}
924ac0bab7fSJens Wiklander 
925fd108c3eSJens Wiklander 	res = tee_fs_dirfile_find(dirh, &old->uuid, old->obj_id,
926fd108c3eSJens Wiklander 				  old->obj_id_len, &dfh);
927ac0bab7fSJens Wiklander 	if (res)
928ac0bab7fSJens Wiklander 		goto out;
929ac0bab7fSJens Wiklander 
930fd108c3eSJens Wiklander 	res = tee_fs_dirfile_rename(dirh, &new->uuid, &dfh, new->obj_id,
931fd108c3eSJens Wiklander 				    new->obj_id_len);
932ac0bab7fSJens Wiklander 	if (res)
933ac0bab7fSJens Wiklander 		goto out;
934ac0bab7fSJens Wiklander 
935ac0bab7fSJens Wiklander 	if (remove_dfh.idx != -1) {
936ac0bab7fSJens Wiklander 		res = tee_fs_dirfile_remove(dirh, &remove_dfh);
937ac0bab7fSJens Wiklander 		if (res)
938ac0bab7fSJens Wiklander 			goto out;
939ac0bab7fSJens Wiklander 	}
940ac0bab7fSJens Wiklander 
941a4ed7bafSJens Wiklander 	res = commit_dirh_writes(dirh);
942ac0bab7fSJens Wiklander 	if (res)
943ac0bab7fSJens Wiklander 		goto out;
944ac0bab7fSJens Wiklander 
945ac0bab7fSJens Wiklander 	if (remove_dfh.idx != -1)
9466009538cSJens Wiklander 		tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &remove_dfh);
947ac0bab7fSJens Wiklander 
948ac0bab7fSJens Wiklander out:
94924f24f84SJens Wiklander 	put_dirh(dirh, res);
95015ace8d3SJerome Forissier 	mutex_unlock(&ree_fs_mutex);
95115ace8d3SJerome Forissier 
95215ace8d3SJerome Forissier 	return res;
953ac0bab7fSJens Wiklander 
95415ace8d3SJerome Forissier }
95515ace8d3SJerome Forissier 
ree_fs_remove(struct tee_pobj * po)956b2215adfSJens Wiklander static TEE_Result ree_fs_remove(struct tee_pobj *po)
9577c3ebaa8SJerome Forissier {
958c8016054SJens Wiklander 	TEE_Result res;
959ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
960ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_fileh dfh;
9617c3ebaa8SJerome Forissier 
96215ace8d3SJerome Forissier 	mutex_lock(&ree_fs_mutex);
963ace6039fSJens Wiklander 	res = get_dirh(&dirh);
964ac0bab7fSJens Wiklander 	if (res)
965ac0bab7fSJens Wiklander 		goto out;
966ac0bab7fSJens Wiklander 
967fd108c3eSJens Wiklander 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
968fd108c3eSJens Wiklander 				  &dfh);
969ac0bab7fSJens Wiklander 	if (res)
970ac0bab7fSJens Wiklander 		goto out;
971ac0bab7fSJens Wiklander 
972ac0bab7fSJens Wiklander 	res = tee_fs_dirfile_remove(dirh, &dfh);
973ac0bab7fSJens Wiklander 	if (res)
974ac0bab7fSJens Wiklander 		goto out;
975ac0bab7fSJens Wiklander 
976a4ed7bafSJens Wiklander 	res = commit_dirh_writes(dirh);
977ac0bab7fSJens Wiklander 	if (res)
978ac0bab7fSJens Wiklander 		goto out;
979ac0bab7fSJens Wiklander 
9806009538cSJens Wiklander 	tee_fs_rpc_remove_dfh(OPTEE_RPC_CMD_FS, &dfh);
981ac0bab7fSJens Wiklander 
982fd108c3eSJens Wiklander 	assert(tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
983fd108c3eSJens Wiklander 				   &dfh));
984ac0bab7fSJens Wiklander out:
98524f24f84SJens Wiklander 	put_dirh(dirh, res);
98615ace8d3SJerome Forissier 	mutex_unlock(&ree_fs_mutex);
987361fb3e3SJens Wiklander 
9887c3ebaa8SJerome Forissier 	return res;
9897c3ebaa8SJerome Forissier }
9907c3ebaa8SJerome Forissier 
ree_fs_truncate(struct tee_file_handle * fh,size_t len)991c8016054SJens Wiklander static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
9927c3ebaa8SJerome Forissier {
993c8016054SJens Wiklander 	TEE_Result res;
994ac0bab7fSJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
995c8016054SJens Wiklander 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
9967c3ebaa8SJerome Forissier 
99715ace8d3SJerome Forissier 	mutex_lock(&ree_fs_mutex);
998ac0bab7fSJens Wiklander 
999ace6039fSJens Wiklander 	res = get_dirh(&dirh);
1000e1c98967SJerome Forissier 	if (res)
1001ac0bab7fSJens Wiklander 		goto out;
1002ac0bab7fSJens Wiklander 
1003c8016054SJens Wiklander 	res = ree_fs_ftruncate_internal(fdp, len);
1004e1c98967SJerome Forissier 	if (res)
1005ac0bab7fSJens Wiklander 		goto out;
1006ac0bab7fSJens Wiklander 
1007623b9bd4SJens Wiklander 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash, NULL);
1008e1c98967SJerome Forissier 	if (res)
1009ac0bab7fSJens Wiklander 		goto out;
1010ac0bab7fSJens Wiklander 
1011ac0bab7fSJens Wiklander 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
1012bf071c7aSJens Wiklander 	if (res)
1013bf071c7aSJens Wiklander 		goto out;
1014bf071c7aSJens Wiklander 	res = commit_dirh_writes(dirh);
1015ac0bab7fSJens Wiklander out:
101624f24f84SJens Wiklander 	put_dirh(dirh, res);
1017ac0bab7fSJens Wiklander 	mutex_unlock(&ree_fs_mutex);
1018ac0bab7fSJens Wiklander 
1019ac0bab7fSJens Wiklander 	return res;
1020ac0bab7fSJens Wiklander }
1021ac0bab7fSJens Wiklander 
ree_fs_opendir_rpc(const TEE_UUID * uuid,struct tee_fs_dir ** dir)1022ac0bab7fSJens Wiklander static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid,
1023ac0bab7fSJens Wiklander 				     struct tee_fs_dir **dir)
1024ac0bab7fSJens Wiklander 
1025ac0bab7fSJens Wiklander {
10267ae15736SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
10277ae15736SJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
1028ac0bab7fSJens Wiklander 	struct tee_fs_dir *d = calloc(1, sizeof(*d));
1029ac0bab7fSJens Wiklander 
1030ac0bab7fSJens Wiklander 	if (!d)
1031ac0bab7fSJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
1032ac0bab7fSJens Wiklander 
1033fd108c3eSJens Wiklander 	d->uuid = uuid;
1034fd108c3eSJens Wiklander 
1035ac0bab7fSJens Wiklander 	mutex_lock(&ree_fs_mutex);
1036ac0bab7fSJens Wiklander 
10377ae15736SJens Wiklander 	res = get_dirh(&dirh);
1038ac0bab7fSJens Wiklander 	if (res)
1039ac0bab7fSJens Wiklander 		goto out;
1040ac0bab7fSJens Wiklander 
1041ac0bab7fSJens Wiklander 	/* See that there's at least one file */
1042ac0bab7fSJens Wiklander 	d->idx = -1;
1043ac0bab7fSJens Wiklander 	d->d.oidlen = sizeof(d->d.oid);
10447ae15736SJens Wiklander 	res = tee_fs_dirfile_get_next(dirh, d->uuid, &d->idx, d->d.oid,
1045fd108c3eSJens Wiklander 				      &d->d.oidlen);
1046ac0bab7fSJens Wiklander 	d->idx = -1;
1047ac0bab7fSJens Wiklander 
1048ac0bab7fSJens Wiklander out:
1049ac0bab7fSJens Wiklander 	if (!res) {
1050ac0bab7fSJens Wiklander 		*dir = d;
1051ac0bab7fSJens Wiklander 	} else {
1052ac0bab7fSJens Wiklander 		if (d)
10537ae15736SJens Wiklander 			put_dirh(dirh, false);
1054ac0bab7fSJens Wiklander 		free(d);
1055ac0bab7fSJens Wiklander 	}
1056ac0bab7fSJens Wiklander 	mutex_unlock(&ree_fs_mutex);
1057ac0bab7fSJens Wiklander 
1058ac0bab7fSJens Wiklander 	return res;
1059ac0bab7fSJens Wiklander }
1060ac0bab7fSJens Wiklander 
ree_fs_closedir_rpc(struct tee_fs_dir * d)1061ac0bab7fSJens Wiklander static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
1062ac0bab7fSJens Wiklander {
1063ac0bab7fSJens Wiklander 	if (d) {
1064ac0bab7fSJens Wiklander 		mutex_lock(&ree_fs_mutex);
1065ac0bab7fSJens Wiklander 
10667ae15736SJens Wiklander 		put_dirh(ree_fs_dirh, false);
1067ac0bab7fSJens Wiklander 		free(d);
1068ac0bab7fSJens Wiklander 
1069ac0bab7fSJens Wiklander 		mutex_unlock(&ree_fs_mutex);
1070ac0bab7fSJens Wiklander 	}
1071ac0bab7fSJens Wiklander }
1072ac0bab7fSJens Wiklander 
ree_fs_readdir_rpc(struct tee_fs_dir * d,struct tee_fs_dirent ** ent)1073ac0bab7fSJens Wiklander static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
1074ac0bab7fSJens Wiklander 				     struct tee_fs_dirent **ent)
1075ac0bab7fSJens Wiklander {
10767ae15736SJens Wiklander 	struct tee_fs_dirfile_dirh *dirh = NULL;
10777ae15736SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
1078ac0bab7fSJens Wiklander 
1079ac0bab7fSJens Wiklander 	mutex_lock(&ree_fs_mutex);
1080ac0bab7fSJens Wiklander 
10817ae15736SJens Wiklander 	res = get_dirh(&dirh);
10827ae15736SJens Wiklander 	if (res)
10837ae15736SJens Wiklander 		goto out;
10847ae15736SJens Wiklander 
1085ac0bab7fSJens Wiklander 	d->d.oidlen = sizeof(d->d.oid);
10867ae15736SJens Wiklander 	res = tee_fs_dirfile_get_next(dirh, d->uuid, &d->idx, d->d.oid,
1087fd108c3eSJens Wiklander 				      &d->d.oidlen);
1088ac0bab7fSJens Wiklander 	if (res == TEE_SUCCESS)
1089ac0bab7fSJens Wiklander 		*ent = &d->d;
1090ac0bab7fSJens Wiklander 
10917ae15736SJens Wiklander 	put_dirh(dirh, res);
10927ae15736SJens Wiklander out:
109315ace8d3SJerome Forissier 	mutex_unlock(&ree_fs_mutex);
109415ace8d3SJerome Forissier 
109515ace8d3SJerome Forissier 	return res;
10967c3ebaa8SJerome Forissier }
10977c3ebaa8SJerome Forissier 
1098b44708c1SJerome Forissier const struct tee_file_operations ree_fs_ops = {
1099b0311ad8SJens Wiklander 	.open = ree_fs_open,
1100b0311ad8SJens Wiklander 	.create = ree_fs_create,
1101b0311ad8SJens Wiklander 	.close = ree_fs_close,
1102b0311ad8SJens Wiklander 	.read = ree_fs_read,
1103b0311ad8SJens Wiklander 	.write = ree_fs_write,
1104b0311ad8SJens Wiklander 	.truncate = ree_fs_truncate,
1105b0311ad8SJens Wiklander 	.rename = ree_fs_rename,
1106b0311ad8SJens Wiklander 	.remove = ree_fs_remove,
1107b0311ad8SJens Wiklander 	.opendir = ree_fs_opendir_rpc,
1108b0311ad8SJens Wiklander 	.closedir = ree_fs_closedir_rpc,
1109b0311ad8SJens Wiklander 	.readdir = ree_fs_readdir_rpc,
11107c3ebaa8SJerome Forissier };
1111