Skip to content

Commit e77d57e

Browse files
committed
fatfs: Added erase disk to format
Right now, many users are trying out many different filesystems. Unfortunately, this can leave partially written filesystems on disk in various states. A very common pattern for using embedded filesystems is to attempt a mount, and on failure, format the storage with the filesystem. Unfortunately, this simply doesn't work if you try to change the filesystem being used on a piece of storage. Filesystems don't always use the same regions of storage, and can leave enough metadata lying around from old filesystems to trick a different mount into thinking a valid filesystem exists on disk. The filesystems we have were never designed to check for malicious modification and can't protect against arbitrary changes. That being said, it's caused enough problems for users, so as a workaround this patch adds a disk erase to the FAT filesystem format. The most common error happens when you use LittleFS, followed by FAT, followed again by LittleFS. No other combination of filesystem usage has shown a similar failure, but it is possible after extensive filesystem use, so it is still suggested to force a format of the storage when changing filesystems.
1 parent 16ab718 commit e77d57e

File tree

1 file changed

+62
-3
lines changed

1 file changed

+62
-3
lines changed

features/filesystem/fat/FATFileSystem.cpp

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,24 +333,83 @@ int FATFileSystem::unmount()
333333
int FATFileSystem::format(BlockDevice *bd, bd_size_t cluster_size)
334334
{
335335
FATFileSystem fs;
336-
int err = fs.mount(bd, false);
336+
fs.lock();
337+
338+
int err = bd->init();
339+
if (err) {
340+
fs.unlock();
341+
return err;
342+
}
343+
344+
// erase first handful of blocks
345+
bd_size_t header = 2*bd->get_erase_size();
346+
err = bd->erase(0, header);
337347
if (err) {
348+
bd->deinit();
349+
fs.unlock();
350+
return err;
351+
}
352+
353+
if (bd->get_erase_value() < 0) {
354+
// erase is unknown, need to write 1s
355+
bd_size_t program_size = bd->get_program_size();
356+
void *buf = malloc(program_size);
357+
if (!buf) {
358+
bd->deinit();
359+
fs.unlock();
360+
return -ENOMEM;
361+
}
362+
363+
memset(buf, 0xff, program_size);
364+
365+
for (bd_addr_t i = 0; i < header; i += program_size) {
366+
err = bd->program(buf, i, program_size);
367+
if (err) {
368+
free(buf);
369+
bd->deinit();
370+
fs.unlock();
371+
return err;
372+
}
373+
}
374+
375+
free(buf);
376+
}
377+
378+
// trim entire device to indicate it is unneeded
379+
err = bd->trim(0, bd->size());
380+
if (err) {
381+
bd->deinit();
382+
fs.unlock();
383+
return err;
384+
}
385+
386+
err = bd->deinit();
387+
if (err) {
388+
fs.unlock();
389+
return err;
390+
}
391+
392+
err = fs.mount(bd, false);
393+
if (err) {
394+
fs.unlock();
338395
return err;
339396
}
340397

341398
// Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
342-
fs.lock();
343399
FRESULT res = f_mkfs(fs._fsid, FM_ANY | FM_SFD, cluster_size, NULL, 0);
344-
fs.unlock();
345400
if (res != FR_OK) {
401+
fs.unmount();
402+
fs.unlock();
346403
return fat_error_remap(res);
347404
}
348405

349406
err = fs.unmount();
350407
if (err) {
408+
fs.unlock();
351409
return err;
352410
}
353411

412+
fs.unlock();
354413
return 0;
355414
}
356415

0 commit comments

Comments
 (0)