Skip to content

Commit 9637b96

Browse files
committed
Fixed lookahead overflow and removed unbounded lookahead pointers
As pointed out by davidefer, the lookahead pointer modular arithmetic does not work around integer overflow when the pointer size is not a multiple of the block count. To avoid overflow problems, the easy solution is to stop trying to work around integer overflows and keep the lookahead offset inside the block device. To make this work, the ack was modified into a resetable counter that is decremented every block allocation. As a plus, quite a bit of the allocation logic ended up simplified.
1 parent 89a7630 commit 9637b96

File tree

2 files changed

+24
-23
lines changed

2 files changed

+24
-23
lines changed

lfs.c

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,7 @@ int lfs_deorphan(lfs_t *lfs);
270270
static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
271271
lfs_t *lfs = p;
272272

273-
lfs_block_t off = (((lfs_soff_t)(block - lfs->free.begin)
274-
% (lfs_soff_t)(lfs->cfg->block_count))
273+
lfs_block_t off = ((block - lfs->free.off)
275274
+ lfs->cfg->block_count) % lfs->cfg->block_count;
276275

277276
if (off < lfs->free.size) {
@@ -283,36 +282,38 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
283282

284283
static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
285284
while (true) {
286-
while (lfs->free.off != lfs->free.size) {
287-
lfs_block_t off = lfs->free.off;
288-
lfs->free.off += 1;
285+
while (lfs->free.i != lfs->free.size) {
286+
lfs_block_t off = lfs->free.i;
287+
lfs->free.i += 1;
288+
lfs->free.ack -= 1;
289289

290290
if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) {
291291
// found a free block
292-
*block = (lfs->free.begin + off) % lfs->cfg->block_count;
292+
*block = (lfs->free.off + off) % lfs->cfg->block_count;
293293

294294
// eagerly find next off so an alloc ack can
295295
// discredit old lookahead blocks
296-
while (lfs->free.off != lfs->free.size &&
297-
(lfs->free.buffer[lfs->free.off / 32] &
298-
(1U << (lfs->free.off % 32)))) {
299-
lfs->free.off += 1;
296+
while (lfs->free.i != lfs->free.size &&
297+
(lfs->free.buffer[lfs->free.i / 32]
298+
& (1U << (lfs->free.i % 32)))) {
299+
lfs->free.i += 1;
300+
lfs->free.ack -= 1;
300301
}
301302

302303
return 0;
303304
}
304305
}
305306

306307
// check if we have looked at all blocks since last ack
307-
if (lfs->free.off == lfs->free.ack - lfs->free.begin) {
308-
LFS_WARN("No more free space %d", lfs->free.off + lfs->free.begin);
308+
if (lfs->free.ack == 0) {
309+
LFS_WARN("No more free space %d", lfs->free.i + lfs->free.off);
309310
return LFS_ERR_NOSPC;
310311
}
311312

312-
lfs->free.begin += lfs->free.size;
313-
lfs->free.size = lfs_min(lfs->cfg->lookahead,
314-
lfs->free.ack - lfs->free.begin);
315-
lfs->free.off = 0;
313+
lfs->free.off = (lfs->free.off + lfs->free.size)
314+
% lfs->cfg->block_count;
315+
lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->free.ack);
316+
lfs->free.i = 0;
316317

317318
// find mask of free blocks from tree
318319
memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8);
@@ -324,7 +325,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
324325
}
325326

326327
static void lfs_alloc_ack(lfs_t *lfs) {
327-
lfs->free.ack = lfs->free.begin+lfs->free.off + lfs->cfg->block_count;
328+
lfs->free.ack = lfs->cfg->block_count;
328329
}
329330

330331

@@ -2103,9 +2104,9 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
21032104

21042105
// create free lookahead
21052106
memset(lfs->free.buffer, 0, lfs->cfg->lookahead/8);
2106-
lfs->free.begin = 0;
2107-
lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
21082107
lfs->free.off = 0;
2108+
lfs->free.size = lfs_min(lfs->cfg->lookahead, lfs->cfg->block_count);
2109+
lfs->free.i = 0;
21092110
lfs_alloc_ack(lfs);
21102111

21112112
// create superblock dir
@@ -2182,9 +2183,9 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
21822183
}
21832184

21842185
// setup free lookahead
2185-
lfs->free.begin = 0;
2186-
lfs->free.size = 0;
21872186
lfs->free.off = 0;
2187+
lfs->free.size = 0;
2188+
lfs->free.i = 0;
21882189
lfs_alloc_ack(lfs);
21892190

21902191
// load superblock

lfs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,9 @@ typedef struct lfs_superblock {
259259
} lfs_superblock_t;
260260

261261
typedef struct lfs_free {
262-
lfs_block_t begin;
263-
lfs_block_t size;
264262
lfs_block_t off;
263+
lfs_block_t size;
264+
lfs_block_t i;
265265
lfs_block_t ack;
266266
uint32_t *buffer;
267267
} lfs_free_t;

0 commit comments

Comments
 (0)