xref: /optee_os/core/tee/tee_ree_fs.c (revision baa999cd61495093ce1e9c43251e655b3a14da67)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <kernel/mutex.h>
8 #include <kernel/panic.h>
9 #include <kernel/thread.h>
10 #include <mm/core_memprot.h>
11 #include <optee_msg_supplicant.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string_ext.h>
15 #include <string.h>
16 #include <sys/queue.h>
17 #include <tee/fs_dirfile.h>
18 #include <tee/fs_htree.h>
19 #include <tee/tee_fs.h>
20 #include <tee/tee_fs_rpc.h>
21 #include <tee/tee_pobj.h>
22 #include <trace.h>
23 #include <utee_defines.h>
24 #include <util.h>
25 
26 #define BLOCK_SHIFT	12
27 
28 #define BLOCK_SIZE	(1 << BLOCK_SHIFT)
29 
30 struct tee_fs_fd {
31 	struct tee_fs_htree *ht;
32 	int fd;
33 	struct tee_fs_dirfile_fileh dfh;
34 	const TEE_UUID *uuid;
35 };
36 
37 struct tee_fs_dir {
38 	struct tee_fs_dirfile_dirh *dirh;
39 	int idx;
40 	struct tee_fs_dirent d;
41 	const TEE_UUID *uuid;
42 };
43 
44 static int pos_to_block_num(int position)
45 {
46 	return position >> BLOCK_SHIFT;
47 }
48 
49 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
50 
51 
52 
53 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos,
54 				     const void *buf, size_t len)
55 {
56 	TEE_Result res;
57 	size_t start_block_num = pos_to_block_num(pos);
58 	size_t end_block_num = pos_to_block_num(pos + len - 1);
59 	size_t remain_bytes = len;
60 	uint8_t *data_ptr = (uint8_t *)buf;
61 	uint8_t *block;
62 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
63 
64 	block = malloc(BLOCK_SIZE);
65 	if (!block)
66 		return TEE_ERROR_OUT_OF_MEMORY;
67 
68 	while (start_block_num <= end_block_num) {
69 		size_t offset = pos % BLOCK_SIZE;
70 		size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
71 
72 		if (size_to_write + offset > BLOCK_SIZE)
73 			size_to_write = BLOCK_SIZE - offset;
74 
75 		if (start_block_num * BLOCK_SIZE <
76 		    ROUNDUP(meta->length, BLOCK_SIZE)) {
77 			res = tee_fs_htree_read_block(&fdp->ht,
78 						      start_block_num, block);
79 			if (res != TEE_SUCCESS)
80 				goto exit;
81 		} else {
82 			memset(block, 0, BLOCK_SIZE);
83 		}
84 
85 		if (data_ptr)
86 			memcpy(block + offset, data_ptr, size_to_write);
87 		else
88 			memset(block + offset, 0, size_to_write);
89 
90 		res = tee_fs_htree_write_block(&fdp->ht, start_block_num,
91 					       block);
92 		if (res != TEE_SUCCESS)
93 			goto exit;
94 
95 		if (data_ptr)
96 			data_ptr += size_to_write;
97 		remain_bytes -= size_to_write;
98 		start_block_num++;
99 		pos += size_to_write;
100 	}
101 
102 	if (pos > meta->length)
103 		meta->length = pos;
104 
105 exit:
106 	free(block);
107 	return res;
108 }
109 
110 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
111 				uint8_t vers, size_t *offs, size_t *size)
112 {
113 	const size_t node_size = sizeof(struct tee_fs_htree_node_image);
114 	const size_t block_nodes = BLOCK_SIZE / (node_size * 2);
115 	size_t pbn;
116 	size_t bidx;
117 
118 	assert(vers == 0 || vers == 1);
119 
120 	/*
121 	 * File layout
122 	 * [demo with input:
123 	 * BLOCK_SIZE = 4096,
124 	 * node_size = 66,
125 	 * block_nodes = 4096/(66*2) = 31 ]
126 	 *
127 	 * phys block 0:
128 	 * tee_fs_htree_image vers 0 @ offs = 0
129 	 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image)
130 	 *
131 	 * phys block 1:
132 	 * tee_fs_htree_node_image 0  vers 0 @ offs = 0
133 	 * tee_fs_htree_node_image 0  vers 1 @ offs = node_size
134 	 * tee_fs_htree_node_image 1  vers 0 @ offs = node_size * 2
135 	 * tee_fs_htree_node_image 1  vers 1 @ offs = node_size * 3
136 	 * ...
137 	 * tee_fs_htree_node_image 30 vers 0 @ offs = node_size * 60
138 	 * tee_fs_htree_node_image 30 vers 1 @ offs = node_size * 61
139 	 *
140 	 * phys block 2:
141 	 * data block 0 vers 0
142 	 *
143 	 * phys block 3:
144 	 * data block 0 vers 1
145 	 *
146 	 * ...
147 	 * phys block 62:
148 	 * data block 30 vers 0
149 	 *
150 	 * phys block 63:
151 	 * data block 30 vers 1
152 	 *
153 	 * phys block 64:
154 	 * tee_fs_htree_node_image 31  vers 0 @ offs = 0
155 	 * tee_fs_htree_node_image 31  vers 1 @ offs = node_size
156 	 * tee_fs_htree_node_image 32  vers 0 @ offs = node_size * 2
157 	 * tee_fs_htree_node_image 32  vers 1 @ offs = node_size * 3
158 	 * ...
159 	 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 60
160 	 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 61
161 	 *
162 	 * phys block 65:
163 	 * data block 31 vers 0
164 	 *
165 	 * phys block 66:
166 	 * data block 31 vers 1
167 	 * ...
168 	 */
169 
170 	switch (type) {
171 	case TEE_FS_HTREE_TYPE_HEAD:
172 		*offs = sizeof(struct tee_fs_htree_image) * vers;
173 		*size = sizeof(struct tee_fs_htree_image);
174 		return TEE_SUCCESS;
175 	case TEE_FS_HTREE_TYPE_NODE:
176 		pbn = 1 + ((idx / block_nodes) * block_nodes * 2);
177 		*offs = pbn * BLOCK_SIZE +
178 			2 * node_size * (idx % block_nodes) +
179 			node_size * vers;
180 		*size = node_size;
181 		return TEE_SUCCESS;
182 	case TEE_FS_HTREE_TYPE_BLOCK:
183 		bidx = 2 * idx + vers;
184 		pbn = 2 + bidx + bidx / (block_nodes * 2 - 1);
185 		*offs = pbn * BLOCK_SIZE;
186 		*size = BLOCK_SIZE;
187 		return TEE_SUCCESS;
188 	default:
189 		return TEE_ERROR_GENERIC;
190 	}
191 }
192 
193 static TEE_Result ree_fs_rpc_read_init(void *aux,
194 				       struct tee_fs_rpc_operation *op,
195 				       enum tee_fs_htree_type type, size_t idx,
196 				       uint8_t vers, void **data)
197 {
198 	struct tee_fs_fd *fdp = aux;
199 	TEE_Result res;
200 	size_t offs;
201 	size_t size;
202 
203 	res = get_offs_size(type, idx, vers, &offs, &size);
204 	if (res != TEE_SUCCESS)
205 		return res;
206 
207 	return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
208 				    offs, size, data);
209 }
210 
211 static TEE_Result ree_fs_rpc_write_init(void *aux,
212 					struct tee_fs_rpc_operation *op,
213 					enum tee_fs_htree_type type, size_t idx,
214 					uint8_t vers, void **data)
215 {
216 	struct tee_fs_fd *fdp = aux;
217 	TEE_Result res;
218 	size_t offs;
219 	size_t size;
220 
221 	res = get_offs_size(type, idx, vers, &offs, &size);
222 	if (res != TEE_SUCCESS)
223 		return res;
224 
225 	return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
226 				     offs, size, data);
227 }
228 
229 static const struct tee_fs_htree_storage ree_fs_storage_ops = {
230 	.block_size = BLOCK_SIZE,
231 	.rpc_read_init = ree_fs_rpc_read_init,
232 	.rpc_read_final = tee_fs_rpc_read_final,
233 	.rpc_write_init = ree_fs_rpc_write_init,
234 	.rpc_write_final = tee_fs_rpc_write_final,
235 };
236 
237 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
238 					    tee_fs_off_t new_file_len)
239 {
240 	TEE_Result res;
241 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
242 
243 	if ((size_t)new_file_len > meta->length) {
244 		size_t ext_len = new_file_len - meta->length;
245 
246 		res = out_of_place_write(fdp, meta->length, NULL, ext_len);
247 		if (res != TEE_SUCCESS)
248 			return res;
249 	} else {
250 		size_t offs;
251 		size_t sz;
252 
253 		res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
254 				    ROUNDUP(new_file_len, BLOCK_SIZE) /
255 					BLOCK_SIZE, 1, &offs, &sz);
256 		if (res != TEE_SUCCESS)
257 			return res;
258 
259 		res = tee_fs_htree_truncate(&fdp->ht,
260 					    new_file_len / BLOCK_SIZE);
261 		if (res != TEE_SUCCESS)
262 			return res;
263 
264 		res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd,
265 					  offs + sz);
266 		if (res != TEE_SUCCESS)
267 			return res;
268 
269 		meta->length = new_file_len;
270 	}
271 
272 	return TEE_SUCCESS;
273 }
274 
275 static TEE_Result ree_fs_read_primitive(struct tee_file_handle *fh, size_t pos,
276 					void *buf, size_t *len)
277 {
278 	TEE_Result res;
279 	int start_block_num;
280 	int end_block_num;
281 	size_t remain_bytes;
282 	uint8_t *data_ptr = buf;
283 	uint8_t *block = NULL;
284 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
285 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
286 
287 	remain_bytes = *len;
288 	if ((pos + remain_bytes) < remain_bytes || pos > meta->length)
289 		remain_bytes = 0;
290 	else if (pos + remain_bytes > meta->length)
291 		remain_bytes = meta->length - pos;
292 
293 	*len = remain_bytes;
294 
295 	if (!remain_bytes) {
296 		res = TEE_SUCCESS;
297 		goto exit;
298 	}
299 
300 	start_block_num = pos_to_block_num(pos);
301 	end_block_num = pos_to_block_num(pos + remain_bytes - 1);
302 
303 	block = malloc(BLOCK_SIZE);
304 	if (!block) {
305 		res = TEE_ERROR_OUT_OF_MEMORY;
306 		goto exit;
307 	}
308 
309 	while (start_block_num <= end_block_num) {
310 		size_t offset = pos % BLOCK_SIZE;
311 		size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
312 
313 		if (size_to_read + offset > BLOCK_SIZE)
314 			size_to_read = BLOCK_SIZE - offset;
315 
316 		res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
317 		if (res != TEE_SUCCESS)
318 			goto exit;
319 
320 		memcpy(data_ptr, block + offset, size_to_read);
321 
322 		data_ptr += size_to_read;
323 		remain_bytes -= size_to_read;
324 		pos += size_to_read;
325 
326 		start_block_num++;
327 	}
328 	res = TEE_SUCCESS;
329 exit:
330 	free(block);
331 	return res;
332 }
333 
334 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos,
335 			      void *buf, size_t *len)
336 {
337 	TEE_Result res;
338 
339 	mutex_lock(&ree_fs_mutex);
340 	res = ree_fs_read_primitive(fh, pos, buf, len);
341 	mutex_unlock(&ree_fs_mutex);
342 
343 	return res;
344 }
345 
346 static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos,
347 					 const void *buf, size_t len)
348 {
349 	TEE_Result res;
350 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
351 	size_t file_size;
352 
353 	if (!len)
354 		return TEE_SUCCESS;
355 
356 	file_size = tee_fs_htree_get_meta(fdp->ht)->length;
357 
358 	if ((pos + len) < len)
359 		return TEE_ERROR_BAD_PARAMETERS;
360 
361 	if (file_size < pos) {
362 		res = ree_fs_ftruncate_internal(fdp, pos);
363 		if (res != TEE_SUCCESS)
364 			return res;
365 	}
366 
367 	return out_of_place_write(fdp, pos, buf, len);
368 }
369 
370 static TEE_Result ree_fs_open_primitive(bool create, uint8_t *hash,
371 					const TEE_UUID *uuid,
372 					struct tee_fs_dirfile_fileh *dfh,
373 					struct tee_file_handle **fh)
374 {
375 	TEE_Result res;
376 	struct tee_fs_fd *fdp;
377 
378 	fdp = calloc(1, sizeof(struct tee_fs_fd));
379 	if (!fdp)
380 		return TEE_ERROR_OUT_OF_MEMORY;
381 	fdp->fd = -1;
382 	fdp->uuid = uuid;
383 
384 	if (create)
385 		res = tee_fs_rpc_create_dfh(OPTEE_MSG_RPC_CMD_FS,
386 					    dfh, &fdp->fd);
387 	else
388 		res = tee_fs_rpc_open_dfh(OPTEE_MSG_RPC_CMD_FS, dfh, &fdp->fd);
389 
390 	if (res != TEE_SUCCESS)
391 		goto out;
392 
393 	res = tee_fs_htree_open(create, hash, uuid, &ree_fs_storage_ops,
394 				fdp, &fdp->ht);
395 out:
396 	if (res == TEE_SUCCESS) {
397 		if (dfh)
398 			fdp->dfh = *dfh;
399 		else
400 			fdp->dfh.idx = -1;
401 		*fh = (struct tee_file_handle *)fdp;
402 	} else {
403 		if (fdp->fd != -1)
404 			tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
405 		if (create)
406 			tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, dfh);
407 		free(fdp);
408 	}
409 
410 	return res;
411 }
412 
413 static void ree_fs_close_primitive(struct tee_file_handle *fh)
414 {
415 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
416 
417 	if (fdp) {
418 		tee_fs_htree_close(&fdp->ht);
419 		tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
420 		free(fdp);
421 	}
422 }
423 
424 static TEE_Result ree_dirf_commit_writes(struct tee_file_handle *fh,
425 					 uint8_t *hash)
426 {
427 	TEE_Result res;
428 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
429 
430 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
431 
432 	if (!res && hash)
433 		memcpy(hash, fdp->dfh.hash, sizeof(fdp->dfh.hash));
434 
435 	return res;
436 }
437 
438 static const struct tee_fs_dirfile_operations ree_dirf_ops = {
439 	.open = ree_fs_open_primitive,
440 	.close = ree_fs_close_primitive,
441 	.read = ree_fs_read_primitive,
442 	.write = ree_fs_write_primitive,
443 	.commit_writes = ree_dirf_commit_writes,
444 };
445 
446 static struct tee_fs_dirfile_dirh *ree_fs_dirh;
447 static size_t ree_fs_dirh_refcount;
448 
449 #ifdef CFG_RPMB_FS
450 static struct tee_file_handle *ree_fs_rpmb_fh;
451 
452 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh)
453 {
454 	TEE_Result res;
455 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
456 	uint8_t *hashp = NULL;
457 	const char fname[] = "dirfile.db.hash";
458 
459 	res = tee_rpmb_fs_raw_open(fname, false, &ree_fs_rpmb_fh);
460 	if (!res) {
461 		size_t l = sizeof(hash);
462 
463 		res = rpmb_fs_ops.read(ree_fs_rpmb_fh, 0, hash, &l);
464 		if (res)
465 			return res;
466 		if (l == sizeof(hash))
467 			hashp = hash;
468 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
469 		res = tee_rpmb_fs_raw_open(fname, true, &ree_fs_rpmb_fh);
470 	}
471 	if (res)
472 		return res;
473 
474 	if (!tee_fs_dirfile_open(false, hashp, &ree_dirf_ops, dirh))
475 		return TEE_SUCCESS;
476 
477 	res = tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh);
478 	if (res)
479 		rpmb_fs_ops.close(&ree_fs_rpmb_fh);
480 	return res;
481 }
482 
483 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh)
484 {
485 	TEE_Result res;
486 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
487 
488 	res = tee_fs_dirfile_commit_writes(dirh, hash);
489 	if (res)
490 		return res;
491 	return rpmb_fs_ops.write(ree_fs_rpmb_fh, 0, hash, sizeof(hash));
492 }
493 
494 static void close_dirh(struct tee_fs_dirfile_dirh **dirh)
495 {
496 	tee_fs_dirfile_close(*dirh);
497 	*dirh = NULL;
498 	rpmb_fs_ops.close(&ree_fs_rpmb_fh);
499 }
500 
501 #else /*!CFG_RPMB_FS*/
502 static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh)
503 {
504 	if (!tee_fs_dirfile_open(false, NULL, &ree_dirf_ops, dirh))
505 		return TEE_SUCCESS;
506 	return tee_fs_dirfile_open(true, NULL, &ree_dirf_ops, dirh);
507 }
508 
509 static TEE_Result commit_dirh_writes(struct tee_fs_dirfile_dirh *dirh)
510 {
511 	return tee_fs_dirfile_commit_writes(dirh, NULL);
512 }
513 
514 static void close_dirh(struct tee_fs_dirfile_dirh **dirh)
515 {
516 	tee_fs_dirfile_close(*dirh);
517 	*dirh = NULL;
518 }
519 #endif /*!CFG_RPMB_FS*/
520 
521 static TEE_Result get_dirh(struct tee_fs_dirfile_dirh **dirh)
522 {
523 	if (!ree_fs_dirh) {
524 		TEE_Result res = open_dirh(&ree_fs_dirh);
525 
526 		if (res) {
527 			*dirh = NULL;
528 			return res;
529 		}
530 	}
531 	ree_fs_dirh_refcount++;
532 	assert(ree_fs_dirh);
533 	assert(ree_fs_dirh_refcount);
534 	*dirh = ree_fs_dirh;
535 	return TEE_SUCCESS;
536 }
537 
538 static void put_dirh_primitive(bool close)
539 {
540 	assert(ree_fs_dirh_refcount);
541 
542 	/*
543 	 * During the execution of one of the ree_fs_ops ree_fs_dirh is
544 	 * guareteed to be a valid pointer. But when the fop has returned
545 	 * another thread may get an error or something causing that fop
546 	 * to do a put with close=1.
547 	 *
548 	 * For all fops but ree_fs_close() there's a call to get_dirh() to
549 	 * get a new dirh which will open it again if it was closed before.
550 	 * But in the ree_fs_close() case there's no call to get_dirh()
551 	 * only to this function, put_dirh_primitive(), and in this case
552 	 * ree_fs_dirh may actually be NULL.
553 	 */
554 	ree_fs_dirh_refcount--;
555 	if (ree_fs_dirh && (!ree_fs_dirh_refcount || close))
556 		close_dirh(&ree_fs_dirh);
557 }
558 
559 static void put_dirh(struct tee_fs_dirfile_dirh *dirh, bool close)
560 {
561 	if (dirh) {
562 		assert(dirh == ree_fs_dirh);
563 		put_dirh_primitive(close);
564 	}
565 }
566 
567 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size,
568 			      struct tee_file_handle **fh)
569 {
570 	TEE_Result res;
571 	struct tee_fs_dirfile_dirh *dirh = NULL;
572 	struct tee_fs_dirfile_fileh dfh;
573 
574 	mutex_lock(&ree_fs_mutex);
575 
576 	res = get_dirh(&dirh);
577 	if (res != TEE_SUCCESS)
578 		goto out;
579 
580 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
581 				  &dfh);
582 	if (res != TEE_SUCCESS)
583 		goto out;
584 
585 	res = ree_fs_open_primitive(false, dfh.hash, &po->uuid, &dfh, fh);
586 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
587 		/*
588 		 * If the object isn't found someone has tampered with it,
589 		 * treat it as corrupt.
590 		 */
591 		res = TEE_ERROR_CORRUPT_OBJECT;
592 	} else if (!res && size) {
593 		struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
594 
595 		*size = tee_fs_htree_get_meta(fdp->ht)->length;
596 	}
597 
598 out:
599 	if (res)
600 		put_dirh(dirh, false);
601 	mutex_unlock(&ree_fs_mutex);
602 
603 	return res;
604 }
605 
606 static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh,
607 			   struct tee_fs_fd *fdp, struct tee_pobj *po,
608 			   bool overwrite)
609 {
610 	TEE_Result res;
611 	bool have_old_dfh = false;
612 	struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 };
613 
614 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
615 				  &old_dfh);
616 	if (!overwrite && !res)
617 		return TEE_ERROR_ACCESS_CONFLICT;
618 
619 	if (!res)
620 		have_old_dfh = true;
621 
622 	/*
623 	 * If old_dfh wasn't found, the idx will be -1 and
624 	 * tee_fs_dirfile_rename() will allocate a new index.
625 	 */
626 	fdp->dfh.idx = old_dfh.idx;
627 	old_dfh.idx = -1;
628 	res = tee_fs_dirfile_rename(dirh, &po->uuid, &fdp->dfh,
629 				    po->obj_id, po->obj_id_len);
630 	if (res)
631 		return res;
632 
633 	res = commit_dirh_writes(dirh);
634 	if (res)
635 		return res;
636 
637 	if (have_old_dfh)
638 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &old_dfh);
639 
640 	return TEE_SUCCESS;
641 }
642 
643 static void ree_fs_close(struct tee_file_handle **fh)
644 {
645 	if (*fh) {
646 		mutex_lock(&ree_fs_mutex);
647 		put_dirh_primitive(false);
648 		mutex_unlock(&ree_fs_mutex);
649 
650 		ree_fs_close_primitive(*fh);
651 		*fh = NULL;
652 	}
653 }
654 
655 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite,
656 				const void *head, size_t head_size,
657 				const void *attr, size_t attr_size,
658 				const void *data, size_t data_size,
659 				struct tee_file_handle **fh)
660 {
661 	struct tee_fs_fd *fdp;
662 	struct tee_fs_dirfile_dirh *dirh = NULL;
663 	struct tee_fs_dirfile_fileh dfh;
664 	TEE_Result res;
665 	size_t pos = 0;
666 
667 	*fh = NULL;
668 	mutex_lock(&ree_fs_mutex);
669 
670 	res = get_dirh(&dirh);
671 	if (res)
672 		goto out;
673 
674 	res = tee_fs_dirfile_get_tmp(dirh, &dfh);
675 	if (res)
676 		goto out;
677 
678 	res = ree_fs_open_primitive(true, dfh.hash, &po->uuid, &dfh, fh);
679 	if (res)
680 		goto out;
681 
682 	if (head && head_size) {
683 		res = ree_fs_write_primitive(*fh, pos, head, head_size);
684 		if (res)
685 			goto out;
686 		pos += head_size;
687 	}
688 
689 	if (attr && attr_size) {
690 		res = ree_fs_write_primitive(*fh, pos, attr, attr_size);
691 		if (res)
692 			goto out;
693 		pos += attr_size;
694 	}
695 
696 	if (data && data_size) {
697 		res = ree_fs_write_primitive(*fh, pos, data, data_size);
698 		if (res)
699 			goto out;
700 	}
701 
702 	fdp = (struct tee_fs_fd *)*fh;
703 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
704 	if (res)
705 		goto out;
706 
707 	res = set_name(dirh, fdp, po, overwrite);
708 out:
709 	if (res) {
710 		put_dirh(dirh, true);
711 		if (*fh) {
712 			ree_fs_close_primitive(*fh);
713 			*fh = NULL;
714 			tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh);
715 		}
716 	}
717 	mutex_unlock(&ree_fs_mutex);
718 
719 	return res;
720 }
721 
722 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos,
723 			       const void *buf, size_t len)
724 {
725 	TEE_Result res;
726 	struct tee_fs_dirfile_dirh *dirh = NULL;
727 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
728 
729 	mutex_lock(&ree_fs_mutex);
730 
731 	res = get_dirh(&dirh);
732 	if (res)
733 		goto out;
734 
735 	res = ree_fs_write_primitive(fh, pos, buf, len);
736 	if (res)
737 		goto out;
738 
739 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
740 	if (res)
741 		goto out;
742 
743 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
744 	if (res)
745 		goto out;
746 	res = commit_dirh_writes(dirh);
747 out:
748 	put_dirh(dirh, res);
749 	mutex_unlock(&ree_fs_mutex);
750 
751 	return res;
752 }
753 
754 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new,
755 				bool overwrite)
756 {
757 	TEE_Result res;
758 	struct tee_fs_dirfile_dirh *dirh = NULL;
759 	struct tee_fs_dirfile_fileh dfh;
760 	struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 };
761 
762 	if (!new)
763 		return TEE_ERROR_BAD_PARAMETERS;
764 
765 	mutex_lock(&ree_fs_mutex);
766 	res = get_dirh(&dirh);
767 	if (res)
768 		goto out;
769 
770 	res = tee_fs_dirfile_find(dirh, &new->uuid, new->obj_id,
771 				  new->obj_id_len, &remove_dfh);
772 	if (!res && !overwrite) {
773 		res = TEE_ERROR_ACCESS_CONFLICT;
774 		goto out;
775 	}
776 
777 	res = tee_fs_dirfile_find(dirh, &old->uuid, old->obj_id,
778 				  old->obj_id_len, &dfh);
779 	if (res)
780 		goto out;
781 
782 	res = tee_fs_dirfile_rename(dirh, &new->uuid, &dfh, new->obj_id,
783 				    new->obj_id_len);
784 	if (res)
785 		goto out;
786 
787 	if (remove_dfh.idx != -1) {
788 		res = tee_fs_dirfile_remove(dirh, &remove_dfh);
789 		if (res)
790 			goto out;
791 	}
792 
793 	res = commit_dirh_writes(dirh);
794 	if (res)
795 		goto out;
796 
797 	if (remove_dfh.idx != -1)
798 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &remove_dfh);
799 
800 out:
801 	put_dirh(dirh, res);
802 	mutex_unlock(&ree_fs_mutex);
803 
804 	return res;
805 
806 }
807 
808 static TEE_Result ree_fs_remove(struct tee_pobj *po)
809 {
810 	TEE_Result res;
811 	struct tee_fs_dirfile_dirh *dirh = NULL;
812 	struct tee_fs_dirfile_fileh dfh;
813 
814 	mutex_lock(&ree_fs_mutex);
815 	res = get_dirh(&dirh);
816 	if (res)
817 		goto out;
818 
819 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
820 				  &dfh);
821 	if (res)
822 		goto out;
823 
824 	res = tee_fs_dirfile_remove(dirh, &dfh);
825 	if (res)
826 		goto out;
827 
828 	res = commit_dirh_writes(dirh);
829 	if (res)
830 		goto out;
831 
832 	tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh);
833 
834 	assert(tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
835 				   &dfh));
836 out:
837 	put_dirh(dirh, res);
838 	mutex_unlock(&ree_fs_mutex);
839 
840 	return res;
841 }
842 
843 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
844 {
845 	TEE_Result res;
846 	struct tee_fs_dirfile_dirh *dirh = NULL;
847 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
848 
849 	mutex_lock(&ree_fs_mutex);
850 
851 	res = get_dirh(&dirh);
852 	if (res != TEE_SUCCESS)
853 		goto out;
854 
855 	res = ree_fs_ftruncate_internal(fdp, len);
856 	if (!res)
857 		goto out;
858 
859 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
860 	if (!res)
861 		goto out;
862 
863 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
864 
865 out:
866 	put_dirh(dirh, res);
867 	mutex_unlock(&ree_fs_mutex);
868 
869 	return res;
870 }
871 
872 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid,
873 				     struct tee_fs_dir **dir)
874 
875 {
876 	TEE_Result res;
877 	struct tee_fs_dir *d = calloc(1, sizeof(*d));
878 
879 	if (!d)
880 		return TEE_ERROR_OUT_OF_MEMORY;
881 
882 	d->uuid = uuid;
883 
884 	mutex_lock(&ree_fs_mutex);
885 
886 	res = get_dirh(&d->dirh);
887 	if (res)
888 		goto out;
889 
890 	/* See that there's at least one file */
891 	d->idx = -1;
892 	d->d.oidlen = sizeof(d->d.oid);
893 	res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid,
894 				      &d->d.oidlen);
895 	d->idx = -1;
896 
897 out:
898 	if (!res) {
899 		*dir = d;
900 	} else {
901 		if (d)
902 			put_dirh(d->dirh, false);
903 		free(d);
904 	}
905 	mutex_unlock(&ree_fs_mutex);
906 
907 	return res;
908 }
909 
910 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
911 {
912 	if (d) {
913 		mutex_lock(&ree_fs_mutex);
914 
915 		put_dirh(d->dirh, false);
916 		free(d);
917 
918 		mutex_unlock(&ree_fs_mutex);
919 	}
920 }
921 
922 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
923 				     struct tee_fs_dirent **ent)
924 {
925 	TEE_Result res;
926 
927 	mutex_lock(&ree_fs_mutex);
928 
929 	d->d.oidlen = sizeof(d->d.oid);
930 	res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid,
931 				      &d->d.oidlen);
932 	if (res == TEE_SUCCESS)
933 		*ent = &d->d;
934 
935 	mutex_unlock(&ree_fs_mutex);
936 
937 	return res;
938 }
939 
940 const struct tee_file_operations ree_fs_ops = {
941 	.open = ree_fs_open,
942 	.create = ree_fs_create,
943 	.close = ree_fs_close,
944 	.read = ree_fs_read,
945 	.write = ree_fs_write,
946 	.truncate = ree_fs_truncate,
947 	.rename = ree_fs_rename,
948 	.remove = ree_fs_remove,
949 	.opendir = ree_fs_opendir_rpc,
950 	.closedir = ree_fs_closedir_rpc,
951 	.readdir = ree_fs_readdir_rpc,
952 };
953