diff --git a/fs/littlefs/lfs_vfs.c b/fs/littlefs/lfs_vfs.c index 19e5792ec0..b8f8363a95 100644 --- a/fs/littlefs/lfs_vfs.c +++ b/fs/littlefs/lfs_vfs.c @@ -44,6 +44,12 @@ * Private Types ****************************************************************************/ +struct littlefs_file_s +{ + struct lfs_file file; + int refs; +}; + /* This structure represents the overall mountpoint state. An instance of * this structure is retained as inode private data on each mountpoint that * is mounted with a littlefs filesystem. @@ -224,7 +230,7 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; int ret; @@ -243,6 +249,8 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, return -ENOMEM; } + priv->refs = 1; + /* Take the semaphore */ ret = littlefs_semtake(fs); @@ -254,7 +262,7 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, /* Try to open the file */ oflags = littlefs_convert_oflags(oflags); - ret = lfs_file_open(&fs->lfs, priv, relpath, oflags); + ret = lfs_file_open(&fs->lfs, &priv->file, relpath, oflags); if (ret < 0) { /* Error opening file */ @@ -268,7 +276,7 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, if (oflags & LFS_O_APPEND) { - ret = lfs_file_seek(&fs->lfs, priv, 0, LFS_SEEK_END); + ret = lfs_file_seek(&fs->lfs, &priv->file, 0, LFS_SEEK_END); if (ret >= 0) { filep->f_pos = ret; @@ -283,8 +291,7 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, * e.g. total 8M, fileA 6M, O_TRUNC re-wrting fileA 6M, meet error. */ - lfs_file_sync(&fs->lfs, priv); - + lfs_file_sync(&fs->lfs, &priv->file); littlefs_semgive(fs); /* Attach the private date to the struct file instance */ @@ -293,7 +300,7 @@ static int littlefs_open(FAR struct file *filep, FAR const char *relpath, return OK; errout_with_file: - lfs_file_close(&fs->lfs, priv); + lfs_file_close(&fs->lfs, &priv->file); errout: littlefs_semgive(fs); errsem: @@ -308,7 +315,7 @@ errsem: static int littlefs_close(FAR struct file *filep) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; int ret; @@ -323,16 +330,20 @@ static int littlefs_close(FAR struct file *filep) ret = littlefs_semtake(fs); if (ret < 0) { - goto errsem; + return ret; + } + + if (--priv->refs <= 0) + { + lfs_file_close(&fs->lfs, &priv->file); } - lfs_file_close(&fs->lfs, priv); littlefs_semgive(fs); + if (priv->refs <= 0) + { + kmm_free(priv); + } - /* Now free the pointer */ - -errsem: - kmm_free(priv); return OK; } @@ -344,7 +355,7 @@ static ssize_t littlefs_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; ssize_t ret; @@ -362,14 +373,23 @@ static ssize_t littlefs_read(FAR struct file *filep, FAR char *buffer, return ret; } - ret = lfs_file_read(&fs->lfs, priv, buffer, buflen); + if (filep->f_pos != priv->file.pos) + { + ret = lfs_file_seek(&fs->lfs, &priv->file, filep->f_pos, LFS_SEEK_SET); + if (ret < 0) + { + goto out; + } + } + + ret = lfs_file_read(&fs->lfs, &priv->file, buffer, buflen); if (ret > 0) { filep->f_pos += ret; } +out: littlefs_semgive(fs); - return ret; } @@ -381,7 +401,7 @@ static ssize_t littlefs_write(FAR struct file *filep, const char *buffer, size_t buflen) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; ssize_t ret; @@ -399,14 +419,23 @@ static ssize_t littlefs_write(FAR struct file *filep, const char *buffer, return ret; } - ret = lfs_file_write(&fs->lfs, priv, buffer, buflen); + if (filep->f_pos != priv->file.pos) + { + ret = lfs_file_seek(&fs->lfs, &priv->file, filep->f_pos, LFS_SEEK_SET); + if (ret < 0) + { + goto out; + } + } + + ret = lfs_file_write(&fs->lfs, &priv->file, buffer, buflen); if (ret > 0) { filep->f_pos += ret; } +out: littlefs_semgive(fs); - return ret; } @@ -417,7 +446,7 @@ static ssize_t littlefs_write(FAR struct file *filep, const char *buffer, static off_t littlefs_seek(FAR struct file *filep, off_t offset, int whence) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; off_t ret; @@ -435,14 +464,13 @@ static off_t littlefs_seek(FAR struct file *filep, off_t offset, int whence) return ret; } - ret = lfs_file_seek(&fs->lfs, priv, offset, whence); + ret = lfs_file_seek(&fs->lfs, &priv->file, offset, whence); if (ret >= 0) { filep->f_pos = ret; } littlefs_semgive(fs); - return ret; } @@ -483,7 +511,7 @@ static int littlefs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) static int littlefs_sync(FAR struct file *filep) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; int ret; @@ -499,7 +527,7 @@ static int littlefs_sync(FAR struct file *filep) return ret; } - ret = lfs_file_sync(&fs->lfs, priv); + ret = lfs_file_sync(&fs->lfs, &priv->file); littlefs_semgive(fs); return ret; @@ -514,7 +542,28 @@ static int littlefs_sync(FAR struct file *filep) static int littlefs_dup(FAR const struct file *oldp, FAR struct file *newp) { - return -ENOSYS; + FAR struct littlefs_mountpt_s *fs; + FAR struct littlefs_file_s *priv; + FAR struct inode *inode; + int ret; + + /* Recover our private data from the struct file instance */ + + priv = oldp->f_priv; + inode = oldp->f_inode; + fs = inode->i_private; + + ret = littlefs_semtake(fs); + if (ret < 0) + { + return ret; + } + + priv->refs++; + newp->f_priv = priv; + littlefs_semgive(fs); + + return ret; } /**************************************************************************** @@ -529,7 +578,7 @@ static int littlefs_dup(FAR const struct file *oldp, FAR struct file *newp) static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; int ret; @@ -549,7 +598,7 @@ static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf) return ret; } - buf->st_size = lfs_file_size(&fs->lfs, priv); + buf->st_size = lfs_file_size(&fs->lfs, &priv->file); littlefs_semgive(fs); if (buf->st_size < 0) @@ -576,7 +625,7 @@ static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf) static int littlefs_truncate(FAR struct file *filep, off_t length) { FAR struct littlefs_mountpt_s *fs; - FAR struct lfs_file *priv; + FAR struct littlefs_file_s *priv; FAR struct inode *inode; int ret; @@ -594,7 +643,7 @@ static int littlefs_truncate(FAR struct file *filep, off_t length) return ret; } - ret = lfs_file_truncate(&fs->lfs, priv, length); + ret = lfs_file_truncate(&fs->lfs, &priv->file, length); littlefs_semgive(fs); return ret; @@ -680,13 +729,12 @@ static int littlefs_closedir(FAR struct inode *mountpt, ret = littlefs_semtake(fs); if (ret < 0) { - goto errsem; + return ret; } lfs_dir_close(&fs->lfs, priv); littlefs_semgive(fs); -errsem: kmm_free(priv); return OK; } @@ -740,7 +788,6 @@ static int littlefs_readdir(FAR struct inode *mountpt, } littlefs_semgive(fs); - return ret; } @@ -778,7 +825,6 @@ static int littlefs_rewinddir(FAR struct inode *mountpt, } littlefs_semgive(fs); - return ret; } @@ -1135,7 +1181,6 @@ static int littlefs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf) } littlefs_semgive(fs); - return ret; }