Skip to content

Commit aa87265

Browse files
committed
Cleaned up block allocator
Removed scanning for stride - Adds complexity with questionable benefit - Can be added as an optimization later Fixed handling around device boundaries and where lookahead may not be a factor of the device size (consider small devices with only a few blocks) Added support for configuration with optional dynamic memory as found in the caching configuration
1 parent 7050922 commit aa87265

File tree

4 files changed

+91
-94
lines changed

4 files changed

+91
-94
lines changed

lfs.c

Lines changed: 74 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -189,103 +189,60 @@ static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
189189
static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
190190
lfs_t *lfs = p;
191191

192-
lfs_block_t off = block - lfs->free.begin;
193-
if (off < LFS_CFG_LOOKAHEAD) {
194-
lfs->lookahead[off / 32] |= 1U << (off % 32);
192+
lfs_block_t off = (block - lfs->free.start) % lfs->cfg->block_count;
193+
if (off < lfs->cfg->lookahead) {
194+
lfs->free.lookahead[off / 32] |= 1U << (off % 32);
195195
}
196196

197197
return 0;
198198
}
199199

200-
static int lfs_alloc_stride(void *p, lfs_block_t block) {
201-
lfs_t *lfs = p;
202-
203-
lfs_block_t noff = block - lfs->free.begin;
204-
lfs_block_t off = lfs->free.end - lfs->free.begin;
205-
if (noff < off) {
206-
lfs->free.end = noff + lfs->free.begin;
207-
}
208-
209-
return 0;
210-
}
211-
212-
static int lfs_alloc_scan(lfs_t *lfs) {
213-
lfs_block_t start = lfs->free.begin;
200+
static int lfs_alloc_scan(lfs_t *lfs, lfs_block_t *block) {
201+
lfs_block_t end = lfs->free.start + lfs->cfg->block_count;
214202

215203
while (true) {
216-
// mask out blocks in lookahead region
217-
memset(lfs->lookahead, 0, sizeof(lfs->lookahead));
218-
int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs);
219-
if (err) {
220-
return err;
221-
}
222-
223-
// check if we've found a free block
224-
for (uint32_t off = 0; off < LFS_CFG_LOOKAHEAD; off++) {
225-
if (lfs->lookahead[off / 32] & (1U << (off % 32))) {
226-
continue;
204+
while (lfs->free.off < lfs->cfg->lookahead) {
205+
lfs_block_t off = lfs->free.off;
206+
lfs->free.off += 1;
207+
208+
if (!(lfs->free.lookahead[off / 32] & (1U << (off % 32)))) {
209+
// found a free block
210+
*block = (lfs->free.start + off) % lfs->cfg->block_count;
211+
return 0;
227212
}
228-
229-
// found free block, now find stride of free blocks
230-
// since this is relatively cheap (stress on relatively)
231-
lfs->free.begin += off;
232-
lfs->free.end = lfs->cfg->block_count; // before superblock
233-
234-
// find maximum stride in tree
235-
return lfs_traverse(lfs, lfs_alloc_stride, lfs);
236213
}
237214

238-
// continue to next lookahead unless we've searched the whole device
239-
if (start-1 - lfs->free.begin < LFS_CFG_LOOKAHEAD) {
240-
return 0;
215+
// could not find block
216+
lfs->free.start += lfs->cfg->lookahead;
217+
lfs->free.off = 0;
218+
if (lfs_scmp(lfs->free.start, end) > 0) {
219+
return LFS_ERROR_NO_SPACE;
241220
}
242221

243-
// continue to next lookahead region
244-
lfs->free.begin += LFS_CFG_LOOKAHEAD;
245-
}
246-
}
247-
248-
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
249-
// If we don't remember any free blocks we will need to start searching
250-
if (lfs->free.begin == lfs->free.end) {
251-
int err = lfs_alloc_scan(lfs);
222+
// find mask of free blocks from tree
223+
memset(lfs->free.lookahead, 0, lfs->cfg->lookahead/8);
224+
int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs);
252225
if (err) {
253226
return err;
254227
}
255-
256-
if (lfs->free.begin == lfs->free.end) {
257-
// Still can't allocate a block? check for orphans
258-
int err = lfs_deorphan(lfs);
259-
if (err) {
260-
return err;
261-
}
262-
263-
err = lfs_alloc_scan(lfs);
264-
if (err) {
265-
return err;
266-
}
267-
268-
if (lfs->free.begin == lfs->free.end) {
269-
// Ok, it's true, we're out of space
270-
return LFS_ERROR_NO_SPACE;
271-
}
272-
}
273228
}
274-
275-
// Take first available block
276-
*block = lfs->free.begin;
277-
lfs->free.begin += 1;
278-
return 0;
279229
}
280230

281-
static int lfs_alloc_erased(lfs_t *lfs, lfs_block_t *block) {
282-
// TODO rm me?
283-
int err = lfs_alloc(lfs, block);
231+
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
232+
// try to scan for free block
233+
int err = lfs_alloc_scan(lfs, block);
234+
if (err != LFS_ERROR_NO_SPACE) {
235+
return err;
236+
}
237+
238+
// still can't allocate a block? check for orphans
239+
err = lfs_deorphan(lfs);
284240
if (err) {
285241
return err;
286242
}
287243

288-
return lfs_bd_erase(lfs, *block);
244+
// scan again or die trying
245+
return lfs_alloc_scan(lfs, block);
289246
}
290247

291248

@@ -343,7 +300,12 @@ static int lfs_index_append(lfs_t *lfs, lfs_block_t *headp,
343300

344301
while (ioff % lfs->words == 0) {
345302
lfs_block_t nhead;
346-
int err = lfs_alloc_erased(lfs, &nhead);
303+
int err = lfs_alloc(lfs, &nhead);
304+
if (err) {
305+
return err;
306+
}
307+
308+
err = lfs_bd_erase(lfs, nhead);
347309
if (err) {
348310
return err;
349311
}
@@ -480,7 +442,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) {
480442
static int lfs_dir_fetch(lfs_t *lfs,
481443
lfs_dir_t *dir, const lfs_block_t pair[2]) {
482444
// copy out pair, otherwise may be aliasing dir
483-
const lfs_block_t tpair[2] = {pair[0], pair[1]};
445+
const lfs_block_t tpair[2] = {pair[0], pair[1]};
484446
bool valid = false;
485447

486448
// check both blocks for the most recent revision
@@ -1048,15 +1010,25 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
10481010
lfs_off_t woff = file->size % lfs->cfg->block_size;
10491011

10501012
if (file->size == 0) {
1051-
int err = lfs_alloc_erased(lfs, &file->wblock);
1013+
int err = lfs_alloc(lfs, &file->wblock);
1014+
if (err) {
1015+
return err;
1016+
}
1017+
1018+
err = lfs_bd_erase(lfs, file->wblock);
10521019
if (err) {
10531020
return err;
10541021
}
10551022

10561023
file->head = file->wblock;
10571024
file->windex = 0;
10581025
} else if (woff == 0) {
1059-
int err = lfs_alloc_erased(lfs, &file->wblock);
1026+
int err = lfs_alloc(lfs, &file->wblock);
1027+
if (err) {
1028+
return err;
1029+
}
1030+
1031+
err = lfs_bd_erase(lfs, file->wblock);
10601032
if (err) {
10611033
return err;
10621034
}
@@ -1124,9 +1096,9 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
11241096
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
11251097
lfs->cfg = cfg;
11261098
lfs->words = lfs->cfg->block_size / sizeof(uint32_t);
1127-
lfs->rcache.off = -1;
1128-
lfs->pcache.off = -1;
11291099

1100+
// setup read cache
1101+
lfs->rcache.off = -1;
11301102
if (lfs->cfg->read_buffer) {
11311103
lfs->rcache.buffer = lfs->cfg->read_buffer;
11321104
} else {
@@ -1136,6 +1108,8 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
11361108
}
11371109
}
11381110

1111+
// setup program cache
1112+
lfs->pcache.off = -1;
11391113
if (lfs->cfg->prog_buffer) {
11401114
lfs->pcache.buffer = lfs->cfg->prog_buffer;
11411115
} else {
@@ -1145,6 +1119,16 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
11451119
}
11461120
}
11471121

1122+
// setup lookahead
1123+
if (lfs->cfg->lookahead_buffer) {
1124+
lfs->free.lookahead = lfs->cfg->lookahead_buffer;
1125+
} else {
1126+
lfs->free.lookahead = malloc(lfs->cfg->lookahead/8);
1127+
if (!lfs->free.lookahead) {
1128+
return LFS_ERROR_NO_MEM;
1129+
}
1130+
}
1131+
11481132
return 0;
11491133
}
11501134

@@ -1167,9 +1151,10 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
11671151
return err;
11681152
}
11691153

1170-
// Create free list
1171-
lfs->free.begin = 0;
1172-
lfs->free.end = lfs->cfg->block_count-1;
1154+
// Create free lookahead
1155+
memset(lfs->free.lookahead, 0, lfs->cfg->lookahead/8);
1156+
lfs->free.start = 0;
1157+
lfs->free.off = 0;
11731158

11741159
// Create superblock dir
11751160
lfs_dir_t superdir;
@@ -1235,6 +1220,11 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
12351220
return err;
12361221
}
12371222

1223+
// setup free lookahead
1224+
lfs->free.start = -lfs->cfg->lookahead;
1225+
lfs->free.off = lfs->cfg->lookahead;
1226+
1227+
// load superblock
12381228
lfs_dir_t dir;
12391229
lfs_superblock_t superblock;
12401230
err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1});

lfs.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,18 @@ struct lfs_config {
7676
// Number of erasable blocks on the device.
7777
lfs_size_t block_count;
7878

79+
// Number of blocks to lookahead during block allocation.
80+
lfs_size_t lookahead;
81+
7982
// Optional, statically allocated read buffer. Must be read sized.
8083
void *read_buffer;
8184

8285
// Optional, statically allocated program buffer. Must be program sized.
8386
void *prog_buffer;
87+
88+
// Optional, statically allocated lookahead buffer.
89+
// Must be 1 bit per lookahead block.
90+
void *lookahead_buffer;
8491
};
8592

8693
// File info structure
@@ -161,18 +168,18 @@ typedef struct lfs {
161168
lfs_size_t words; // number of 32-bit words that can fit in a block
162169

163170
lfs_block_t root[2];
164-
struct {
165-
lfs_block_t begin;
166-
lfs_block_t end;
167-
} free;
168171

169172
struct {
170173
lfs_block_t block;
171174
lfs_off_t off;
172175
uint8_t *buffer;
173176
} rcache, pcache;
174177

175-
uint32_t lookahead[LFS_CFG_LOOKAHEAD/32];
178+
struct {
179+
lfs_block_t start;
180+
lfs_block_t off;
181+
uint32_t *lookahead;
182+
} free;
176183
} lfs_t;
177184

178185

lfs_config.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ typedef uint32_t lfs_block_t;
2323
#define LFS_NAME_MAX 255
2424
#endif
2525

26-
// Lookahead distance
27-
#ifndef LFS_CFG_LOOKAHEAD
28-
#define LFS_CFG_LOOKAHEAD 128
29-
#endif
30-
3126
// Logging operations
3227
#include <stdio.h>
3328
#define LFS_ERROR(fmt, ...) printf("lfs error: " fmt "\n", __VA_ARGS__)

tests/template.fmt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ uintmax_t res;
7070
#define LFS_BLOCK_COUNT 1024
7171
#endif
7272

73+
#ifndef LFS_LOOKAHEAD
74+
#define LFS_LOOKAHEAD 128
75+
#endif
76+
7377
const struct lfs_config cfg = {{
7478
.context = &bd,
7579
.read = &lfs_emubd_read,
@@ -81,6 +85,7 @@ const struct lfs_config cfg = {{
8185
.prog_size = LFS_PROG_SIZE,
8286
.block_size = LFS_BLOCK_SIZE,
8387
.block_count = LFS_BLOCK_COUNT,
88+
.lookahead = LFS_LOOKAHEAD,
8489
}};
8590

8691

0 commit comments

Comments
 (0)