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