99
1010#include <string.h>
1111#include <stdbool.h>
12+ #include <stdlib.h>
1213
1314
1415/// Block device operations ///
16+ static int lfs_bd_flush (lfs_t * lfs ) {
17+ if (lfs -> pcache .off != -1 ) {
18+ int err = lfs -> cfg -> prog (lfs -> cfg , lfs -> pcache .block ,
19+ lfs -> pcache .off , lfs -> cfg -> prog_size ,
20+ lfs -> pcache .buffer );
21+ if (err ) {
22+ return err ;
23+ }
24+
25+ lfs -> pcache .off = -1 ;
26+ }
27+
28+ return 0 ;
29+ }
30+
1531static int lfs_bd_read (lfs_t * lfs , lfs_block_t block ,
1632 lfs_off_t off , lfs_size_t size , void * buffer ) {
17- return lfs -> cfg -> read (lfs -> cfg , block , off , size , buffer );
33+ uint8_t * data = buffer ;
34+
35+ // flush overlapping programs
36+ while (size > 0 ) {
37+ if (block == lfs -> pcache .block && off >= lfs -> pcache .off &&
38+ off < lfs -> pcache .off + lfs -> cfg -> prog_size ) {
39+ // is already in cache?
40+ lfs_size_t diff = lfs_min (size ,
41+ lfs -> cfg -> prog_size - (off - lfs -> pcache .off ));
42+ memcpy (data , & lfs -> pcache .buffer [off - lfs -> pcache .off ], diff );
43+
44+ data += diff ;
45+ off += diff ;
46+ size -= diff ;
47+ continue ;
48+ } else if (block == lfs -> rcache .block && off >= lfs -> rcache .off &&
49+ off < lfs -> rcache .off + lfs -> cfg -> read_size ) {
50+ // is already in cache?
51+ lfs_size_t diff = lfs_min (size ,
52+ lfs -> cfg -> read_size - (off - lfs -> rcache .off ));
53+ memcpy (data , & lfs -> rcache .buffer [off - lfs -> rcache .off ], diff );
54+
55+ data += diff ;
56+ off += diff ;
57+ size -= diff ;
58+ continue ;
59+ }
60+
61+ // write out pending programs
62+ int err = lfs_bd_flush (lfs );
63+ if (err ) {
64+ return err ;
65+ }
66+
67+ if (off % lfs -> cfg -> read_size == 0 &&
68+ size >= lfs -> cfg -> read_size ) {
69+ // bypass cache?
70+ lfs_size_t diff = size - (size % lfs -> cfg -> read_size );
71+ int err = lfs -> cfg -> read (lfs -> cfg , block , off , diff , data );
72+ if (err ) {
73+ return err ;
74+ }
75+
76+ data += diff ;
77+ off += diff ;
78+ size -= diff ;
79+ continue ;
80+ }
81+
82+ // load to cache, first condition can no longer fail
83+ lfs -> rcache .block = block ;
84+ lfs -> rcache .off = off - (off % lfs -> cfg -> read_size );
85+ // TODO remove reading, should be unnecessary
86+ err = lfs -> cfg -> read (lfs -> cfg , lfs -> rcache .block ,
87+ lfs -> rcache .off , lfs -> cfg -> read_size ,
88+ lfs -> rcache .buffer );
89+ if (err ) {
90+ return err ;
91+ }
92+ }
93+
94+ return 0 ;
1895}
1996
2097static int lfs_bd_prog (lfs_t * lfs , lfs_block_t block ,
2198 lfs_off_t off , lfs_size_t size , const void * buffer ) {
22- return lfs -> cfg -> prog (lfs -> cfg , block , off , size , buffer );
99+ const uint8_t * data = buffer ;
100+
101+ if (block == lfs -> rcache .block ) {
102+ // invalidate read cache
103+ lfs -> rcache .off = -1 ;
104+ }
105+
106+ while (size > 0 ) {
107+ if (block == lfs -> pcache .block && off >= lfs -> pcache .off &&
108+ off < lfs -> pcache .off + lfs -> cfg -> prog_size ) {
109+ // is already in cache?
110+ lfs_size_t diff = lfs_min (size ,
111+ lfs -> cfg -> prog_size - (off - lfs -> pcache .off ));
112+ memcpy (& lfs -> pcache .buffer [off - lfs -> pcache .off ], data , diff );
113+
114+ data += diff ;
115+ off += diff ;
116+ size -= diff ;
117+ continue ;
118+ }
119+
120+ // write out pending programs
121+ int err = lfs_bd_flush (lfs );
122+ if (err ) {
123+ return err ;
124+ }
125+
126+ if (off % lfs -> cfg -> prog_size == 0 &&
127+ size >= lfs -> cfg -> prog_size ) {
128+ // bypass cache?
129+ lfs_size_t diff = size - (size % lfs -> cfg -> prog_size );
130+ int err = lfs -> cfg -> prog (lfs -> cfg , block , off , diff , data );
131+ if (err ) {
132+ return err ;
133+ }
134+
135+ data += diff ;
136+ off += diff ;
137+ size -= diff ;
138+ continue ;
139+ }
140+
141+ // prepare cache, first condition can no longer fail
142+ lfs -> pcache .block = block ;
143+ lfs -> pcache .off = off - (off % lfs -> cfg -> prog_size );
144+ err = lfs -> cfg -> read (lfs -> cfg , lfs -> pcache .block ,
145+ lfs -> pcache .off , lfs -> cfg -> prog_size ,
146+ lfs -> pcache .buffer );
147+ if (err ) {
148+ return err ;
149+ }
150+ }
151+
152+ return 0 ;
23153}
24154
25155static int lfs_bd_erase (lfs_t * lfs , lfs_block_t block ) {
26156 return lfs -> cfg -> erase (lfs -> cfg , block );
27157}
28158
29159static int lfs_bd_sync (lfs_t * lfs ) {
160+ int err = lfs_bd_flush (lfs );
161+ if (err ) {
162+ return err ;
163+ }
164+
30165 return lfs -> cfg -> sync (lfs -> cfg );
31166}
32167
@@ -41,11 +176,9 @@ static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
41176 return err ;
42177 }
43178
44- if (c != * data ) {
179+ if (c != data [ i ] ) {
45180 return false;
46181 }
47-
48- data += 1 ;
49182 }
50183
51184 return true;
@@ -452,13 +585,13 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
452585 }
453586
454587 while (off < lfs -> cfg -> block_size - 4 ) {
455- uint8_t data ;
456- int err = lfs_bd_read (lfs , dir -> pair [0 ], off , 1 , & data );
588+ uint8_t data = 0xff ;
589+ crc = lfs_crc (crc , 1 , & data );
590+ err = lfs_bd_prog (lfs , dir -> pair [0 ], off , 1 , & data );
457591 if (err ) {
458592 return err ;
459593 }
460594
461- crc = lfs_crc (crc , 1 , & data );
462595 off += 1 ;
463596 }
464597
@@ -512,13 +645,14 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
512645 }
513646
514647 while (woff < lfs -> cfg -> block_size - 4 ) {
515- uint8_t data ;
516- int err = lfs_bd_read (lfs , dir -> pair [0 ], woff , 1 , & data );
648+ uint8_t data = 0xff ;
649+ crc = lfs_crc (crc , 1 , & data );
650+ err = lfs_bd_prog (lfs , dir -> pair [0 ], woff , 1 , & data );
517651 if (err ) {
518652 return err ;
519653 }
520654
521- crc = lfs_crc ( crc , 1 , & data );
655+
522656 woff += 1 ;
523657 }
524658
@@ -618,6 +752,7 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
618752 }
619753
620754 dir -> off = sizeof (dir -> d );
755+ continue ;
621756 }
622757
623758 int err = lfs_bd_read (lfs , dir -> pair [0 ], dir -> off ,
@@ -986,17 +1121,59 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
9861121
9871122
9881123/// Generic filesystem operations ///
989- int lfs_format (lfs_t * lfs , const struct lfs_config * config ) {
990- lfs -> cfg = config ;
1124+ static int lfs_init (lfs_t * lfs , const struct lfs_config * cfg ) {
1125+ lfs -> cfg = cfg ;
9911126 lfs -> words = lfs -> cfg -> block_size / sizeof (uint32_t );
1127+ lfs -> rcache .off = -1 ;
1128+ lfs -> pcache .off = -1 ;
1129+
1130+ if (lfs -> cfg -> read_buffer ) {
1131+ lfs -> rcache .buffer = lfs -> cfg -> read_buffer ;
1132+ } else {
1133+ lfs -> rcache .buffer = malloc (lfs -> cfg -> read_size );
1134+ if (!lfs -> rcache .buffer ) {
1135+ return LFS_ERROR_NO_MEM ;
1136+ }
1137+ }
1138+
1139+ if (lfs -> cfg -> prog_buffer ) {
1140+ lfs -> pcache .buffer = lfs -> cfg -> prog_buffer ;
1141+ } else {
1142+ lfs -> pcache .buffer = malloc (lfs -> cfg -> prog_size );
1143+ if (!lfs -> pcache .buffer ) {
1144+ return LFS_ERROR_NO_MEM ;
1145+ }
1146+ }
1147+
1148+ return 0 ;
1149+ }
1150+
1151+ static int lfs_deinit (lfs_t * lfs ) {
1152+ // Free allocated memory
1153+ if (!lfs -> cfg -> read_buffer ) {
1154+ free (lfs -> rcache .buffer );
1155+ }
1156+
1157+ if (!lfs -> cfg -> prog_buffer ) {
1158+ free (lfs -> pcache .buffer );
1159+ }
1160+
1161+ return 0 ;
1162+ }
1163+
1164+ int lfs_format (lfs_t * lfs , const struct lfs_config * cfg ) {
1165+ int err = lfs_init (lfs , cfg );
1166+ if (err ) {
1167+ return err ;
1168+ }
9921169
9931170 // Create free list
9941171 lfs -> free .begin = 0 ;
9951172 lfs -> free .end = lfs -> cfg -> block_count - 1 ;
9961173
9971174 // Create superblock dir
9981175 lfs_dir_t superdir ;
999- int err = lfs_dir_alloc (lfs , & superdir );
1176+ err = lfs_dir_alloc (lfs , & superdir );
10001177 if (err ) {
10011178 return err ;
10021179 }
@@ -1044,16 +1221,23 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config) {
10441221 }
10451222
10461223 // sanity check that fetch works
1047- return lfs_dir_fetch (lfs , & superdir , (const lfs_block_t [2 ]){0 , 1 });
1224+ err = lfs_dir_fetch (lfs , & superdir , (const lfs_block_t [2 ]){0 , 1 });
1225+ if (err ) {
1226+ return err ;
1227+ }
1228+
1229+ return lfs_deinit (lfs );
10481230}
10491231
1050- int lfs_mount (lfs_t * lfs , const struct lfs_config * config ) {
1051- lfs -> cfg = config ;
1052- lfs -> words = lfs -> cfg -> block_size / sizeof (uint32_t );
1232+ int lfs_mount (lfs_t * lfs , const struct lfs_config * cfg ) {
1233+ int err = lfs_init (lfs , cfg );
1234+ if (err ) {
1235+ return err ;
1236+ }
10531237
10541238 lfs_dir_t dir ;
10551239 lfs_superblock_t superblock ;
1056- int err = lfs_dir_fetch (lfs , & dir , (const lfs_block_t [2 ]){0 , 1 });
1240+ err = lfs_dir_fetch (lfs , & dir , (const lfs_block_t [2 ]){0 , 1 });
10571241 if (!err ) {
10581242 err = lfs_bd_read (lfs , dir .pair [0 ],
10591243 sizeof (dir .d ), sizeof (superblock .d ), & superblock .d );
@@ -1078,8 +1262,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *config) {
10781262}
10791263
10801264int lfs_unmount (lfs_t * lfs ) {
1081- // Do nothing for now
1082- return 0 ;
1265+ return lfs_deinit (lfs );
10831266}
10841267
10851268int lfs_traverse (lfs_t * lfs , int (* cb )(void * , lfs_block_t ), void * data ) {
0 commit comments