1 /*
2  * Copyright (c) 2017-2020 Nordic Semiconductor ASA
3  * Copyright (c) 2015 Runtime Inc
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <stddef.h>
9 #include <string.h>
10 
11 #include <zephyr/fs/fcb.h>
12 #include "fcb_priv.h"
13 
14 static struct flash_sector *
fcb_new_sector(struct fcb * fcb,int cnt)15 fcb_new_sector(struct fcb *fcb, int cnt)
16 {
17 	struct flash_sector *prev;
18 	struct flash_sector *cur;
19 	int i;
20 
21 	prev = NULL;
22 	i = 0;
23 	cur = fcb->f_active.fe_sector;
24 	do {
25 		cur = fcb_getnext_sector(fcb, cur);
26 		if (!prev) {
27 			prev = cur;
28 		}
29 		if (cur == fcb->f_oldest) {
30 			return NULL;
31 		}
32 	} while (i++ < cnt);
33 	return prev;
34 }
35 
36 /*
37  * Take one of the scratch blocks into use, if at all possible.
38  */
39 int
fcb_append_to_scratch(struct fcb * fcb)40 fcb_append_to_scratch(struct fcb *fcb)
41 {
42 	struct flash_sector *sector;
43 	int rc;
44 
45 	sector = fcb_new_sector(fcb, 0);
46 	if (!sector) {
47 		return -ENOSPC;
48 	}
49 	rc = fcb_sector_hdr_init(fcb, sector, fcb->f_active_id + 1);
50 	if (rc) {
51 		return rc;
52 	}
53 	fcb->f_active.fe_sector = sector;
54 	fcb->f_active.fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area));
55 	fcb->f_active_id++;
56 	return 0;
57 }
58 
59 int
fcb_append(struct fcb * fcb,uint16_t len,struct fcb_entry * append_loc)60 fcb_append(struct fcb *fcb, uint16_t len, struct fcb_entry *append_loc)
61 {
62 	struct flash_sector *sector;
63 	struct fcb_entry *active;
64 	int cnt;
65 	int rc;
66 	uint8_t tmp_str[MAX(8, fcb->f_align)];
67 
68 	/* Ensure defined value of padding bytes */
69 	memset(tmp_str, fcb->f_erase_value, sizeof(tmp_str));
70 
71 	cnt = fcb_put_len(fcb, tmp_str, len);
72 	if (cnt < 0) {
73 		return cnt;
74 	}
75 	cnt = fcb_len_in_flash(fcb, cnt);
76 	len = fcb_len_in_flash(fcb, len) + fcb_len_in_flash(fcb, FCB_CRC_SZ);
77 
78 	__ASSERT_NO_MSG(cnt <= sizeof(tmp_str));
79 
80 	rc = k_mutex_lock(&fcb->f_mtx, K_FOREVER);
81 	if (rc) {
82 		return -EINVAL;
83 	}
84 	active = &fcb->f_active;
85 	if (active->fe_elem_off + len + cnt > active->fe_sector->fs_size) {
86 		sector = fcb_new_sector(fcb, fcb->f_scratch_cnt);
87 		if (!sector || (sector->fs_size <
88 			fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)) + len + cnt)) {
89 			rc = -ENOSPC;
90 			goto err;
91 		}
92 		rc = fcb_sector_hdr_init(fcb, sector, fcb->f_active_id + 1);
93 		if (rc) {
94 			goto err;
95 		}
96 		fcb->f_active.fe_sector = sector;
97 		fcb->f_active.fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area));
98 		fcb->f_active_id++;
99 	}
100 
101 	rc = fcb_flash_write(fcb, active->fe_sector, active->fe_elem_off, tmp_str, cnt);
102 	if (rc) {
103 		rc = -EIO;
104 		goto err;
105 	}
106 	append_loc->fe_sector = active->fe_sector;
107 	append_loc->fe_elem_off = active->fe_elem_off;
108 	append_loc->fe_data_off = active->fe_elem_off + cnt;
109 
110 	active->fe_elem_off = append_loc->fe_data_off + len;
111 
112 	k_mutex_unlock(&fcb->f_mtx);
113 
114 	return 0;
115 err:
116 	k_mutex_unlock(&fcb->f_mtx);
117 	return rc;
118 }
119 
120 int
fcb_append_finish(struct fcb * fcb,struct fcb_entry * loc)121 fcb_append_finish(struct fcb *fcb, struct fcb_entry *loc)
122 {
123 	int rc;
124 	uint8_t em[fcb->f_align];
125 	off_t off;
126 
127 	(void)memset(em, 0xFF, sizeof(em));
128 
129 	rc = fcb_elem_endmarker(fcb, loc, &em[0]);
130 	if (rc) {
131 		return rc;
132 	}
133 	off = loc->fe_data_off + fcb_len_in_flash(fcb, loc->fe_data_len);
134 
135 	rc = fcb_flash_write(fcb, loc->fe_sector, off, em, fcb->f_align);
136 	if (rc) {
137 		return -EIO;
138 	}
139 	return 0;
140 }
141