Skip to content

Commit 71ea438

Browse files
committed
extmod/vfs: Check block 0 and 1 when auto-detecting littlefs.
The superblock for littlefs is in block 0 and 1, but block 0 may be erased or partially written, so block 1 must be checked if block 0 does not have a valid littlefs superblock in it. Prior to this commit, the mount of a block device which auto-detected the filysystem type would fail for littlefs if block 0 did not contain a valid superblock. That is now fixed. Signed-off-by: Damien George <damien@micropython.org>
1 parent 4eaebc1 commit 71ea438

File tree

3 files changed

+69
-17
lines changed

3 files changed

+69
-17
lines changed

extmod/vfs.c

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -160,27 +160,30 @@ STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) {
160160
#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2
161161
nlr_buf_t nlr;
162162
if (nlr_push(&nlr) == 0) {
163-
mp_obj_t vfs = MP_OBJ_NULL;
163+
// The superblock for littlefs is in both block 0 and 1, but block 0 may be erased
164+
// or partially written, so search both blocks 0 and 1 for the littlefs signature.
164165
mp_vfs_blockdev_t blockdev;
165166
mp_vfs_blockdev_init(&blockdev, bdev_obj);
166167
uint8_t buf[44];
167-
mp_vfs_blockdev_read_ext(&blockdev, 0, 8, sizeof(buf), buf);
168-
#if MICROPY_VFS_LFS1
169-
if (memcmp(&buf[32], "littlefs", 8) == 0) {
170-
// LFS1
171-
vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, 0, &bdev_obj);
172-
nlr_pop();
173-
return vfs;
174-
}
175-
#endif
176-
#if MICROPY_VFS_LFS2
177-
if (memcmp(&buf[0], "littlefs", 8) == 0) {
178-
// LFS2
179-
vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, 0, &bdev_obj);
180-
nlr_pop();
181-
return vfs;
168+
for (size_t block_num = 0; block_num <= 1; ++block_num) {
169+
mp_vfs_blockdev_read_ext(&blockdev, block_num, 8, sizeof(buf), buf);
170+
#if MICROPY_VFS_LFS1
171+
if (memcmp(&buf[32], "littlefs", 8) == 0) {
172+
// LFS1
173+
mp_obj_t vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, 0, &bdev_obj);
174+
nlr_pop();
175+
return vfs;
176+
}
177+
#endif
178+
#if MICROPY_VFS_LFS2
179+
if (memcmp(&buf[0], "littlefs", 8) == 0) {
180+
// LFS2
181+
mp_obj_t vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, 0, &bdev_obj);
182+
nlr_pop();
183+
return vfs;
184+
}
185+
#endif
182186
}
183-
#endif
184187
nlr_pop();
185188
} else {
186189
// Ignore exception (eg block device doesn't support extended readblocks)

tests/extmod/vfs_lfs_superblock.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Test for VfsLfs using a RAM device, when the first superblock does not exist
2+
3+
try:
4+
import uos
5+
6+
uos.VfsLfs2
7+
except (ImportError, AttributeError):
8+
print("SKIP")
9+
raise SystemExit
10+
11+
12+
class RAMBlockDevice:
13+
def __init__(self, block_size, data):
14+
self.block_size = block_size
15+
self.data = data
16+
17+
def readblocks(self, block, buf, off):
18+
addr = block * self.block_size + off
19+
for i in range(len(buf)):
20+
buf[i] = self.data[addr + i]
21+
22+
def ioctl(self, op, arg):
23+
if op == 4: # block count
24+
return len(self.data) // self.block_size
25+
if op == 5: # block size
26+
return self.block_size
27+
if op == 6: # erase block
28+
return 0
29+
30+
31+
# This is a valid littlefs2 filesystem with a block size of 64 bytes.
32+
# The first block (where the first superblock is stored) is fully erased.
33+
lfs2_data = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02\x00\x00\x00\xf0\x0f\xff\xf7littlefs/\xe0\x00\x10\x00\x00\x02\x00@\x00\x00\x00\x04\x00\x00\x00\xff\x00\x00\x00\xff\xff\xff\x7f\xfe\x03\x00\x00p\x1f\xfc\x08\x1b\xb4\x14\xa7\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\xff\xef\xff\xf7test.txt \x00\x00\x08p\x1f\xfc\x08\x83\xf1u\xba\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
34+
35+
# Create the block device from the static data (it will be read-only).
36+
bdev = RAMBlockDevice(64, lfs2_data)
37+
38+
# Create the VFS explicitly, no auto-detection is needed for this.
39+
vfs = uos.VfsLfs2(bdev)
40+
print(list(vfs.ilistdir()))
41+
42+
# Mount the block device directly; this relies on auto-detection.
43+
uos.mount(bdev, "/userfs")
44+
print(uos.listdir("/userfs"))
45+
46+
# Clean up.
47+
uos.umount("/userfs")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[]
2+
[]

0 commit comments

Comments
 (0)