Skip to content

Commit

Permalink
Make FAT filesystem thread safe
Browse files Browse the repository at this point in the history
Add lock and unlock calls to the FAT filesystem so it is thread safe.
  • Loading branch information
c1728p9 committed Jun 11, 2016
1 parent b174d6a commit 3d8d441
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 18 deletions.
26 changes: 24 additions & 2 deletions libraries/fs/fat/FATDirHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,22 @@

using namespace mbed;

FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir) {
FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir, PlatformMutex * mutex): _mutex(mutex) {
dir = the_dir;
}

int FATDirHandle::closedir() {
lock();
int retval = f_closedir(&dir);
unlock();
delete this;
return retval;
}

struct dirent *FATDirHandle::readdir() {
FILINFO finfo;

lock();
#if _USE_LFN
finfo.lfname = cur_entry.d_name;
finfo.lfsize = sizeof(cur_entry.d_name);
Expand All @@ -47,33 +50,52 @@ struct dirent *FATDirHandle::readdir() {

#if _USE_LFN
if(res != 0 || finfo.fname[0]==0) {
unlock();
return NULL;
} else {
if(cur_entry.d_name[0]==0) {
// No long filename so use short filename.
memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
}
unlock();
return &cur_entry;
}
#else
if(res != 0 || finfo.fname[0]==0) {
unlock();
return NULL;
} else {
memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
unlock();
return &cur_entry;
}
#endif /* _USE_LFN */
}

void FATDirHandle::rewinddir() {
lock();
dir.index = 0;
unlock();
}

off_t FATDirHandle::telldir() {
return dir.index;
lock();
off_t offset = dir.index;
unlock();
return offset;
}

void FATDirHandle::seekdir(off_t location) {
lock();
dir.index = location;
unlock();
}

void FATDirHandle::lock() {
_mutex->lock();
}

void FATDirHandle::unlock() {
_mutex->unlock();
}

10 changes: 9 additions & 1 deletion libraries/fs/fat/FATDirHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,27 @@
#define MBED_FATDIRHANDLE_H

#include "DirHandle.h"
#include "platform.h"

using namespace mbed;

class FATDirHandle : public DirHandle {

public:
FATDirHandle(const FATFS_DIR &the_dir);
FATDirHandle(const FATFS_DIR &the_dir, PlatformMutex * mutex);
virtual int closedir();
virtual struct dirent *readdir();
virtual void rewinddir();
virtual off_t telldir();
virtual void seekdir(off_t location);

protected:

virtual void lock();
virtual void unlock();

PlatformMutex * _mutex;

private:
FATFS_DIR dir;
struct dirent cur_entry;
Expand Down
29 changes: 27 additions & 2 deletions libraries/fs/fat/FATFileHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,42 @@

#include "FATFileHandle.h"

FATFileHandle::FATFileHandle(FIL fh) {
FATFileHandle::FATFileHandle(FIL fh, PlatformMutex * mutex): _mutex(mutex) {
_fh = fh;
}

int FATFileHandle::close() {
lock();
int retval = f_close(&_fh);
unlock();
delete this;
return retval;
}

ssize_t FATFileHandle::write(const void* buffer, size_t length) {
lock();
UINT n;
FRESULT res = f_write(&_fh, buffer, length, &n);
if (res) {
debug_if(FFS_DBG, "f_write() failed: %d", res);
unlock();
return -1;
}
unlock();
return n;
}

ssize_t FATFileHandle::read(void* buffer, size_t length) {
lock();
debug_if(FFS_DBG, "read(%d)\n", length);
UINT n;
FRESULT res = f_read(&_fh, buffer, length, &n);
if (res) {
debug_if(FFS_DBG, "f_read() failed: %d\n", res);
unlock();
return -1;
}
unlock();
return n;
}

Expand All @@ -61,6 +69,7 @@ int FATFileHandle::isatty() {
}

off_t FATFileHandle::lseek(off_t position, int whence) {
lock();
if (whence == SEEK_END) {
position += _fh.fsize;
} else if(whence==SEEK_CUR) {
Expand All @@ -69,22 +78,38 @@ off_t FATFileHandle::lseek(off_t position, int whence) {
FRESULT res = f_lseek(&_fh, position);
if (res) {
debug_if(FFS_DBG, "lseek failed: %d\n", res);
unlock();
return -1;
} else {
debug_if(FFS_DBG, "lseek OK, returning %i\n", _fh.fptr);
unlock();
return _fh.fptr;
}
}

int FATFileHandle::fsync() {
lock();
FRESULT res = f_sync(&_fh);
if (res) {
debug_if(FFS_DBG, "f_sync() failed: %d\n", res);
unlock();
return -1;
}
unlock();
return 0;
}

off_t FATFileHandle::flen() {
return _fh.fsize;
lock();
off_t size = _fh.fsize;
unlock();
return size;
}

void FATFileHandle::lock() {
_mutex->lock();
}

void FATFileHandle::unlock() {
_mutex->unlock();
}
7 changes: 6 additions & 1 deletion libraries/fs/fat/FATFileHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@
#define MBED_FATFILEHANDLE_H

#include "FileHandle.h"
#include "platform.h"

using namespace mbed;

class FATFileHandle : public FileHandle {
public:

FATFileHandle(FIL fh);
FATFileHandle(FIL fh, PlatformMutex * mutex);
virtual int close();
virtual ssize_t write(const void* buffer, size_t length);
virtual ssize_t read(void* buffer, size_t length);
Expand All @@ -40,7 +41,11 @@ class FATFileHandle : public FileHandle {

protected:

virtual void lock();
virtual void unlock();

FIL _fh;
PlatformMutex * _mutex;

};

Expand Down
67 changes: 61 additions & 6 deletions libraries/fs/fat/FATFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "FATFileSystem.h"
#include "FATFileHandle.h"
#include "FATDirHandle.h"
#include "critical.h"

DWORD get_fattime(void) {
time_t rawtime;
Expand All @@ -41,33 +42,55 @@ DWORD get_fattime(void) {
}

FATFileSystem *FATFileSystem::_ffs[_VOLUMES] = {0};
static PlatformMutex * mutex = NULL;

FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
PlatformMutex * get_fat_mutex() {
PlatformMutex * new_mutex = new PlatformMutex;

core_util_critical_section_enter();
if (NULL == mutex) {
mutex = new_mutex;
}
core_util_critical_section_exit();

if (mutex != new_mutex) {
delete new_mutex;
}
return mutex;
}

FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n), _mutex(get_fat_mutex()) {
lock();
debug_if(FFS_DBG, "FATFileSystem(%s)\n", n);
for(int i=0; i<_VOLUMES; i++) {
if(_ffs[i] == 0) {
_ffs[i] = this;
_fsid[0] = '0' + i;
_fsid[1] = '\0';
debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", _name, _fsid);
debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid);
f_mount(&_fs, _fsid, 0);
unlock();
return;
}
}
error("Couldn't create %s in FATFileSystem::FATFileSystem\n", n);
unlock();
}

FATFileSystem::~FATFileSystem() {
lock();
for (int i=0; i<_VOLUMES; i++) {
if (_ffs[i] == this) {
_ffs[i] = 0;
f_mount(NULL, _fsid, 0);
}
}
unlock();
}

FileHandle *FATFileSystem::open(const char* name, int flags) {
debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", name, _name, _fsid);
lock();
debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", name, getName(), _fsid);
char n[64];
sprintf(n, "%s:/%s", _fsid, name);

Expand All @@ -92,63 +115,95 @@ FileHandle *FATFileSystem::open(const char* name, int flags) {
FRESULT res = f_open(&fh, n, openmode);
if (res) {
debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
unlock();
return NULL;
}
if (flags & O_APPEND) {
f_lseek(&fh, fh.fsize);
}
return new FATFileHandle(fh);
FATFileHandle * handle = new FATFileHandle(fh, _mutex);
unlock();
return handle;
}

int FATFileSystem::remove(const char *filename) {
lock();
FRESULT res = f_unlink(filename);
if (res) {
debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
unlock();
return -1;
}
unlock();
return 0;
}

int FATFileSystem::rename(const char *oldname, const char *newname) {
lock();
FRESULT res = f_rename(oldname, newname);
if (res) {
debug_if(FFS_DBG, "f_rename() failed: %d\n", res);
unlock();
return -1;
}
unlock();
return 0;
}

int FATFileSystem::format() {
lock();
FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
if (res) {
debug_if(FFS_DBG, "f_mkfs() failed: %d\n", res);
unlock();
return -1;
}
unlock();
return 0;
}

DirHandle *FATFileSystem::opendir(const char *name) {
lock();
FATFS_DIR dir;
FRESULT res = f_opendir(&dir, name);
if (res != 0) {
unlock();
return NULL;
}
return new FATDirHandle(dir);
FATDirHandle *handle = new FATDirHandle(dir, _mutex);
unlock();
return handle;
}

int FATFileSystem::mkdir(const char *name, mode_t mode) {
lock();
FRESULT res = f_mkdir(name);
unlock();
return res == 0 ? 0 : -1;
}

int FATFileSystem::mount() {
lock();
FRESULT res = f_mount(&_fs, _fsid, 1);
unlock();
return res == 0 ? 0 : -1;
}

int FATFileSystem::unmount() {
if (disk_sync())
lock();
if (disk_sync()) {
unlock();
return -1;
}
FRESULT res = f_mount(NULL, _fsid, 0);
unlock();
return res == 0 ? 0 : -1;
}

void FATFileSystem::lock() {
_mutex->lock();
}

void FATFileSystem::unlock() {
_mutex->unlock();
}
Loading

0 comments on commit 3d8d441

Please sign in to comment.