Skip to content

Commit 12ad64b

Browse files
committed
extmod/vfs_fat: Mount FatFS on creation so VFS methods can be used.
It's possible to use the methods (eg ilistdir) of a VFS FatFS object without it being mounted in the VFS itself. This previously worked but only because FatFS was "mounting" the filesystem automatically when any function (eg f_opendir) was called. But it didn't work for ports that used synchronisation objects (_FS_REENTRANT) because they are only initialised via a call to f_mount. So, call f_mount explicitly when creating a new FatFS object so that everything is set up correctly. Then also provide a finaliser to do the f_umount call, but only if synchronisation objects are enabled (since otherwise the f_umount call does nothing).
1 parent ccaa5f5 commit 12ad64b

2 files changed

Lines changed: 27 additions & 8 deletions

File tree

extmod/vfs_fat.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,28 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_
6969
mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count);
7070
}
7171

72+
// mount the block device so the VFS methods can be used
73+
FRESULT res = f_mount(&vfs->fatfs);
74+
if (res == FR_NO_FILESYSTEM) {
75+
// don't error out if no filesystem, to let mkfs()/mount() create one if wanted
76+
vfs->flags |= FSUSER_NO_FILESYSTEM;
77+
} else if (res != FR_OK) {
78+
mp_raise_OSError(fresult_to_errno_table[res]);
79+
}
80+
7281
return MP_OBJ_FROM_PTR(vfs);
7382
}
7483

84+
#if _FS_REENTRANT
85+
STATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) {
86+
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in);
87+
// f_umount only needs to be called to release the sync object
88+
f_umount(&self->fatfs);
89+
return mp_const_none;
90+
}
91+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_del_obj, fat_vfs_del);
92+
#endif
93+
7594
STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {
7695
// create new object
7796
fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in));
@@ -291,33 +310,32 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs
291310
self->writeblocks[0] = MP_OBJ_NULL;
292311
}
293312

294-
// mount the block device
295-
FRESULT res = f_mount(&self->fatfs);
296-
297313
// check if we need to make the filesystem
314+
FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK;
298315
if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) {
299316
uint8_t working_buf[_MAX_SS];
300317
res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
301318
}
302319
if (res != FR_OK) {
303320
mp_raise_OSError(fresult_to_errno_table[res]);
304321
}
322+
self->flags &= ~FSUSER_NO_FILESYSTEM;
305323

306324
return mp_const_none;
307325
}
308326
STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount);
309327

310328
STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) {
311-
fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
312-
FRESULT res = f_umount(&self->fatfs);
313-
if (res != FR_OK) {
314-
mp_raise_OSError(fresult_to_errno_table[res]);
315-
}
329+
(void)self_in;
330+
// keep the FAT filesystem mounted internally so the VFS methods can still be used
316331
return mp_const_none;
317332
}
318333
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount);
319334

320335
STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
336+
#if _FS_REENTRANT
337+
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) },
338+
#endif
321339
{ MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) },
322340
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) },
323341
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) },

extmod/vfs_fat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#define FSUSER_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func
3636
#define FSUSER_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount
3737
#define FSUSER_HAVE_IOCTL (0x0004) // new protocol with ioctl
38+
#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it
3839

3940
typedef struct _fs_user_mount_t {
4041
mp_obj_base_t base;

0 commit comments

Comments
 (0)