summaryrefslogtreecommitdiff
path: root/components/dfs
diff options
context:
space:
mode:
Diffstat (limited to 'components/dfs')
-rw-r--r--components/dfs/Kconfig34
-rw-r--r--components/dfs/dfs_v1/filesystems/devfs/devfs.c5
-rw-r--r--components/dfs/dfs_v1/filesystems/tmpfs/dfs_tmpfs.c4
-rw-r--r--components/dfs/dfs_v1/include/dfs_file.h6
-rw-r--r--components/dfs/dfs_v1/src/dfs_file.c2
-rw-r--r--components/dfs/dfs_v2/SConscript14
-rw-r--r--components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c148
-rw-r--r--components/dfs/dfs_v2/filesystems/mqueue/dfs_mqueue.c6
-rw-r--r--components/dfs/dfs_v2/filesystems/romfs/dfs_romfs.c4
-rw-r--r--components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c95
-rw-r--r--components/dfs/dfs_v2/include/dfs_file.h15
-rw-r--r--components/dfs/dfs_v2/include/dfs_mnt.h1
-rw-r--r--components/dfs/dfs_v2/include/dfs_pcache.h125
-rw-r--r--components/dfs/dfs_v2/include/dfs_seq_file.h69
-rw-r--r--components/dfs/dfs_v2/src/dfs_dentry.c4
-rw-r--r--components/dfs/dfs_v2/src/dfs_file.c93
-rw-r--r--components/dfs/dfs_v2/src/dfs_file_mmap.c443
-rw-r--r--components/dfs/dfs_v2/src/dfs_fs.c19
-rw-r--r--components/dfs/dfs_v2/src/dfs_mnt.c63
-rw-r--r--components/dfs/dfs_v2/src/dfs_pcache.c1439
-rw-r--r--components/dfs/dfs_v2/src/dfs_posix.c43
-rw-r--r--components/dfs/dfs_v2/src/dfs_seq_file.c494
-rw-r--r--components/dfs/dfs_v2/src/dfs_vnode.c17
23 files changed, 3045 insertions, 98 deletions
diff --git a/components/dfs/Kconfig b/components/dfs/Kconfig
index 33bfd3379b..9c0b1c88d5 100644
--- a/components/dfs/Kconfig
+++ b/components/dfs/Kconfig
@@ -193,6 +193,40 @@ if RT_USING_DFS_V1
endif
endif
+if RT_USING_DFS_V2
+ config RT_USING_PAGECACHE
+ bool "Enable page cache"
+ default n
+
+ if RT_USING_PAGECACHE
+ menu "page cache config"
+ config RT_PAGECACHE_COUNT
+ int "page cache max total pages."
+ default 4096
+
+ config RT_PAGECACHE_ASPACE_COUNT
+ int "aspace max active pages."
+ default 1024
+
+ config RT_PAGECACHE_PRELOAD
+ int "max pre load pages."
+ default 4
+
+ config RT_PAGECACHE_HASH_NR
+ int "page cache hash size."
+ default 1024
+
+ config RT_PAGECACHE_GC_WORK_LEVEL
+ int "page cache gc work trigger min percentage, default 90%."
+ default 90
+
+ config RT_PAGECACHE_GC_STOP_LEVEL
+ int "page cache gc to min percentage, default 70%."
+ default 70
+ endmenu
+ endif
+endif
+
endif
endmenu
diff --git a/components/dfs/dfs_v1/filesystems/devfs/devfs.c b/components/dfs/dfs_v1/filesystems/devfs/devfs.c
index 993f967131..cceb14150e 100644
--- a/components/dfs/dfs_v1/filesystems/devfs/devfs.c
+++ b/components/dfs/dfs_v1/filesystems/devfs/devfs.c
@@ -286,11 +286,10 @@ int dfs_device_fs_unlink(struct dfs_filesystem *fs, const char *path)
int dfs_device_fs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
{
+ st->st_dev = (dev_t)((size_t)dfs_filesystem_lookup(fs->path));
/* stat root directory */
if ((path[0] == '/') && (path[1] == '\0'))
{
- st->st_dev = 0;
-
st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH;
st->st_mode &= ~S_IFREG;
@@ -308,8 +307,6 @@ int dfs_device_fs_stat(struct dfs_filesystem *fs, const char *path, struct stat
dev_id = rt_device_find(&path[1]);
if (dev_id != RT_NULL)
{
- st->st_dev = 0;
-
st->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH;
diff --git a/components/dfs/dfs_v1/filesystems/tmpfs/dfs_tmpfs.c b/components/dfs/dfs_v1/filesystems/tmpfs/dfs_tmpfs.c
index e59721a714..c87be8239b 100644
--- a/components/dfs/dfs_v1/filesystems/tmpfs/dfs_tmpfs.c
+++ b/components/dfs/dfs_v1/filesystems/tmpfs/dfs_tmpfs.c
@@ -198,9 +198,11 @@ int dfs_tmpfs_ioctl(struct dfs_file *file, int cmd, void *args)
{
return -RT_ENOMEM;
}
+ else if (mmap2->lwp == RT_NULL)
+ return -RT_EINVAL;
LOG_D("tmpfile mmap ptr:%x , size:%d\n", d_file->data, mmap2->length);
- mmap2->ret = lwp_map_user_phy(lwp_self(), RT_NULL, d_file->data, mmap2->length, 0);
+ mmap2->ret = lwp_map_user_phy(mmap2->lwp, mmap2->addr, d_file->data, mmap2->length, 0);
}
return RT_EOK;
break;
diff --git a/components/dfs/dfs_v1/include/dfs_file.h b/components/dfs/dfs_v1/include/dfs_file.h
index d36b2ce89b..e125fb25ac 100644
--- a/components/dfs/dfs_v1/include/dfs_file.h
+++ b/components/dfs/dfs_v1/include/dfs_file.h
@@ -64,6 +64,7 @@ struct dfs_file
void *data; /* Specific fd data */
};
+#ifdef RT_USING_SMART
struct dfs_mmap2_args
{
void *addr;
@@ -72,8 +73,10 @@ struct dfs_mmap2_args
int flags;
off_t pgoffset;
+ struct rt_lwp *lwp;
void *ret;
};
+#endif
void dfs_vnode_mgr_init(void);
int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops *fops);
@@ -92,8 +95,9 @@ off_t dfs_file_lseek(struct dfs_file *fd, off_t offset);
int dfs_file_stat(const char *path, struct stat *buf);
int dfs_file_rename(const char *oldpath, const char *newpath);
int dfs_file_ftruncate(struct dfs_file *fd, off_t length);
+#ifdef RT_USING_SMART
int dfs_file_mmap2(struct dfs_file *fd, struct dfs_mmap2_args *mmap2);
-
+#endif
/* 0x5254 is just a magic number to make these relatively unique ("RT") */
#define RT_FIOFTRUNCATE 0x52540000U
#define RT_FIOGETADDR 0x52540001U
diff --git a/components/dfs/dfs_v1/src/dfs_file.c b/components/dfs/dfs_v1/src/dfs_file.c
index a22f7b3f31..acdc124f9a 100644
--- a/components/dfs/dfs_v1/src/dfs_file.c
+++ b/components/dfs/dfs_v1/src/dfs_file.c
@@ -713,6 +713,7 @@ int dfs_file_ftruncate(struct dfs_file *fd, off_t length)
return result;
}
+#ifdef RT_USING_SMART
int dfs_file_mmap2(struct dfs_file *fd, struct dfs_mmap2_args *mmap2)
{
int ret = 0;
@@ -736,6 +737,7 @@ int dfs_file_mmap2(struct dfs_file *fd, struct dfs_mmap2_args *mmap2)
return ret;
}
+#endif
#ifdef RT_USING_FINSH
#include <finsh.h>
diff --git a/components/dfs/dfs_v2/SConscript b/components/dfs/dfs_v2/SConscript
index a8f2811a18..ae7432f71a 100644
--- a/components/dfs/dfs_v2/SConscript
+++ b/components/dfs/dfs_v2/SConscript
@@ -2,20 +2,12 @@ from building import *
import os
# The set of source files associated with this SConscript file.
-src = Split('''
-src/dfs.c
-src/dfs_file.c
-src/dfs_fs.c
-src/dfs_dentry.c
-src/dfs_vnode.c
-src/dfs_mnt.c
-src/dfs_posix.c
-''')
+src = Glob('src/*.c') + Glob('src/*.cpp')
cwd = GetCurrentDir()
CPPPATH = [cwd + "/include"]
-if GetDepend('RT_USING_POSIX'):
- src += ['src/poll.c', 'src/select.c']
+if not GetDepend('RT_USING_SMART'):
+ SrcRemove(src, ['src/dfs_file_mmap.c'])
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_V2'], CPPPATH = CPPPATH)
diff --git a/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c b/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c
index c6281c55b7..c453058d72 100644
--- a/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c
+++ b/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c
@@ -32,6 +32,24 @@
#include <dfs_file.h>
#include <dfs_mnt.h>
+#ifdef RT_USING_PAGECACHE
+#include "dfs_pcache.h"
+#endif
+
+
+static int dfs_elm_free_vnode(struct dfs_vnode *vnode);
+
+#ifdef RT_USING_PAGECACHE
+static ssize_t dfs_elm_page_read(struct dfs_file *file, struct dfs_page *page);
+static ssize_t dfs_elm_page_write(struct dfs_page *page);
+
+static struct dfs_aspace_ops dfs_elm_aspace_ops =
+{
+ .read = dfs_elm_page_read,
+ .write = dfs_elm_page_write,
+};
+#endif
+
#undef SS
#if FF_MAX_SS == FF_MIN_SS
#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */
@@ -361,7 +379,7 @@ int dfs_elm_open(struct dfs_file *file)
extern int elm_get_vol(FATFS * fat);
RT_ASSERT(file->vnode->ref_count > 0);
- if (file->vnode->ref_count > 1)
+ if (file->vnode->data)
{
if (file->vnode->type == FT_DIRECTORY
&& !(file->flags & O_DIRECTORY))
@@ -425,6 +443,7 @@ int dfs_elm_open(struct dfs_file *file)
}
file->vnode->data = dir;
+ rt_mutex_init(&file->vnode->lock, file->dentry->pathname, RT_IPC_FLAG_PRIO);
return RT_EOK;
}
else
@@ -465,6 +484,7 @@ int dfs_elm_open(struct dfs_file *file)
file->vnode->size = f_size(fd);
file->vnode->type = FT_REGULAR;
file->vnode->data = fd;
+ rt_mutex_init(&file->vnode->lock, file->dentry->pathname, RT_IPC_FLAG_PRIO);
if (file->flags & O_APPEND)
{
@@ -516,6 +536,9 @@ int dfs_elm_close(struct dfs_file *file)
rt_free(fd);
}
+ file->vnode->data = RT_NULL;
+ rt_mutex_detach(&file->vnode->lock);
+
return elm_result_to_dfs(result);
}
@@ -558,7 +581,7 @@ int dfs_elm_ioctl(struct dfs_file *file, int cmd, void *args)
ssize_t dfs_elm_read(struct dfs_file *file, void *buf, size_t len, off_t *pos)
{
FIL *fd;
- FRESULT result;
+ FRESULT result = FR_OK;
UINT byte_read;
if (file->vnode->type == FT_DIRECTORY)
@@ -566,14 +589,19 @@ ssize_t dfs_elm_read(struct dfs_file *file, void *buf, size_t len, off_t *pos)
return -EISDIR;
}
- fd = (FIL *)(file->vnode->data);
- RT_ASSERT(fd != RT_NULL);
-
- result = f_read(fd, buf, len, &byte_read);
- /* update position */
- *pos = fd->fptr;
- if (result == FR_OK)
- return byte_read;
+ if (file->vnode->size > *pos)
+ {
+ fd = (FIL *)(file->vnode->data);
+ RT_ASSERT(fd != RT_NULL);
+ rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
+ f_lseek(fd, *pos);
+ result = f_read(fd, buf, len, &byte_read);
+ /* update position */
+ *pos = fd->fptr;
+ rt_mutex_release(&file->vnode->lock);
+ if (result == FR_OK)
+ return byte_read;
+ }
return elm_result_to_dfs(result);
}
@@ -591,11 +619,13 @@ ssize_t dfs_elm_write(struct dfs_file *file, const void *buf, size_t len, off_t
fd = (FIL *)(file->vnode->data);
RT_ASSERT(fd != RT_NULL);
-
+ rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
+ f_lseek(fd, *pos);
result = f_write(fd, buf, len, &byte_write);
/* update position and file size */
*pos = fd->fptr;
file->vnode->size = f_size(fd);
+ rt_mutex_release(&file->vnode->lock);
if (result == FR_OK)
return byte_write;
@@ -642,8 +672,9 @@ off_t dfs_elm_lseek(struct dfs_file *file, off_t offset, int wherece)
/* regular file type */
fd = (FIL *)(file->vnode->data);
RT_ASSERT(fd != RT_NULL);
-
+ rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
result = f_lseek(fd, offset);
+ rt_mutex_release(&file->vnode->lock);
if (result == FR_OK)
{
/* return current position */
@@ -657,8 +688,9 @@ off_t dfs_elm_lseek(struct dfs_file *file, off_t offset, int wherece)
dir = (DIR *)(file->vnode->data);
RT_ASSERT(dir != RT_NULL);
-
+ rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
result = f_seekdir(dir, offset / sizeof(struct dirent));
+ rt_mutex_release(&file->vnode->lock);
if (result == FR_OK)
{
/* update file position */
@@ -827,21 +859,35 @@ int dfs_elm_stat(struct dfs_dentry *dentry, struct stat *st)
st->st_dev = (dev_t)(size_t)(dentry->mnt->dev_id);
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
- st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
- S_IWUSR | S_IWGRP | S_IWOTH;
if (file_info.fattrib & AM_DIR)
{
- st->st_mode &= ~S_IFREG;
- st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ st->st_mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ }
+ else
+ {
+ st->st_mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
}
+
if (file_info.fattrib & AM_RDO)
st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
- st->st_size = file_info.fsize;
+ if (S_IFDIR & st->st_mode)
+ {
+ st->st_size = file_info.fsize;
+ }
+ else
+ {
+#ifdef RT_USING_PAGECACHE
+ st->st_size = (dentry->vnode && dentry->vnode->aspace) ? dentry->vnode->size : file_info.fsize;
+#else
+ st->st_size = file_info.fsize;
+#endif
+ }
+
st->st_blksize = fat->csize * SS(fat);
if (file_info.fattrib & AM_ARC)
{
- st->st_blocks = file_info.fsize ? ((file_info.fsize - 1) / SS(fat) / fat->csize + 1) : 0;
+ st->st_blocks = st->st_size ? ((st->st_size - 1) / SS(fat) / fat->csize + 1) : 0;
st->st_blocks *= (st->st_blksize / 512); // man say st_blocks is number of 512B blocks allocated
}
else
@@ -901,20 +947,23 @@ static struct dfs_vnode *dfs_elm_lookup(struct dfs_dentry *dentry)
vnode = dfs_vnode_create();
if (vnode)
{
+ vnode->mnt = dentry->mnt;
+ vnode->size = st.st_size;
+ vnode->data = NULL;
+
if (S_ISDIR(st.st_mode))
{
- vnode->mode = S_IFDIR | (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
vnode->type = FT_DIRECTORY;
}
else
{
- vnode->mode = S_IFREG | S_IXUSR | (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
vnode->type = FT_REGULAR;
+#ifdef RT_USING_PAGECACHE
+ vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_elm_aspace_ops);
+#endif
}
-
- vnode->mnt = dentry->mnt;
- vnode->data = NULL;
- vnode->size = 0;
}
return vnode;
@@ -934,13 +983,18 @@ static struct dfs_vnode *dfs_elm_create_vnode(struct dfs_dentry *dentry, int typ
{
if (type == FT_DIRECTORY)
{
- vnode->mode = S_IFDIR | mode;
+ /* fat directory force mode 0555 */
+ vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
vnode->type = FT_DIRECTORY;
}
else
{
- vnode->mode = S_IFREG | mode;
+ /* fat REGULAR file mode force mode 0777 */
+ vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
vnode->type = FT_REGULAR;
+#ifdef RT_USING_PAGECACHE
+ vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_elm_aspace_ops);
+#endif
}
vnode->mnt = dentry->mnt;
@@ -962,6 +1016,46 @@ static int dfs_elm_free_vnode(struct dfs_vnode *vnode)
return 0;
}
+#ifdef RT_USING_PAGECACHE
+static ssize_t dfs_elm_page_read(struct dfs_file *file, struct dfs_page *page)
+{
+ int ret = -EINVAL;
+
+ if (page->page)
+ {
+ off_t fpos = page->fpos;
+ ret = dfs_elm_read(file, page->page, page->size, &fpos);
+ }
+
+ return ret;
+}
+
+ssize_t dfs_elm_page_write(struct dfs_page *page)
+{
+ FIL *fd;
+ FRESULT result;
+ UINT byte_write;
+
+ if (page->aspace->vnode->type == FT_DIRECTORY)
+ {
+ return -EISDIR;
+ }
+
+ fd = (FIL *)(page->aspace->vnode->data);
+ RT_ASSERT(fd != RT_NULL);
+ rt_mutex_take(&page->aspace->vnode->lock, RT_WAITING_FOREVER);
+ f_lseek(fd, page->fpos);
+ result = f_write(fd, page->page, page->len, &byte_write);
+ rt_mutex_release(&page->aspace->vnode->lock);
+ if (result == FR_OK)
+ {
+ return byte_write;
+ }
+
+ return elm_result_to_dfs(result);
+}
+#endif
+
static const struct dfs_file_ops dfs_elm_fops =
{
.open = dfs_elm_open,
diff --git a/components/dfs/dfs_v2/filesystems/mqueue/dfs_mqueue.c b/components/dfs/dfs_v2/filesystems/mqueue/dfs_mqueue.c
index 13719f386a..0bc61c635c 100644
--- a/components/dfs/dfs_v2/filesystems/mqueue/dfs_mqueue.c
+++ b/components/dfs/dfs_v2/filesystems/mqueue/dfs_mqueue.c
@@ -149,7 +149,7 @@ static struct dfs_vnode *dfs_mqueue_create_vnode(struct dfs_dentry *dentry, int
dfs_mqueue_insert_after(&(mq_file->list));
}
- vnode->mode = S_IFREG | mode;
+ vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
vnode->type = FT_REGULAR;
rt_mq_t mq = rt_mq_create(dentry->pathname + 1, mq_file->msg_size, mq_file->max_msgs,
RT_IPC_FLAG_FIFO);
@@ -191,7 +191,7 @@ struct dfs_vnode *_dfs_mqueue_lookup(struct dfs_dentry *dentry) {
vnode = dfs_vnode_create();
if (mq_file && mq_file->data) {
- vnode->mode = S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR;
+ vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
vnode->type = FT_REGULAR;
vnode->mnt = dentry->mnt;
vnode->data = mq_file;
@@ -202,7 +202,7 @@ struct dfs_vnode *_dfs_mqueue_lookup(struct dfs_dentry *dentry) {
vnode->fops = &_mqueue_fops;
vnode->mnt = dentry->mnt;
vnode->type = FT_DIRECTORY;
- vnode->mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
+ vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
}
return vnode;
}
diff --git a/components/dfs/dfs_v2/filesystems/romfs/dfs_romfs.c b/components/dfs/dfs_v2/filesystems/romfs/dfs_romfs.c
index 81382ae69b..43db9b6ec3 100644
--- a/components/dfs/dfs_v2/filesystems/romfs/dfs_romfs.c
+++ b/components/dfs/dfs_v2/filesystems/romfs/dfs_romfs.c
@@ -191,12 +191,12 @@ static struct dfs_vnode *dfs_romfs_lookup (struct dfs_dentry *dentry)
vnode->size = dirent->size;
if (dirent->type == ROMFS_DIRENT_DIR)
{
- vnode->mode = romfs_modemap[ROMFS_DIRENT_DIR] | S_IRUSR;
+ vnode->mode = romfs_modemap[ROMFS_DIRENT_DIR] | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
vnode->type = FT_DIRECTORY;
}
else if (dirent->type == ROMFS_DIRENT_FILE)
{
- vnode->mode = romfs_modemap[ROMFS_DIRENT_FILE] | S_IRUSR | S_IXUSR;
+ vnode->mode = romfs_modemap[ROMFS_DIRENT_FILE] | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
vnode->type = FT_REGULAR;
}
diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c
index 3db3823926..36d1ea692b 100644
--- a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c
+++ b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c
@@ -28,6 +28,20 @@
#define DBG_TAG "tmpfs"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
+#ifdef RT_USING_PAGECACHE
+#include "dfs_pcache.h"
+#endif
+
+#ifdef RT_USING_PAGECACHE
+static ssize_t dfs_tmp_page_read(struct dfs_file *file, struct dfs_page *page);
+static ssize_t dfs_tmp_page_write(struct dfs_page *page);
+
+static struct dfs_aspace_ops dfs_tmp_aspace_ops =
+{
+ .read = dfs_tmp_page_read,
+ .write = dfs_tmp_page_write,
+};
+#endif
static int _path_separate(const char *path, char *parent_path, char *file_name)
{
@@ -285,6 +299,8 @@ static ssize_t dfs_tmpfs_read(struct dfs_file *file, void *buf, size_t count, of
d_file = (struct tmpfs_file *)file->vnode->data;
RT_ASSERT(d_file != NULL);
+ rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
+
if (count < file->vnode->size - *pos)
length = count;
else
@@ -296,6 +312,8 @@ static ssize_t dfs_tmpfs_read(struct dfs_file *file, void *buf, size_t count, of
/* update file current position */
*pos += length;
+ rt_mutex_release(&file->vnode->lock);
+
return length;
}
@@ -310,12 +328,15 @@ static ssize_t dfs_tmpfs_write(struct dfs_file *file, const void *buf, size_t co
superblock = d_file->sb;
RT_ASSERT(superblock != NULL);
+ rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
+
if (count + *pos > file->vnode->size)
{
rt_uint8_t *ptr;
ptr = rt_realloc(d_file->data, *pos + count);
if (ptr == NULL)
{
+ rt_mutex_release(&file->vnode->lock);
rt_set_errno(-ENOMEM);
return 0;
}
@@ -335,6 +356,7 @@ static ssize_t dfs_tmpfs_write(struct dfs_file *file, const void *buf, size_t co
/* update file current position */
*pos += count;
+ rt_mutex_release(&file->vnode->lock);
return count;
}
@@ -371,6 +393,7 @@ static int dfs_tmpfs_close(struct dfs_file *file)
struct tmpfs_file *d_file;
RT_ASSERT(file->vnode->ref_count > 0);
+
if (file->vnode->ref_count != 1)
return 0;
@@ -390,6 +413,8 @@ static int dfs_tmpfs_close(struct dfs_file *file)
rt_free(d_file);
}
+ rt_mutex_detach(&file->vnode->lock);
+
return RT_EOK;
}
@@ -424,6 +449,12 @@ static int dfs_tmpfs_open(struct dfs_file *file)
file->fpos = 0;
}
+ RT_ASSERT(file->vnode->ref_count > 0);
+ if(file->vnode->ref_count == 1)
+ {
+ rt_mutex_init(&file->vnode->lock, file->dentry->pathname, RT_IPC_FLAG_PRIO);
+ }
+
return 0;
}
@@ -442,12 +473,13 @@ static int dfs_tmpfs_stat(struct dfs_dentry *dentry, struct stat *st)
st->st_dev = (dev_t)(size_t)(dentry->mnt->dev_id);
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
- st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
- S_IWUSR | S_IWGRP | S_IWOTH;
if (d_file->type == TMPFS_TYPE_DIR)
{
- st->st_mode &= ~S_IFREG;
- st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+ st->st_mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ }
+ else
+ {
+ st->st_mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
}
st->st_size = d_file->size;
@@ -468,13 +500,18 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
d_file = (struct tmpfs_file *)file->vnode->data;
+ rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
+
superblock = d_file->sb;
RT_ASSERT(superblock != RT_NULL);
/* make integer count */
count = (count / sizeof(struct dirent));
if (count == 0)
+ {
+ rt_mutex_release(&file->vnode->lock);
return -EINVAL;
+ }
end = file->fpos + count;
index = 0;
@@ -507,6 +544,7 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
break;
}
}
+ rt_mutex_release(&file->vnode->lock);
return count * sizeof(struct dirent);
}
@@ -607,13 +645,16 @@ static struct dfs_vnode *_dfs_tmpfs_lookup(struct dfs_dentry *dentry)
{
if (d_file->type == TMPFS_TYPE_DIR)
{
- vnode->mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
+ vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
vnode->type = FT_DIRECTORY;
}
else
{
- vnode->mode = S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR;
+ vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
vnode->type = FT_REGULAR;
+#ifdef RT_USING_PAGECACHE
+ vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_tmp_aspace_ops);
+#endif
}
vnode->mnt = dentry->mnt;
@@ -681,14 +722,17 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
if (type == FT_DIRECTORY)
{
d_file->type = TMPFS_TYPE_DIR;
- vnode->mode = S_IFDIR | mode;
+ vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
vnode->type = FT_DIRECTORY;
}
else
{
d_file->type = TMPFS_TYPE_FILE;
- vnode->mode = S_IFREG | mode;
+ vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
vnode->type = FT_REGULAR;
+#ifdef RT_USING_PAGECACHE
+ vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_tmp_aspace_ops);
+#endif
}
rt_spin_lock(&superblock->lock);
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
@@ -713,6 +757,41 @@ static int dfs_tmpfs_free_vnode(struct dfs_vnode *vnode)
return 0;
}
+#ifdef RT_USING_PAGECACHE
+static ssize_t dfs_tmp_page_read(struct dfs_file *file, struct dfs_page *page)
+{
+ int ret = -EINVAL;
+
+ if (page->page)
+ {
+ off_t fpos = page->fpos;
+ ret = dfs_tmpfs_read(file, page->page, page->size, &fpos);
+ }
+
+ return ret;
+}
+
+ssize_t dfs_tmp_page_write(struct dfs_page *page)
+{
+ struct tmpfs_file *d_file;
+
+ if (page->aspace->vnode->type == FT_DIRECTORY)
+ {
+ return -EISDIR;
+ }
+
+ d_file = (struct tmpfs_file *)(page->aspace->vnode->data);
+ RT_ASSERT(d_file != RT_NULL);
+ rt_mutex_take(&page->aspace->vnode->lock, RT_WAITING_FOREVER);
+ if (page->len > 0)
+ memcpy(d_file->data + page->fpos, page->page, page->len);
+
+ rt_mutex_release(&page->aspace->vnode->lock);
+
+ return F_OK;
+}
+#endif
+
static int dfs_tmpfs_truncate(struct dfs_file *file, off_t offset)
{
struct tmpfs_file *d_file = RT_NULL;
diff --git a/components/dfs/dfs_v2/include/dfs_file.h b/components/dfs/dfs_v2/include/dfs_file.h
index bb6551c8eb..4486401333 100644
--- a/components/dfs/dfs_v2/include/dfs_file.h
+++ b/components/dfs/dfs_v2/include/dfs_file.h
@@ -33,6 +33,7 @@ struct rt_pollreq;
struct dirent;
struct lwp_avl_struct;
struct file_lock;
+struct dfs_aspace;
struct dfs_file_ops
{
@@ -73,6 +74,9 @@ struct dfs_vnode
struct timespec mtime;
struct timespec ctime;
+ struct dfs_aspace *aspace;
+ struct rt_mutex lock;
+
void *data; /* private data of this file system */
};
@@ -93,6 +97,8 @@ struct dfs_file
struct dfs_dentry *dentry; /* dentry of this file */
struct dfs_vnode *vnode; /* vnode of this file */
+ void *mmap_context; /* used by mmap routine */
+
void *data;
};
@@ -122,7 +128,7 @@ struct dfs_vnode *dfs_vnode_ref(struct dfs_vnode *vnode);
void dfs_vnode_unref(struct dfs_vnode *vnode);
/*dfs_file.c*/
-
+#ifdef RT_USING_SMART
struct dfs_mmap2_args
{
void *addr;
@@ -131,8 +137,10 @@ struct dfs_mmap2_args
int flags;
off_t pgoffset;
+ struct rt_lwp *lwp;
void *ret;
};
+#endif
void dfs_file_init(struct dfs_file *file);
void dfs_file_deinit(struct dfs_file *file);
@@ -166,8 +174,13 @@ int dfs_file_isdir(const char *path);
int dfs_file_access(const char *path, mode_t mode);
int dfs_file_chdir(const char *path);
char *dfs_file_getcwd(char *buf, size_t size);
+
+#ifdef RT_USING_SMART
int dfs_file_mmap2(struct dfs_file *file, struct dfs_mmap2_args *mmap2);
+int dfs_file_mmap(struct dfs_file *file, struct dfs_mmap2_args *mmap2);
+#endif
+
/* 0x5254 is just a magic number to make these relatively unique ("RT") */
#define RT_FIOFTRUNCATE 0x52540000U
#define RT_FIOGETADDR 0x52540001U
diff --git a/components/dfs/dfs_v2/include/dfs_mnt.h b/components/dfs/dfs_v2/include/dfs_mnt.h
index 0d73051868..207c9b6bfd 100644
--- a/components/dfs/dfs_v2/include/dfs_mnt.h
+++ b/components/dfs/dfs_v2/include/dfs_mnt.h
@@ -53,6 +53,7 @@ int dfs_mnt_destroy(struct dfs_mnt* mnt);
int dfs_mnt_list(struct dfs_mnt* mnt);
int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child);
+struct dfs_mnt *dfs_mnt_dev_lookup(rt_device_t dev_id);
struct dfs_mnt *dfs_mnt_lookup(const char *path);
const char *dfs_mnt_get_mounted_path(struct rt_device *device);
diff --git a/components/dfs/dfs_v2/include/dfs_pcache.h b/components/dfs/dfs_v2/include/dfs_pcache.h
new file mode 100644
index 0000000000..356df6c4f9
--- /dev/null
+++ b/components/dfs/dfs_v2/include/dfs_pcache.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-05-05 RTT Implement dentry in dfs v2.0
+ */
+
+#ifndef DFS_PAGE_CACHE_H__
+#define DFS_PAGE_CACHE_H__
+
+#include <rtthread.h>
+
+#ifdef RT_USING_PAGECACHE
+
+#include <dfs_file.h>
+#include <avl.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct dfs_vnode;
+struct dfs_dentry;
+struct dfs_aspace;
+
+struct dfs_mmap
+{
+ rt_list_t mmap_node;
+ struct rt_varea *varea;
+};
+
+struct dfs_page
+{
+ rt_list_t space_node;
+ rt_list_t dirty_node;
+ struct util_avl_struct avl_node;
+ rt_list_t mmap_head;
+
+ rt_atomic_t ref_count;
+
+ void *page;
+ off_t fpos;
+ size_t size;
+ size_t len;
+ int is_dirty;
+ rt_tick_t tick_ms;
+
+ struct dfs_aspace *aspace;
+};
+
+struct dfs_aspace_ops
+{
+ ssize_t (*read)(struct dfs_file *file, struct dfs_page *page);
+ ssize_t (*write)(struct dfs_page *page);
+};
+
+struct dfs_aspace
+{
+ rt_list_t hash_node, cache_node;
+ char *fullpath, *pathname;
+ struct dfs_mnt *mnt;
+
+ rt_list_t list_active, list_inactive;
+ rt_list_t list_dirty;
+ size_t pages_count;
+
+ struct util_avl_root avl_root;
+ struct dfs_page *avl_page;
+
+ rt_bool_t is_active;
+
+ struct rt_mutex lock;
+ rt_atomic_t ref_count;
+
+ struct dfs_vnode *vnode;
+ const struct dfs_aspace_ops *ops;
+};
+
+#ifndef RT_PAGECACHE_HASH_NR
+#define RT_PAGECACHE_HASH_NR 1024
+#endif
+
+struct dfs_pcache
+{
+ rt_list_t head[RT_PAGECACHE_HASH_NR];
+ rt_list_t list_active, list_inactive;
+ rt_atomic_t pages_count;
+ struct rt_mutex lock;
+ struct rt_messagequeue *mqueue;
+ rt_tick_t last_time_wb;
+};
+
+struct dfs_aspace *dfs_aspace_create(struct dfs_dentry *dentry, struct dfs_vnode *vnode, const struct dfs_aspace_ops *ops);
+int dfs_aspace_destroy(struct dfs_aspace *aspace);
+
+int dfs_aspace_read(struct dfs_file *file, void *buf, size_t count, off_t *pos);
+int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos);
+int dfs_aspace_flush(struct dfs_aspace *aspace);
+int dfs_aspace_clean(struct dfs_aspace *aspace);
+
+void *dfs_aspace_mmap(struct dfs_file *file, struct rt_varea *varea, void *vaddr);
+int dfs_aspace_unmap(struct dfs_file *file, struct rt_varea *varea);
+int dfs_aspace_page_unmap(struct dfs_file *file, struct rt_varea *varea, void *vaddr);
+int dfs_aspace_page_dirty(struct dfs_file *file, struct rt_varea *varea, void *vaddr);
+
+off_t dfs_aspace_fpos(struct rt_varea *varea, void *vaddr);
+void *dfs_aspace_vaddr(struct rt_varea *varea, off_t fpos);
+
+int dfs_aspace_mmap_read(struct dfs_file *file, struct rt_varea *varea, void *data);
+int dfs_aspace_mmap_write(struct dfs_file *file, struct rt_varea *varea, void *data);
+
+void dfs_pcache_release(size_t count);
+void dfs_pcache_unmount(struct dfs_mnt *mnt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
diff --git a/components/dfs/dfs_v2/include/dfs_seq_file.h b/components/dfs/dfs_v2/include/dfs_seq_file.h
new file mode 100644
index 0000000000..6dbc30f24d
--- /dev/null
+++ b/components/dfs/dfs_v2/include/dfs_seq_file.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#ifndef __DFS_SEQ_FILE_H__
+#define __DFS_SEQ_FILE_H__
+
+#include <dfs.h>
+#include <dfs_fs.h>
+
+struct dfs_seq_ops;
+
+struct dfs_seq_file
+{
+ char *buf;
+ size_t size;
+ size_t from;
+ size_t count;
+ size_t pad_until;
+ off_t index;
+ off_t read_pos;
+ struct rt_mutex lock;
+ const struct dfs_seq_ops *ops;
+ const struct dfs_file *file;
+ void *data;
+};
+
+struct dfs_seq_ops
+{
+ void *(*start)(struct dfs_seq_file *seq, off_t *index);
+ void (*stop)(struct dfs_seq_file *seq, void *data);
+ void *(*next)(struct dfs_seq_file *seq, void *data, off_t *index);
+ int (*show)(struct dfs_seq_file *seq, void *data);
+};
+
+/**
+ * check if the buffer is full
+ */
+static inline rt_bool_t dfs_seq_is_full(struct dfs_seq_file *seq)
+{
+ return seq->count == seq->size;
+}
+
+/**
+ * set padding width size
+ */
+static inline void dfs_seq_setwidth(struct dfs_seq_file *seq, size_t size)
+{
+ seq->pad_until = seq->count + size;
+}
+
+int dfs_seq_open(struct dfs_file *file, const struct dfs_seq_ops *ops);
+ssize_t dfs_seq_read(struct dfs_file *file, void *buf, size_t size, off_t *pos);
+ssize_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence);
+int dfs_seq_release(struct dfs_file *file);
+int dfs_seq_write(struct dfs_seq_file *seq, const void *data, size_t len);
+
+void dfs_seq_vprintf(struct dfs_seq_file *seq, const char *fmt, va_list args);
+void dfs_seq_printf(struct dfs_seq_file *seq, const char *fmt, ...);
+void dfs_seq_putc(struct dfs_seq_file *seq, char c);
+void dfs_seq_puts(struct dfs_seq_file *seq, const char *s);
+void dfs_seq_pad(struct dfs_seq_file *seq, char c);
+
+#endif
diff --git a/components/dfs/dfs_v2/src/dfs_dentry.c b/components/dfs/dfs_v2/src/dfs_dentry.c
index 6605f094f2..27054b1af5 100644
--- a/components/dfs/dfs_v2/src/dfs_dentry.c
+++ b/components/dfs/dfs_v2/src/dfs_dentry.c
@@ -197,7 +197,7 @@ struct dfs_dentry *dfs_dentry_lookup(struct dfs_mnt *mnt, const char *path, uint
path = "/";
}
}
-
+ dfs_file_lock();
dentry = _dentry_hash_lookup(mnt, path);
if (!dentry)
{
@@ -252,7 +252,7 @@ struct dfs_dentry *dfs_dentry_lookup(struct dfs_mnt *mnt, const char *path, uint
{
DLOG(note, "dentry", "found dentry");
}
-
+ dfs_file_unlock();
return dentry;
}
diff --git a/components/dfs/dfs_v2/src/dfs_file.c b/components/dfs/dfs_v2/src/dfs_file.c
index 544e38bc61..a7baa9323f 100644
--- a/components/dfs/dfs_v2/src/dfs_file.c
+++ b/components/dfs/dfs_v2/src/dfs_file.c
@@ -19,6 +19,10 @@
#include "dfs_mnt.h"
#include "dfs_private.h"
+#ifdef RT_USING_PAGECACHE
+#include "dfs_pcache.h"
+#endif
+
#define DBG_TAG "DFS.file"
#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
@@ -114,7 +118,7 @@ static void dfs_file_unref(struct dfs_file *file)
{
if (file->vnode->ref_count > 1)
{
- file->vnode->ref_count--;
+ rt_atomic_sub(&(file->vnode->ref_count), 1);
}
else if (file->vnode->ref_count == 1)
{
@@ -448,6 +452,7 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo
struct dfs_vnode *vnode = RT_NULL;
DLOG(msg, "dfs_file", "dentry", DLOG_MSG, "dfs_dentry_create(%s)", fullpath);
+ dfs_file_lock();
dentry = dfs_dentry_create(mnt, fullpath);
if (dentry)
{
@@ -472,6 +477,7 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo
dentry = RT_NULL;
}
}
+ dfs_file_unlock();
}
}
}
@@ -518,7 +524,9 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo
if (dfs_is_mounted(file->vnode->mnt) == 0)
{
+ dfs_file_lock();
ret = file->fops->open(file);
+ dfs_file_unlock();
}
else
{
@@ -572,6 +580,12 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo
if (dfs_is_mounted(file->vnode->mnt) == 0)
{
+#ifdef RT_USING_PAGECACHE
+ if (file->vnode->aspace)
+ {
+ dfs_aspace_clean(file->vnode->aspace);
+ }
+#endif
ret = file->fops->truncate(file, 0);
}
else
@@ -612,7 +626,12 @@ int dfs_file_close(struct dfs_file *file)
if (ref_count == 1 && file->fops && file->fops->close)
{
DLOG(msg, "dfs_file", file->dentry->mnt->fs_ops->name, DLOG_MSG, "fops->close(file)");
-
+#ifdef RT_USING_PAGECACHE
+ if (file->vnode->aspace)
+ {
+ dfs_aspace_flush(file->vnode->aspace);
+ }
+#endif
ret = file->fops->close(file);
if (ret == 0) /* close file sucessfully */
@@ -665,7 +684,16 @@ ssize_t dfs_file_read(struct dfs_file *file, void *buf, size_t len)
if (dfs_is_mounted(file->vnode->mnt) == 0)
{
- ret = file->fops->read(file, buf, len, &pos);
+#ifdef RT_USING_PAGECACHE
+ if (file->vnode->aspace)
+ {
+ ret = dfs_aspace_read(file, buf, len, &pos);
+ }
+ else
+#endif
+ {
+ ret = file->fops->read(file, buf, len, &pos);
+ }
}
else
{
@@ -710,7 +738,16 @@ ssize_t dfs_file_write(struct dfs_file *file, const void *buf, size_t len)
if (dfs_is_mounted(file->vnode->mnt) == 0)
{
- ret = file->fops->write(file, buf, len, &pos);
+#ifdef RT_USING_PAGECACHE
+ if (file->vnode->aspace)
+ {
+ ret = dfs_aspace_write(file, buf, len, &pos);
+ }
+ else
+#endif
+ {
+ ret = file->fops->write(file, buf, len, &pos);
+ }
}
else
{
@@ -1047,6 +1084,12 @@ int dfs_file_fsync(struct dfs_file *file)
{
if (dfs_is_mounted(file->vnode->mnt) == 0)
{
+#ifdef RT_USING_PAGECACHE
+ if (file->vnode->aspace)
+ {
+ dfs_aspace_flush(file->vnode->aspace);
+ }
+#endif
ret = file->fops->flush(file);
}
else
@@ -1089,6 +1132,14 @@ int dfs_file_unlink(const char *path)
rt_bool_t has_child = RT_FALSE;
has_child = dfs_mnt_has_child_mnt(mnt, fullpath);
+#ifdef RT_USING_PAGECACHE
+ if (dentry->vnode->aspace)
+ {
+ dfs_aspace_clean(dentry->vnode->aspace);
+ }
+#endif
+ dfs_file_lock();
+
if (has_child == RT_FALSE)
{
/* no child mnt point, unlink it */
@@ -1106,6 +1157,7 @@ int dfs_file_unlink(const char *path)
{
ret = -EBUSY;
}
+ dfs_file_unlock();
/* release this dentry */
dfs_dentry_unref(dentry);
@@ -1467,6 +1519,12 @@ int dfs_file_rename(const char *old_file, const char *new_file)
{
if (dfs_is_mounted(mnt) == 0)
{
+#ifdef RT_USING_PAGECACHE
+ if (old_dentry->vnode->aspace)
+ {
+ dfs_aspace_clean(old_dentry->vnode->aspace);
+ }
+#endif
ret = mnt->fs_ops->rename(old_dentry, new_dentry);
}
}
@@ -1499,6 +1557,12 @@ int dfs_file_ftruncate(struct dfs_file *file, off_t length)
{
if (dfs_is_mounted(file->vnode->mnt) == 0)
{
+#ifdef RT_USING_PAGECACHE
+ if (file->vnode->aspace)
+ {
+ dfs_aspace_clean(file->vnode->aspace);
+ }
+#endif
ret = file->fops->truncate(file, length);
}
else
@@ -1529,6 +1593,12 @@ int dfs_file_flush(struct dfs_file *file)
{
if (dfs_is_mounted(file->vnode->mnt) == 0)
{
+#ifdef RT_USING_PAGECACHE
+ if (file->vnode->aspace)
+ {
+ dfs_aspace_flush(file->vnode->aspace);
+ }
+#endif
ret = file->fops->flush(file);
}
else
@@ -1669,13 +1739,23 @@ int dfs_file_access(const char *path, mode_t mode)
return ret;
}
+#ifdef RT_USING_SMART
int dfs_file_mmap2(struct dfs_file *file, struct dfs_mmap2_args *mmap2)
{
- int ret = 0;
+ int ret = RT_EOK;
if (file && mmap2)
{
- if (file->vnode->type != FT_DEVICE || !file->vnode->fops->ioctl)
+ if (file->vnode->type == FT_REGULAR)
+ {
+ ret = dfs_file_mmap(file, mmap2);
+ if (ret != 0)
+ {
+ ret = ret > 0 ? ret : -ret;
+ rt_set_errno(ret);
+ }
+ }
+ else if (file->vnode->type != FT_DEVICE || !file->vnode->fops->ioctl)
{
rt_set_errno(EINVAL);
}
@@ -1700,6 +1780,7 @@ int dfs_file_mmap2(struct dfs_file *file, struct dfs_mmap2_args *mmap2)
return ret;
}
+#endif
#ifdef RT_USING_FINSH
diff --git a/components/dfs/dfs_v2/src/dfs_file_mmap.c b/components/dfs/dfs_v2/src/dfs_file_mmap.c
new file mode 100644
index 0000000000..6e356ef405
--- /dev/null
+++ b/components/dfs/dfs_v2/src/dfs_file_mmap.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#include "dfs_file.h"
+#include "dfs_dentry.h"
+#include "dfs_mnt.h"
+
+#define DBG_TAG "dfs.mmap"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
+#if defined(RT_USING_SMART) && defined(ARCH_MM_MMU) && defined(RT_USING_PAGECACHE)
+
+#include "dfs_pcache.h"
+
+#include <lwp.h>
+
+#include <sys/mman.h>
+
+#include <lwp_user_mm.h>
+#include <mm_aspace.h>
+#include <mm_fault.h>
+#include <mm_flag.h>
+#include <mm_page.h>
+#include <mmu.h>
+#include <page.h>
+#include <tlb.h>
+
+static rt_mem_obj_t dfs_get_mem_obj(struct dfs_file *file);
+static void *dfs_mem_obj_get_file(rt_mem_obj_t mem_obj);
+
+static rt_varea_t _dfs_map_user_varea_data(struct rt_lwp *lwp, void *map_vaddr, size_t map_size, size_t attr, mm_flag_t flags, off_t pgoffset, void *data)
+{
+ int ret = 0;
+ rt_varea_t varea;
+ void *vaddr = map_vaddr;
+ rt_mem_obj_t mem_obj = dfs_get_mem_obj(data);
+
+ ret = rt_aspace_map(lwp->aspace, &vaddr, map_size,
+ attr, flags, mem_obj, pgoffset);
+ if (ret != RT_EOK)
+ {
+ varea = RT_NULL;
+ }
+ else
+ {
+ varea = rt_aspace_query(lwp->aspace, vaddr);
+ }
+
+ if (ret != RT_EOK)
+ {
+ LOG_E("failed to map %lx with size %lx with errno %d", map_vaddr,
+ map_size, ret);
+ }
+
+ return varea;
+}
+
+static rt_varea_t dfs_map_user_varea_data(struct dfs_mmap2_args *mmap2, void *data)
+{
+ rt_varea_t varea = RT_NULL;
+ size_t offset = 0;
+ void *map_vaddr = mmap2->addr;
+ size_t map_size = mmap2->length;
+ struct rt_lwp *lwp = mmap2->lwp;
+ rt_size_t k_attr;
+ rt_size_t k_flags;
+
+ if (map_size)
+ {
+ offset = (size_t)map_vaddr & ARCH_PAGE_MASK;
+ map_size += (offset + ARCH_PAGE_SIZE - 1);
+ map_size &= ~ARCH_PAGE_MASK;
+ map_vaddr = (void *)((size_t)map_vaddr & ~ARCH_PAGE_MASK);
+
+ k_flags = lwp_user_mm_flag_to_kernel(mmap2->flags);
+ k_attr = lwp_user_mm_attr_to_kernel(mmap2->prot);
+
+ varea = _dfs_map_user_varea_data(lwp, map_vaddr, map_size, k_attr, k_flags, mmap2->pgoffset, data);
+ }
+
+ return varea;
+}
+
+static void hint_free(rt_mm_va_hint_t hint)
+{
+}
+
+static void on_page_fault(struct rt_varea *varea, struct rt_aspace_fault_msg *msg)
+{
+ void *page;
+ struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
+
+ if (file)
+ {
+ LOG_I("%s varea: %p", __func__, varea);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ varea->start, varea->size, varea->offset, varea->attr, varea->flag);
+ LOG_I("fault vaddr: %p", msg->fault_vaddr);
+
+ if (file->dentry)
+ {
+ LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
+ }
+
+ page = dfs_aspace_mmap(file, varea, msg->fault_vaddr);
+ if (page)
+ {
+ msg->response.status = MM_FAULT_STATUS_OK_MAPPED;
+ msg->response.size = ARCH_PAGE_SIZE;
+ msg->response.vaddr = page;
+ }
+ else
+ {
+ LOG_E("%s varea %p mmap failed at vaddr %p", __func__, varea, msg->fault_vaddr);
+ }
+ }
+ else
+ {
+ LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
+ }
+}
+
+/* do pre open bushiness like inc a ref */
+static void on_varea_open(struct rt_varea *varea)
+{
+ struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
+ varea->data = RT_NULL;
+ rt_atomic_add(&(file->ref_count), 1);
+}
+
+/* do post close bushiness like def a ref */
+static void on_varea_close(struct rt_varea *varea)
+{
+ struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
+
+ if (file)
+ {
+ LOG_I("%s varea: %p", __func__, varea);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ varea->start, varea->size, varea->offset, varea->attr, varea->flag);
+
+ if (file->dentry)
+ {
+ LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
+ }
+
+ dfs_aspace_unmap(file, varea);
+ dfs_file_lock();
+ if (rt_atomic_load(&(file->ref_count)) == 1)
+ {
+ dfs_file_close(file);
+ }
+ else
+ {
+ rt_atomic_sub(&(file->ref_count), 1);
+ }
+ dfs_file_unlock();
+ }
+ else
+ {
+ LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
+ }
+}
+
+static const char *get_name(rt_varea_t varea)
+{
+ struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
+
+ return (file && file->dentry) ? file->dentry->pathname : "file-mapper";
+}
+
+void page_read(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
+{
+ rt_ubase_t ret;
+ struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
+
+ if (file)
+ {
+ LOG_I("%s varea: %p", __func__, varea);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ varea->start, varea->size, varea->offset, varea->attr, varea->flag);
+
+ ret = dfs_aspace_mmap_read(file, varea, msg);
+ if (ret > 0)
+ {
+ msg->response.status = MM_FAULT_STATUS_OK;
+ if (ret < ARCH_PAGE_SIZE)
+ {
+ memset((char *)msg->buffer_vaddr + ret, 0, ARCH_PAGE_SIZE - ret);
+ }
+ }
+ }
+ else
+ {
+ LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
+ }
+}
+
+void page_write(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
+{
+ rt_ubase_t ret;
+ struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
+
+ if (file)
+ {
+ LOG_I("%s varea: %p", __func__, varea);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ varea->start, varea->size, varea->offset, varea->attr, varea->flag);
+
+ ret = dfs_aspace_mmap_write(file, varea, msg);
+ if (ret > 0)
+ {
+ msg->response.status = MM_FAULT_STATUS_OK;
+ if (ret < ARCH_PAGE_SIZE)
+ {
+ memset((char *)msg->buffer_vaddr + ret, 0, ARCH_PAGE_SIZE - ret);
+ }
+ }
+ }
+ else
+ {
+ LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
+ }
+}
+
+static rt_err_t unmap_pages(rt_varea_t varea, void *rm_start, void *rm_end)
+{
+ struct dfs_file *file = dfs_mem_obj_get_file(varea->mem_obj);
+
+ if (file)
+ {
+ LOG_I("%s varea: %p start: %p end: %p", __func__, varea, rm_start, rm_end);
+
+ RT_ASSERT(!((rt_ubase_t)rm_start & ARCH_PAGE_MASK));
+ RT_ASSERT(!((rt_ubase_t)rm_end & ARCH_PAGE_MASK));
+ while (rm_start != rm_end)
+ {
+ dfs_aspace_page_unmap(file, varea, rm_start);
+ rm_start += ARCH_PAGE_SIZE;
+ }
+
+ return RT_EOK;
+ }
+ else
+ {
+ LOG_E("%s varea %p not a file, vaddr %p", __func__, varea, varea->start);
+ }
+
+ return -RT_ERROR;
+}
+
+rt_err_t on_varea_shrink(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
+{
+ char *varea_start = varea->start;
+ void *rm_start;
+ void *rm_end;
+
+ LOG_I("%s varea: %p", __func__, varea);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ varea->start, varea->size, varea->offset, varea->attr, varea->flag);
+ LOG_I("new_vaddr: %p size: %p", new_vaddr, size);
+
+ if (varea_start == (char *)new_vaddr)
+ {
+ rm_start = varea_start + size;
+ rm_end = varea_start + varea->size;
+ }
+ else if (varea_start < (char *)new_vaddr)
+ {
+ rm_start = varea_start;
+ rm_end = new_vaddr;
+ }
+
+ return unmap_pages(varea, rm_start, rm_end);
+}
+
+rt_err_t on_varea_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
+{
+ LOG_I("%s varea: %p", __func__, varea);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ varea->start, varea->size, varea->offset, varea->attr, varea->flag);
+ LOG_I("new_vaddr: %p size: %p", new_vaddr, size);
+
+ return RT_EOK;
+}
+
+rt_err_t on_varea_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
+{
+ struct dfs_file *file = dfs_mem_obj_get_file(existed->mem_obj);
+
+ if (file)
+ {
+ LOG_I("%s varea: %p", __func__, existed);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ existed->start, existed->size, existed->offset, existed->attr, existed->flag);
+ LOG_I("unmap_start: %p unmap_len: %p", unmap_start, unmap_len);
+
+ if (file->dentry)
+ {
+ LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
+ }
+
+ unmap_pages(existed, unmap_start, (char *)unmap_start + unmap_len);
+
+ subset->data = existed->data;
+ rt_atomic_add(&(file->ref_count), 1);
+
+ return RT_EOK;
+ }
+ else
+ {
+ LOG_E("%s varea %p not a file, vaddr %p", __func__, existed, existed->start);
+ }
+
+ return -RT_ERROR;
+}
+
+rt_err_t on_varea_merge(struct rt_varea *merge_to, struct rt_varea *merge_from)
+{
+ struct dfs_file *file = dfs_mem_obj_get_file(merge_from->mem_obj);
+
+ if (file)
+ {
+ LOG_I("%s varea: %p", __func__, merge_from);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ merge_from->start, merge_from->size, merge_from->offset, merge_from->attr, merge_from->flag);
+
+ if (file->dentry)
+ {
+ LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
+ }
+
+ dfs_aspace_unmap(file, merge_from);
+ merge_from->data = RT_NULL;
+ rt_atomic_sub(&(file->ref_count), 1);
+
+ return RT_EOK;
+ }
+ else
+ {
+ LOG_E("%s varea %p not a file, vaddr %p", __func__, merge_from, merge_from->start);
+ }
+
+ return -RT_ERROR;
+}
+
+static struct rt_mem_obj _mem_obj =
+{
+ .hint_free = hint_free,
+ .on_page_fault = on_page_fault,
+ .on_varea_open = on_varea_open,
+ .on_varea_close = on_varea_close,
+ .get_name = get_name,
+
+ .page_read = page_read,
+ .page_write = page_write,
+
+ .on_varea_shrink = on_varea_shrink,
+ .on_varea_expand = on_varea_expand,
+ .on_varea_split = on_varea_split,
+ .on_varea_merge = on_varea_merge,
+};
+
+struct dfs_mem_obj {
+ struct rt_mem_obj mem_obj;
+ void *file;
+};
+
+static rt_mem_obj_t dfs_get_mem_obj(struct dfs_file *file)
+{
+ rt_mem_obj_t mobj = file->mmap_context;
+ if (!mobj)
+ {
+ struct dfs_mem_obj *dfs_mobj;
+ dfs_file_lock();
+ dfs_mobj = rt_malloc(sizeof(*dfs_mobj));
+ if (dfs_mobj)
+ {
+ dfs_mobj->file = file;
+ mobj = &dfs_mobj->mem_obj;
+ memcpy(mobj, &_mem_obj, sizeof(*mobj));
+ file->mmap_context = mobj;
+ }
+ dfs_file_unlock();
+ }
+ return mobj;
+}
+
+static void *dfs_mem_obj_get_file(rt_mem_obj_t mem_obj)
+{
+ struct dfs_mem_obj *dfs_mobj;
+ dfs_mobj = rt_container_of(mem_obj, struct dfs_mem_obj, mem_obj);
+ return dfs_mobj->file;
+}
+
+int dfs_file_mmap(struct dfs_file *file, struct dfs_mmap2_args *mmap2)
+{
+ int ret = -EINVAL;
+
+ LOG_I("mmap2 args addr: %p length: 0x%x prot: %d flags: 0x%x pgoffset: 0x%x",
+ mmap2->addr, mmap2->length, mmap2->prot, mmap2->flags, mmap2->pgoffset);
+ if (file && file->vnode && file->vnode->aspace)
+ {
+ /* create a va area in user space (lwp) */
+ rt_varea_t varea = dfs_map_user_varea_data(mmap2, file);
+ if (varea)
+ {
+ mmap2->ret = varea->start;
+ LOG_I("%s varea: %p", __func__, varea);
+ LOG_I("varea start: %p size: 0x%x offset: 0x%x attr: 0x%x flag: 0x%x",
+ varea->start, varea->size, varea->offset, varea->attr, varea->flag);
+ LOG_I("file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
+ ret = RT_EOK;
+ }
+ else
+ {
+ ret = -ENOMEM;
+ }
+ }
+ else if (file->vnode->aspace == RT_NULL)
+ {
+ LOG_E("File mapping is not supported, file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
+ }
+
+ return ret;
+}
+#else
+int dfs_file_mmap(struct dfs_file *file, struct dfs_mmap2_args *mmap2)
+{
+ LOG_E("File mapping support is not enabled, file: %s%s", file->dentry->mnt->fullpath, file->dentry->pathname);
+ LOG_E("mmap2 args addr: %p length: 0x%x prot: %d flags: 0x%x pgoffset: 0x%x",
+ mmap2->addr, mmap2->length, mmap2->prot, mmap2->flags, mmap2->pgoffset);
+
+ return -EPERM;
+}
+#endif
diff --git a/components/dfs/dfs_v2/src/dfs_fs.c b/components/dfs/dfs_v2/src/dfs_fs.c
index 8c28dbe7ef..e65ccee478 100644
--- a/components/dfs/dfs_v2/src/dfs_fs.c
+++ b/components/dfs/dfs_v2/src/dfs_fs.c
@@ -19,6 +19,10 @@
#include <dfs_mnt.h>
#include "dfs_private.h"
+#ifdef RT_USING_PAGECACHE
+#include "dfs_pcache.h"
+#endif
+
#define DBG_TAG "DFS.fs"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
@@ -314,6 +318,9 @@ int dfs_umount(const char *specialfile, int flags)
if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
{
+#ifdef RT_USING_PAGECACHE
+ dfs_pcache_unmount(mnt);
+#endif
/* destroy this mount point */
DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt)");
ret = dfs_mnt_destroy(mnt);
@@ -396,6 +403,18 @@ int dfs_mkfs(const char *fs_name, const char *device_name)
if (type->fs_ops->mkfs)
{
ret = type->fs_ops->mkfs(dev_id, type->fs_ops->name);
+#ifdef RT_USING_PAGECACHE
+ if (ret == RT_EOK)
+ {
+ struct dfs_mnt *mnt = RT_NULL;
+
+ mnt = dfs_mnt_dev_lookup(dev_id);
+ if (mnt)
+ {
+ dfs_pcache_unmount(mnt);
+ }
+ }
+#endif
}
return ret;
diff --git a/components/dfs/dfs_v2/src/dfs_mnt.c b/components/dfs/dfs_v2/src/dfs_mnt.c
index 379606d9ce..4ad73c6dee 100644
--- a/components/dfs/dfs_v2/src/dfs_mnt.c
+++ b/components/dfs/dfs_v2/src/dfs_mnt.c
@@ -131,6 +131,53 @@ int dfs_mnt_remove(struct dfs_mnt* mnt)
return ret;
}
+static struct dfs_mnt *_dfs_mnt_dev_lookup(struct dfs_mnt *mnt, rt_device_t dev_id)
+{
+ struct dfs_mnt *ret = RT_NULL, *iter = RT_NULL;
+
+ rt_list_for_each_entry(iter, &mnt->child, sibling)
+ {
+ if (iter->dev_id == dev_id)
+ {
+ ret = iter;
+ break;
+ }
+ else
+ {
+ ret = _dfs_mnt_dev_lookup(iter, dev_id);
+ if (ret)
+ {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+struct dfs_mnt *dfs_mnt_dev_lookup(rt_device_t dev_id)
+{
+ struct dfs_mnt *mnt = _root_mnt;
+ struct dfs_mnt *ret = RT_NULL;
+
+ if (mnt)
+ {
+ dfs_lock();
+
+ if (mnt->dev_id == dev_id)
+ {
+ dfs_unlock();
+ return mnt;
+ }
+
+ ret = _dfs_mnt_dev_lookup(mnt, dev_id);
+
+ dfs_unlock();
+ }
+
+ return ret;
+}
+
/**
* this function will return the file system mounted on specified path.
*
@@ -139,24 +186,26 @@ int dfs_mnt_remove(struct dfs_mnt* mnt)
* @return the found file system or NULL if no file system mounted on
* specified path
*/
-struct dfs_mnt* dfs_mnt_lookup(const char* fullpath)
+struct dfs_mnt *dfs_mnt_lookup(const char *fullpath)
{
struct dfs_mnt *mnt = _root_mnt;
struct dfs_mnt *iter = RT_NULL;
if (mnt)
{
+ int mnt_len = rt_strlen(mnt->fullpath);
+
dfs_lock();
- if (strncmp(mnt->fullpath, fullpath, strlen(fullpath))!= 0)
+ if ((strncmp(mnt->fullpath, fullpath, mnt_len) == 0) &&
+ (mnt_len == 1 || (fullpath[mnt_len] == '\0') || (fullpath[mnt_len] == '/')))
{
while (!rt_list_isempty(&mnt->child))
{
rt_list_for_each_entry(iter, &mnt->child, sibling)
{
- int mnt_len = rt_strlen(iter->fullpath);
+ mnt_len = rt_strlen(iter->fullpath);
if ((strncmp(iter->fullpath, fullpath, mnt_len) == 0) &&
- ((fullpath[mnt_len] == '\0') ||
- (fullpath[mnt_len] == '/')))
+ ((fullpath[mnt_len] == '\0') || (fullpath[mnt_len] == '/')))
{
mnt = iter;
break;
@@ -166,6 +215,10 @@ struct dfs_mnt* dfs_mnt_lookup(const char* fullpath)
if (mnt != iter) break;
}
}
+ else
+ {
+ mnt = RT_NULL;
+ }
dfs_unlock();
if (mnt)
diff --git a/components/dfs/dfs_v2/src/dfs_pcache.c b/components/dfs/dfs_v2/src/dfs_pcache.c
new file mode 100644
index 0000000000..0b2492dc7f
--- /dev/null
+++ b/components/dfs/dfs_v2/src/dfs_pcache.c
@@ -0,0 +1,1439 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-05-05 RTT Implement mnt in dfs v2.0
+ */
+
+#include "dfs_pcache.h"
+#include "dfs_dentry.h"
+#include "dfs_mnt.h"
+#include "mm_page.h"
+#include <mmu.h>
+#include <tlb.h>
+
+#ifdef RT_USING_PAGECACHE
+
+#define DBG_TAG "dfs.pcache"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
+#ifndef RT_PAGECACHE_COUNT
+#define RT_PAGECACHE_COUNT 4096
+#endif
+
+#ifndef RT_PAGECACHE_ASPACE_COUNT
+#define RT_PAGECACHE_ASPACE_COUNT 1024
+#endif
+
+#ifndef RT_PAGECACHE_PRELOAD
+#define RT_PAGECACHE_PRELOAD 4
+#endif
+
+#ifndef RT_PAGECACHE_GC_WORK_LEVEL
+#define RT_PAGECACHE_GC_WORK_LEVEL 90
+#endif
+
+#ifndef RT_PAGECACHE_GC_STOP_LEVEL
+#define RT_PAGECACHE_GC_STOP_LEVEL 70
+#endif
+
+#define PCACHE_MQ_GC 1
+#define PCACHE_MQ_WB 2
+
+struct dfs_aspace_mmap_obj
+{
+ rt_uint32_t cmd;
+ struct rt_mailbox *ack;
+ struct dfs_file *file;
+ struct rt_varea *varea;
+ void *data;
+};
+
+struct dfs_pcache_mq_obj
+{
+ struct rt_mailbox *ack;
+ rt_uint32_t cmd;
+};
+
+static struct dfs_page *dfs_page_lookup(struct dfs_file *file, off_t pos);
+static void dfs_page_ref(struct dfs_page *page);
+static int dfs_page_inactive(struct dfs_page *page);
+static int dfs_page_remove(struct dfs_page *page);
+static void dfs_page_release(struct dfs_page *page);
+static int dfs_page_dirty(struct dfs_page *page);
+
+static int dfs_aspace_release(struct dfs_aspace *aspace);
+
+static int dfs_aspace_lock(struct dfs_aspace *aspace);
+static int dfs_aspace_unlock(struct dfs_aspace *aspace);
+
+static int dfs_pcache_lock(void);
+static int dfs_pcache_unlock(void);
+
+
+static struct dfs_pcache __pcache;
+
+
+static int dfs_aspace_gc(struct dfs_aspace *aspace, int count)
+{
+ int cnt = count;
+
+ if (aspace)
+ {
+ dfs_aspace_lock(aspace);
+
+ if (aspace->pages_count > 0)
+ {
+ struct dfs_page *page = RT_NULL;
+ rt_list_t *node = aspace->list_inactive.next;
+
+ while (cnt && node != &aspace->list_active)
+ {
+ page = rt_list_entry(node, struct dfs_page, space_node);
+ node = node->next;
+ if (dfs_page_remove(page) == 0)
+ {
+ cnt --;
+ }
+ }
+
+ node = aspace->list_active.next;
+ while (cnt && node != &aspace->list_inactive)
+ {
+ page = rt_list_entry(node, struct dfs_page, space_node);
+ node = node->next;
+ if (dfs_page_remove(page) == 0)
+ {
+ cnt --;
+ }
+ }
+ }
+
+ dfs_aspace_unlock(aspace);
+ }
+
+ return count - cnt;
+}
+
+void dfs_pcache_release(size_t count)
+{
+ rt_list_t *node = RT_NULL;
+ struct dfs_aspace *aspace = RT_NULL;
+
+ dfs_pcache_lock();
+
+ if (count == 0)
+ {
+ count = rt_atomic_load(&(__pcache.pages_count)) - RT_PAGECACHE_COUNT * RT_PAGECACHE_GC_STOP_LEVEL / 100;
+ }
+
+ node = __pcache.list_inactive.next;
+ while (count && node != &__pcache.list_active)
+ {
+ aspace = rt_list_entry(node, struct dfs_aspace, cache_node);
+ node = node->next;
+ if (aspace)
+ {
+ count -= dfs_aspace_gc(aspace, count);
+ dfs_aspace_release(aspace);
+ }
+ }
+
+ node = __pcache.list_active.next;
+ while (count && node != &__pcache.list_inactive)
+ {
+ aspace = rt_list_entry(node, struct dfs_aspace, cache_node);
+ node = node->next;
+ if (aspace)
+ {
+ count -= dfs_aspace_gc(aspace, count);
+ }
+ }
+
+ dfs_pcache_unlock();
+}
+
+void dfs_pcache_unmount(struct dfs_mnt *mnt)
+{
+ rt_list_t *node = RT_NULL;
+ struct dfs_aspace *aspace = RT_NULL;
+
+ dfs_pcache_lock();
+
+ node = __pcache.list_inactive.next;
+ while (node != &__pcache.list_active)
+ {
+ aspace = rt_list_entry(node, struct dfs_aspace, cache_node);
+ node = node->next;
+ if (aspace && aspace->mnt == mnt)
+ {
+ dfs_aspace_clean(aspace);
+ dfs_aspace_release(aspace);
+ }
+ }
+
+ node = __pcache.list_active.next;
+ while (node != &__pcache.list_inactive)
+ {
+ aspace = rt_list_entry(node, struct dfs_aspace, cache_node);
+ node = node->next;
+ if (aspace && aspace->mnt == mnt)
+ {
+ dfs_aspace_clean(aspace);
+ dfs_aspace_release(aspace);
+ }
+ }
+
+ dfs_pcache_unlock();
+}
+
+static int dfs_pcache_limit_check(void)
+{
+ int index = 4;
+
+ while (index && rt_atomic_load(&(__pcache.pages_count)) > RT_PAGECACHE_COUNT * RT_PAGECACHE_GC_WORK_LEVEL / 100)
+ {
+ dfs_pcache_release(0);
+ index --;
+ }
+
+ return 0;
+}
+
+static void dfs_pcache_thread(void *parameter)
+{
+ struct dfs_pcache_mq_obj work;
+
+ while (1)
+ {
+ if (rt_mq_recv(__pcache.mqueue, &work, sizeof(work), RT_WAITING_FOREVER) == sizeof(work))
+ {
+ if (work.cmd == PCACHE_MQ_GC)
+ {
+ dfs_pcache_limit_check();
+ }
+ else if (work.cmd == PCACHE_MQ_WB)
+ {
+ int count = 0;
+ rt_list_t *node;
+ struct dfs_page *page = 0;
+
+ while (1)
+ {
+ /* try to get dirty page */
+ dfs_pcache_lock();
+ page = 0;
+ rt_list_for_each(node, &__pcache.list_active)
+ {
+ if (node != &__pcache.list_inactive)
+ {
+ struct dfs_aspace *aspace = rt_list_entry(node, struct dfs_aspace, cache_node);
+ dfs_aspace_lock(aspace);
+ if (aspace->list_dirty.next != &aspace->list_dirty)
+ {
+ page = rt_list_entry(aspace->list_dirty.next, struct dfs_page, dirty_node);
+ dfs_page_ref(page);
+ dfs_aspace_unlock(aspace);
+ break;
+ }
+ else
+ {
+ page = RT_NULL;
+ }
+ dfs_aspace_unlock(aspace);
+ }
+ }
+ dfs_pcache_unlock();
+
+ if (page)
+ {
+ struct dfs_aspace *aspace = page->aspace;
+
+ dfs_aspace_lock(aspace);
+ if (page->is_dirty == 1 && aspace->vnode)
+ {
+ if (rt_tick_get_millisecond() - page->tick_ms >= 500)
+ {
+ if (aspace->vnode->size < page->fpos + page->size)
+ {
+ page->len = aspace->vnode->size - page->fpos;
+ }
+ else
+ {
+ page->len = page->size;
+ }
+ //rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
+ aspace->ops->write(page);
+
+ page->is_dirty = 0;
+
+ if (page->dirty_node.next != RT_NULL)
+ {
+ rt_list_remove(&page->dirty_node);
+ page->dirty_node.next = RT_NULL;
+ }
+ }
+ }
+ dfs_page_release(page);
+ dfs_aspace_unlock(aspace);
+ }
+ else
+ {
+ break;
+ }
+
+ rt_thread_mdelay(5);
+
+ count ++;
+ if (count >= 4)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static int dfs_pcache_init(void)
+{
+ rt_thread_t tid;
+
+ for (int i = 0; i < RT_PAGECACHE_HASH_NR; i++)
+ {
+ rt_list_init(&__pcache.head[i]);
+ }
+
+ rt_list_init(&__pcache.list_active);
+ rt_list_init(&__pcache.list_inactive);
+ rt_list_insert_after(&__pcache.list_active, &__pcache.list_inactive);
+
+ rt_atomic_store(&(__pcache.pages_count), 0);
+
+ rt_mutex_init(&__pcache.lock, "pcache", RT_IPC_FLAG_PRIO);
+
+ __pcache.mqueue = rt_mq_create("pcache", sizeof(struct dfs_pcache_mq_obj), 1024, RT_IPC_FLAG_FIFO);
+ tid = rt_thread_create("pcache", dfs_pcache_thread, 0, 8192, 25, 5);
+ if (tid)
+ {
+ rt_thread_startup(tid);
+ }
+
+ __pcache.last_time_wb = rt_tick_get_millisecond();
+
+ return 0;
+}
+INIT_PREV_EXPORT(dfs_pcache_init);
+
+static rt_ubase_t dfs_pcache_mq_work(rt_uint32_t cmd)
+{
+ rt_err_t err;
+ struct dfs_pcache_mq_obj work = { 0 };
+
+ work.cmd = cmd;
+
+ err = rt_mq_send_wait(__pcache.mqueue, (const void *)&work, sizeof(struct dfs_pcache_mq_obj), 0);
+
+ return err;
+}
+
+static int dfs_pcache_lock(void)
+{
+ rt_mutex_take(&__pcache.lock, RT_WAITING_FOREVER);
+ return 0;
+}
+
+static int dfs_pcache_unlock(void)
+{
+ rt_mutex_release(&__pcache.lock);
+ return 0;
+}
+
+static uint32_t dfs_aspace_hash(struct dfs_mnt *mnt, const char *path)
+{
+ uint32_t val = 0;
+
+ if (path)
+ {
+ while (*path)
+ {
+ val = ((val << 5) + val) + *path++;
+ }
+ }
+
+ return (val ^ (unsigned long)mnt) & (RT_PAGECACHE_HASH_NR - 1);
+}
+
+static struct dfs_aspace *dfs_aspace_hash_lookup(struct dfs_dentry *dentry, const struct dfs_aspace_ops *ops)
+{
+ struct dfs_aspace *aspace = RT_NULL;
+
+ dfs_pcache_lock();
+ rt_list_for_each_entry(aspace, &__pcache.head[dfs_aspace_hash(dentry->mnt, dentry->pathname)], hash_node)
+ {
+
+ if (aspace->mnt == dentry->mnt
+ && aspace->ops == ops
+ && !strcmp(aspace->pathname, dentry->pathname))
+ {
+ rt_atomic_add(&aspace->ref_count, 1);
+ dfs_pcache_unlock();
+ return aspace;
+ }
+ }
+ dfs_pcache_unlock();
+
+ return RT_NULL;
+}
+
+static void dfs_aspace_insert(struct dfs_aspace *aspace)
+{
+ uint32_t val = 0;
+
+ val = dfs_aspace_hash(aspace->mnt, aspace->pathname);
+
+ dfs_pcache_lock();
+ rt_atomic_add(&aspace->ref_count, 1);
+ rt_list_insert_after(&__pcache.head[val], &aspace->hash_node);
+ rt_list_insert_before(&__pcache.list_inactive, &aspace->cache_node);
+ dfs_pcache_unlock();
+}
+
+static void dfs_aspace_remove(struct dfs_aspace *aspace)
+{
+ dfs_pcache_lock();
+ if (aspace->hash_node.next != RT_NULL)
+ {
+ rt_list_remove(&aspace->hash_node);
+ }
+ if (aspace->cache_node.next != RT_NULL)
+ {
+ rt_list_remove(&aspace->cache_node);
+ }
+ dfs_pcache_unlock();
+}
+
+static void dfs_aspace_active(struct dfs_aspace *aspace)
+{
+ dfs_pcache_lock();
+ if (aspace->cache_node.next != RT_NULL)
+ {
+ rt_list_remove(&aspace->cache_node);
+ rt_list_insert_before(&__pcache.list_inactive, &aspace->cache_node);
+ }
+ dfs_pcache_unlock();
+}
+
+static void dfs_aspace_inactive(struct dfs_aspace *aspace)
+{
+ dfs_pcache_lock();
+ if (aspace->cache_node.next != RT_NULL)
+ {
+ rt_list_remove(&aspace->cache_node);
+ rt_list_insert_before(&__pcache.list_active, &aspace->cache_node);
+ }
+ dfs_pcache_unlock();
+}
+
+static struct dfs_aspace *_dfs_aspace_create(struct dfs_dentry *dentry,
+ struct dfs_vnode *vnode,
+ const struct dfs_aspace_ops *ops)
+{
+ struct dfs_aspace *aspace;
+
+ aspace = rt_calloc(1, sizeof(struct dfs_aspace));
+ if (aspace)
+ {
+ rt_list_init(&aspace->list_active);
+ rt_list_init(&aspace->list_inactive);
+ rt_list_init(&aspace->list_dirty);
+ rt_list_insert_after(&aspace->list_active, &aspace->list_inactive);
+
+ aspace->avl_root.root_node = 0;
+ aspace->avl_page = 0;
+
+ rt_mutex_init(&aspace->lock, rt_thread_self()->parent.name, RT_IPC_FLAG_PRIO);
+ rt_atomic_store(&aspace->ref_count, 1);
+
+ aspace->pages_count = 0;
+ aspace->vnode = vnode;
+ aspace->ops = ops;
+
+ if (dentry && dentry->mnt)
+ {
+ aspace->mnt = dentry->mnt;
+ aspace->fullpath = rt_strdup(dentry->mnt->fullpath);
+ aspace->pathname = rt_strdup(dentry->pathname);
+ }
+
+ dfs_aspace_insert(aspace);
+ }
+
+ return aspace;
+}
+
+struct dfs_aspace *dfs_aspace_create(struct dfs_dentry *dentry,
+ struct dfs_vnode *vnode,
+ const struct dfs_aspace_ops *ops)
+{
+ struct dfs_aspace *aspace = RT_NULL;
+
+ RT_ASSERT(vnode && ops);
+ dfs_pcache_lock();
+ if (dentry)
+ {
+ aspace = dfs_aspace_hash_lookup(dentry, ops);
+ }
+
+ if (!aspace)
+ {
+ aspace = _dfs_aspace_create(dentry, vnode, ops);
+ }
+ else
+ {
+ aspace->vnode = vnode;
+ dfs_aspace_active(aspace);
+ }
+ dfs_pcache_unlock();
+ return aspace;
+}
+
+int dfs_aspace_destroy(struct dfs_aspace *aspace)
+{
+ int ret = -EINVAL;
+
+ if (aspace)
+ {
+ dfs_pcache_lock();
+ dfs_aspace_lock(aspace);
+ rt_atomic_sub(&aspace->ref_count, 1);
+ RT_ASSERT(rt_atomic_load(&aspace->ref_count) > 0);
+ dfs_aspace_inactive(aspace);
+ aspace->vnode = RT_NULL;
+ if (dfs_aspace_release(aspace) != 0)
+ {
+ dfs_aspace_unlock(aspace);
+ }
+ dfs_pcache_unlock();
+ }
+
+ return ret;
+}
+
+static int dfs_aspace_release(struct dfs_aspace *aspace)
+{
+ int ret = -1;
+
+ if (aspace)
+ {
+ dfs_pcache_lock();
+ dfs_aspace_lock(aspace);
+
+ if (rt_atomic_load(&aspace->ref_count) == 1 && aspace->pages_count == 0)
+ {
+ dfs_aspace_remove(aspace);
+ if (aspace->fullpath)
+ {
+ rt_free(aspace->fullpath);
+ }
+ if (aspace->pathname)
+ {
+ rt_free(aspace->pathname);
+ }
+ rt_mutex_detach(&aspace->lock);
+ rt_free(aspace);
+ ret = 0;
+ }
+ else
+ {
+ dfs_aspace_unlock(aspace);
+ }
+ dfs_pcache_unlock();
+ }
+
+ return ret;
+}
+
+static int _dfs_aspace_dump(struct dfs_aspace *aspace, int is_dirty)
+{
+ if (aspace)
+ {
+ rt_list_t *next;
+ struct dfs_page *page;
+
+ dfs_aspace_lock(aspace);
+ if (aspace->pages_count > 0)
+ {
+ rt_list_for_each(next, &aspace->list_inactive)
+ {
+ if (next != &aspace->list_active)
+ {
+ page = rt_list_entry(next, struct dfs_page, space_node);
+ if (is_dirty && page->is_dirty)
+ {
+ rt_kprintf(" pages >> fpos: %d index :%d is_dirty: %d\n", page->fpos, page->fpos / ARCH_PAGE_SIZE, page->is_dirty);
+ }
+ else if (is_dirty == 0)
+ {
+ rt_kprintf(" pages >> fpos: %d index :%d is_dirty: %d\n", page->fpos, page->fpos / ARCH_PAGE_SIZE, page->is_dirty);
+ }
+ }
+ }
+ }
+ else
+ {
+ rt_kprintf(" pages >> empty\n");
+ }
+ dfs_aspace_unlock(aspace);
+ }
+ return 0;
+}
+
+static int dfs_pcache_dump(int argc, char **argv)
+{
+ int dump = 0;
+ rt_list_t *node;
+ struct dfs_aspace *aspace;
+
+ if (argc == 2)
+ {
+ if (strcmp(argv[1], "--dump") == 0)
+ {
+ dump = 1;
+ }
+ else if (strcmp(argv[1], "--dirty") == 0)
+ {
+ dump = 2;
+ }
+ else
+ {
+ rt_kprintf("dfs page cache dump\n");
+ rt_kprintf("usage: dfs_cache\n");
+ rt_kprintf(" dfs_cache --dump\n");
+ rt_kprintf(" dfs_cache --dirty\n");
+ return 0;
+ }
+ }
+
+ dfs_pcache_lock();
+
+ rt_kprintf("total pages count: %d / %d\n", rt_atomic_load(&(__pcache.pages_count)), RT_PAGECACHE_COUNT);
+
+ rt_list_for_each(node, &__pcache.list_active)
+ {
+ if (node != &__pcache.list_inactive)
+ {
+ aspace = rt_list_entry(node, struct dfs_aspace, cache_node);
+
+ if (aspace->mnt)
+ {
+ rt_kprintf("file: %s%s pages: %d\n", aspace->fullpath, aspace->pathname, aspace->pages_count);
+ }
+ else
+ {
+ rt_kprintf("unknown type, pages: %d\n", aspace->pages_count);
+ }
+
+ if (dump > 0)
+ {
+ _dfs_aspace_dump(aspace, dump == 2 ? 1 : 0);
+ }
+ }
+ }
+
+ dfs_pcache_unlock();
+
+ return 0;
+}
+MSH_CMD_EXPORT_ALIAS(dfs_pcache_dump, dfs_cache, dump dfs page cache);
+
+static int dfs_page_unmap(struct dfs_page *page)
+{
+ rt_list_t *next;
+ struct dfs_mmap *map;
+
+ next = page->mmap_head.next;
+
+ if (next != &page->mmap_head && page->fpos < page->aspace->vnode->size)
+ {
+ dfs_page_dirty(page);
+ }
+
+ while (next != &page->mmap_head)
+ {
+ map = rt_list_entry(next, struct dfs_mmap, mmap_node);
+ next = next->next;
+
+ if (map)
+ {
+ void *vaddr = dfs_aspace_vaddr(map->varea, page->fpos);
+ //rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, vaddr, ARCH_PAGE_SIZE);
+ rt_varea_unmap_page(map->varea, vaddr);
+
+ rt_free(map);
+ }
+ }
+
+ rt_list_init(&page->mmap_head);
+
+ return 0;
+}
+
+static struct dfs_page *dfs_page_create(void)
+{
+ struct dfs_page *page = RT_NULL;
+
+ page = rt_calloc(1, sizeof(struct dfs_page));
+ if (page)
+ {
+ page->page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
+ if (page->page)
+ {
+ //memset(page->page, 0x00, ARCH_PAGE_SIZE);
+ rt_list_init(&page->mmap_head);
+ rt_atomic_store(&(page->ref_count), 1);
+ }
+ else
+ {
+ LOG_E("page alloc failed!\n");
+ rt_free(page);
+ page = RT_NULL;
+ }
+ }
+
+ return page;
+}
+
+static void dfs_page_ref(struct dfs_page *page)
+{
+ rt_atomic_add(&(page->ref_count), 1);
+}
+
+static void dfs_page_release(struct dfs_page *page)
+{
+ struct dfs_aspace *aspace = page->aspace;
+
+ dfs_aspace_lock(aspace);
+
+ rt_atomic_sub(&(page->ref_count), 1);
+
+ if (rt_atomic_load(&(page->ref_count)) == 0)
+ {
+ dfs_page_unmap(page);
+
+ if (page->is_dirty == 1 && aspace->vnode)
+ {
+ if (aspace->vnode->size < page->fpos + page->size)
+ {
+ page->len = aspace->vnode->size - page->fpos;
+ }
+ else
+ {
+ page->len = page->size;
+ }
+ //rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
+ aspace->ops->write(page);
+ page->is_dirty = 0;
+ }
+ RT_ASSERT(page->is_dirty == 0);
+
+ rt_pages_free(page->page, 0);
+ page->page = RT_NULL;
+ rt_free(page);
+ }
+
+ dfs_aspace_unlock(aspace);
+}
+
+static int dfs_page_compare(off_t fpos, off_t value)
+{
+ return fpos / ARCH_PAGE_SIZE * ARCH_PAGE_SIZE - value;
+}
+
+static int _dfs_page_insert(struct dfs_aspace *aspace, struct dfs_page *page)
+{
+ struct dfs_page *tmp;
+ struct util_avl_struct *current = NULL;
+ struct util_avl_struct **next = &(aspace->avl_root.root_node);
+
+ /* Figure out where to put new node */
+ while (*next)
+ {
+ current = *next;
+ tmp = rt_container_of(current, struct dfs_page, avl_node);
+
+ if (page->fpos < tmp->fpos)
+ next = &(current->avl_left);
+ else if (page->fpos > tmp->fpos)
+ next = &(current->avl_right);
+ else
+ return -1;
+ }
+
+ /* Add new node and rebalance tree. */
+ util_avl_link(&page->avl_node, current, next);
+ util_avl_rebalance(current, &aspace->avl_root);
+ aspace->avl_page = page;
+
+ return 0;
+}
+
+static void _dfs_page_remove(struct dfs_aspace *aspace, struct dfs_page *page)
+{
+ if (aspace->avl_page && aspace->avl_page == page)
+ {
+ aspace->avl_page = 0;
+ }
+
+ util_avl_remove(&page->avl_node, &aspace->avl_root);
+}
+
+static int dfs_aspace_lock(struct dfs_aspace *aspace)
+{
+ rt_mutex_take(&aspace->lock, RT_WAITING_FOREVER);
+ return 0;
+}
+
+static int dfs_aspace_unlock(struct dfs_aspace *aspace)
+{
+ rt_mutex_release(&aspace->lock);
+ return 0;
+}
+
+static int dfs_page_insert(struct dfs_page *page)
+{
+ struct dfs_aspace *aspace = page->aspace;
+
+ dfs_aspace_lock(aspace);
+
+ rt_list_insert_before(&aspace->list_inactive, &page->space_node);
+ aspace->pages_count ++;
+
+ RT_ASSERT(_dfs_page_insert(aspace, page) == 0);
+
+ if (aspace->pages_count > RT_PAGECACHE_ASPACE_COUNT)
+ {
+ rt_list_t *next = aspace->list_active.next;
+
+ if (next != &aspace->list_inactive)
+ {
+ struct dfs_page *tmp = rt_list_entry(next, struct dfs_page, space_node);
+ dfs_page_inactive(tmp);
+ }
+ }
+
+ rt_atomic_add(&(__pcache.pages_count), 1);
+
+ dfs_aspace_unlock(aspace);
+
+ return 0;
+}
+
+static int dfs_page_remove(struct dfs_page *page)
+{
+ int ret = -1;
+ struct dfs_aspace *aspace = page->aspace;
+
+ dfs_aspace_lock(aspace);
+
+ if (rt_atomic_load(&(page->ref_count)) == 1)
+ {
+ if (page->space_node.next != RT_NULL)
+ {
+ rt_list_remove(&page->space_node);
+ page->space_node.next = RT_NULL;
+ aspace->pages_count--;
+ _dfs_page_remove(aspace, page);
+ }
+ if (page->dirty_node.next != RT_NULL)
+ {
+ rt_list_remove(&page->dirty_node);
+ page->dirty_node.next = RT_NULL;
+ }
+
+ rt_atomic_sub(&(__pcache.pages_count), 1);
+
+ dfs_page_release(page);
+ ret = 0;
+ }
+
+ dfs_aspace_unlock(aspace);
+
+ return ret;
+}
+
+static int dfs_page_active(struct dfs_page *page)
+{
+ struct dfs_aspace *aspace = page->aspace;
+
+ dfs_aspace_lock(aspace);
+ if (page->space_node.next != RT_NULL)
+ {
+ rt_list_remove(&page->space_node);
+ rt_list_insert_before(&aspace->list_inactive, &page->space_node);
+ }
+ dfs_aspace_unlock(aspace);
+
+ return 0;
+}
+
+static int dfs_page_inactive(struct dfs_page *page)
+{
+ struct dfs_aspace *aspace = page->aspace;
+
+ dfs_aspace_lock(aspace);
+ if (page->space_node.next != RT_NULL)
+ {
+ rt_list_remove(&page->space_node);
+ rt_list_insert_before(&aspace->list_active, &page->space_node);
+ }
+ dfs_aspace_unlock(aspace);
+
+ return 0;
+}
+
+static int dfs_page_dirty(struct dfs_page *page)
+{
+ struct dfs_aspace *aspace = page->aspace;
+
+ dfs_aspace_lock(aspace);
+
+ if (page->dirty_node.next == RT_NULL && page->space_node.next != RT_NULL)
+ {
+ rt_list_insert_before(&aspace->list_dirty, &page->dirty_node);
+ }
+
+ page->is_dirty = 1;
+ page->tick_ms = rt_tick_get_millisecond();
+
+ if (rt_tick_get_millisecond() - __pcache.last_time_wb >= 1000)
+ {
+ dfs_pcache_mq_work(PCACHE_MQ_WB);
+ __pcache.last_time_wb = rt_tick_get_millisecond();
+ }
+
+ dfs_aspace_unlock(aspace);
+
+ return 0;
+}
+
+static struct dfs_page *dfs_page_search(struct dfs_aspace *aspace, off_t fpos)
+{
+ int cmp;
+ struct dfs_page *page;
+ struct util_avl_struct *avl_node;
+
+ dfs_aspace_lock(aspace);
+
+ if (aspace->avl_page && dfs_page_compare(fpos, aspace->avl_page->fpos) == 0)
+ {
+ page = aspace->avl_page;
+ dfs_page_active(page);
+ dfs_page_ref(page);
+ dfs_aspace_unlock(aspace);
+ return page;
+ }
+
+ avl_node = aspace->avl_root.root_node;
+ while (avl_node)
+ {
+ page = rt_container_of(avl_node, struct dfs_page, avl_node);
+ cmp = dfs_page_compare(fpos, page->fpos);
+
+ if (cmp < 0)
+ {
+ avl_node = avl_node->avl_left;
+ }
+ else if (cmp > 0)
+ {
+ avl_node = avl_node->avl_right;
+ }
+ else
+ {
+ aspace->avl_page = page;
+ dfs_page_active(page);
+ dfs_page_ref(page);
+ dfs_aspace_unlock(aspace);
+ return page;
+ }
+ }
+
+ dfs_aspace_unlock(aspace);
+
+ return RT_NULL;
+}
+
+static struct dfs_page *dfs_aspace_load_page(struct dfs_file *file, off_t pos)
+{
+ struct dfs_page *page = RT_NULL;
+
+ if (file && file->vnode && file->vnode->aspace)
+ {
+ struct dfs_vnode *vnode = file->vnode;
+ struct dfs_aspace *aspace = vnode->aspace;
+
+ page = dfs_page_create();
+ if (page)
+ {
+ page->aspace = aspace;
+ page->size = ARCH_PAGE_SIZE;
+ page->fpos = pos / ARCH_PAGE_SIZE * ARCH_PAGE_SIZE;
+ aspace->ops->read(file, page);
+ //rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
+ page->ref_count ++;
+
+ dfs_page_insert(page);
+ }
+ }
+
+ return page;
+}
+
+static struct dfs_page *dfs_page_lookup(struct dfs_file *file, off_t pos)
+{
+ struct dfs_page *page = RT_NULL;
+ struct dfs_aspace *aspace = file->vnode->aspace;
+
+ dfs_aspace_lock(aspace);
+ page = dfs_page_search(aspace, pos);
+ if (!page)
+ {
+ int count = RT_PAGECACHE_PRELOAD;
+ struct dfs_page *tmp = RT_NULL;
+ off_t fpos = pos / ARCH_PAGE_SIZE * ARCH_PAGE_SIZE;
+
+ do
+ {
+ page = dfs_aspace_load_page(file, fpos);
+ if (page)
+ {
+ if (tmp == RT_NULL)
+ {
+ tmp = page;
+ }
+ else
+ {
+ dfs_page_release(page);
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ fpos += ARCH_PAGE_SIZE;
+ page = dfs_page_search(aspace, fpos);
+ if (page)
+ {
+ dfs_page_release(page);
+ }
+ count --;
+
+ } while (count && page == RT_NULL);
+
+ page = tmp;
+ if (page)
+ {
+ dfs_aspace_unlock(aspace);
+
+ if (rt_atomic_load(&(__pcache.pages_count)) >= RT_PAGECACHE_COUNT)
+ {
+ dfs_pcache_limit_check();
+ }
+ else if (rt_atomic_load(&(__pcache.pages_count)) >= RT_PAGECACHE_COUNT * RT_PAGECACHE_GC_WORK_LEVEL / 100)
+ {
+ dfs_pcache_mq_work(PCACHE_MQ_GC);
+ }
+
+ return page;
+ }
+ }
+ dfs_aspace_unlock(aspace);
+
+ return page;
+}
+
+int dfs_aspace_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
+{
+ int ret = -EINVAL;
+
+ if (file && file->vnode && file->vnode->aspace)
+ {
+ struct dfs_vnode *vnode = file->vnode;
+ struct dfs_aspace *aspace = vnode->aspace;
+
+ struct dfs_page *page;
+ char *ptr = (char *)buf;
+
+ ret = 0;
+
+ while (count)
+ {
+ page = dfs_page_lookup(file, *pos);
+ if (page)
+ {
+ off_t len;
+
+ dfs_aspace_lock(aspace);
+ if (aspace->vnode->size < page->fpos + ARCH_PAGE_SIZE)
+ {
+ len = aspace->vnode->size - *pos;
+ }
+ else
+ {
+ len = page->fpos + ARCH_PAGE_SIZE - *pos;
+ }
+
+ len = count > len ? len : count;
+ if (len)
+ {
+ //rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
+ rt_memcpy(ptr, page->page + *pos - page->fpos, len);
+ ptr += len;
+ *pos += len;
+ count -= len;
+ ret += len;
+ }
+ else
+ {
+ dfs_page_release(page);
+ dfs_aspace_unlock(aspace);
+ break;
+ }
+ dfs_page_release(page);
+ dfs_aspace_unlock(aspace);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
+{
+ int ret = -EINVAL;
+
+ if (file && file->vnode && file->vnode->aspace)
+ {
+ struct dfs_vnode *vnode = file->vnode;
+ struct dfs_aspace *aspace = vnode->aspace;
+
+ struct dfs_page *page;
+ char *ptr = (char *)buf;
+
+ ret = 0;
+
+ while (count)
+ {
+ page = dfs_page_lookup(file, *pos);
+ if (page)
+ {
+ off_t len;
+
+ dfs_aspace_lock(aspace);
+ len = page->fpos + ARCH_PAGE_SIZE - *pos;
+ len = count > len ? len : count;
+ rt_memcpy(page->page + *pos - page->fpos, ptr, len);
+ //rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
+ ptr += len;
+ *pos += len;
+ count -= len;
+ ret += len;
+
+ if (*pos > aspace->vnode->size)
+ {
+ aspace->vnode->size = *pos;
+ }
+
+ dfs_page_dirty(page);
+ dfs_page_release(page);
+ dfs_aspace_unlock(aspace);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int dfs_aspace_flush(struct dfs_aspace *aspace)
+{
+ if (aspace)
+ {
+ rt_list_t *next;
+ struct dfs_page *page;
+
+ dfs_aspace_lock(aspace);
+
+ if (aspace->pages_count > 0 && aspace->vnode)
+ {
+ rt_list_for_each(next, &aspace->list_dirty)
+ {
+ page = rt_list_entry(next, struct dfs_page, dirty_node);
+ if (page->is_dirty == 1 && aspace->vnode)
+ {
+ if (aspace->vnode->size < page->fpos + page->size)
+ {
+ page->len = aspace->vnode->size - page->fpos;
+ }
+ else
+ {
+ page->len = page->size;
+ }
+ //rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
+
+ aspace->ops->write(page);
+
+ page->is_dirty = 0;
+ }
+ RT_ASSERT(page->is_dirty == 0);
+ }
+ }
+
+ dfs_aspace_unlock(aspace);
+ }
+ return 0;
+}
+
+int dfs_aspace_clean(struct dfs_aspace *aspace)
+{
+ if (aspace)
+ {
+ dfs_aspace_lock(aspace);
+
+ if (aspace->pages_count > 0)
+ {
+ rt_list_t *next = aspace->list_active.next;
+ struct dfs_page *page;
+
+ while (next && next != &aspace->list_active)
+ {
+ if (next == &aspace->list_inactive)
+ {
+ next = next->next;
+ continue;
+ }
+ page = rt_list_entry(next, struct dfs_page, space_node);
+ next = next->next;
+ dfs_page_remove(page);
+ }
+ }
+
+ dfs_aspace_unlock(aspace);
+ }
+
+ return 0;
+}
+
+void *dfs_aspace_mmap(struct dfs_file *file, struct rt_varea *varea, void *vaddr)
+{
+ void *ret = RT_NULL;
+ struct dfs_page *page;
+ struct dfs_aspace *aspace = file->vnode->aspace;
+
+ page = dfs_page_lookup(file, dfs_aspace_fpos(varea, vaddr));
+ if (page)
+ {
+ struct dfs_mmap *map = (struct dfs_mmap *)rt_calloc(1, sizeof(struct dfs_mmap));
+ if (map)
+ {
+ void *pg_paddr = rt_kmem_v2p(page->page);
+ int err = rt_varea_map_range(varea, vaddr, pg_paddr, page->size);
+ if (err == RT_EOK)
+ {
+ ret = page->page;
+ map->varea = varea;
+ dfs_aspace_lock(aspace);
+ rt_list_insert_after(&page->mmap_head, &map->mmap_node);
+ dfs_page_release(page);
+ dfs_aspace_unlock(aspace);
+ }
+ else
+ {
+ dfs_page_release(page);
+ rt_free(map);
+ }
+ }
+ else
+ {
+ dfs_page_release(page);
+ }
+ }
+
+ return ret;
+}
+
+int dfs_aspace_unmap(struct dfs_file *file, struct rt_varea *varea)
+{
+ struct dfs_vnode *vnode = file->vnode;
+ struct dfs_aspace *aspace = vnode->aspace;
+
+ if (aspace)
+ {
+ rt_list_t *next;
+ struct dfs_page *page;
+
+ dfs_aspace_lock(aspace);
+ if (aspace->pages_count > 0)
+ {
+ rt_list_for_each(next, &aspace->list_active)
+ {
+ if (next != &aspace->list_inactive)
+ {
+ page = rt_list_entry(next, struct dfs_page, space_node);
+ if (page)
+ {
+ rt_list_t *node, *tmp;
+ struct dfs_mmap *map;
+
+ node = page->mmap_head.next;
+
+ while (node != &page->mmap_head)
+ {
+ map = rt_list_entry(node, struct dfs_mmap, mmap_node);
+ tmp = node;
+ node = node->next;
+
+ if (map && varea == map->varea)
+ {
+ if (varea->attr == MMU_MAP_U_RWCB && page->fpos < page->aspace->vnode->size)
+ {
+ dfs_page_dirty(page);
+ }
+ rt_list_remove(tmp);
+ rt_free(map);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ dfs_aspace_unlock(aspace);
+ }
+
+ return 0;
+}
+
+int dfs_aspace_page_unmap(struct dfs_file *file, struct rt_varea *varea, void *vaddr)
+{
+ struct dfs_page *page;
+ struct dfs_aspace *aspace = file->vnode->aspace;
+
+ if (aspace)
+ {
+ dfs_aspace_lock(aspace);
+
+ page = dfs_page_search(aspace, dfs_aspace_fpos(varea, vaddr));
+ if (page)
+ {
+ rt_list_t *node, *tmp;
+ struct dfs_mmap *map;
+
+ node = page->mmap_head.next;
+
+ while (node != &page->mmap_head)
+ {
+ map = rt_list_entry(node, struct dfs_mmap, mmap_node);
+ tmp = node;
+ node = node->next;
+
+ if (map && varea == map->varea)
+ {
+ if (varea->attr == MMU_MAP_U_RWCB)
+ {
+ dfs_page_dirty(page);
+ }
+ rt_list_remove(tmp);
+ rt_free(map);
+ break;
+ }
+ }
+
+ dfs_page_release(page);
+ }
+
+ dfs_aspace_unlock(aspace);
+ }
+
+ return 0;
+}
+
+int dfs_aspace_page_dirty(struct dfs_file *file, struct rt_varea *varea, void *vaddr)
+{
+ struct dfs_page *page;
+ struct dfs_aspace *aspace = file->vnode->aspace;
+
+ if (aspace)
+ {
+ dfs_aspace_lock(aspace);
+
+ page = dfs_page_search(aspace, dfs_aspace_fpos(varea, vaddr));
+ if (page)
+ {
+ dfs_page_dirty(page);
+ dfs_page_release(page);
+ }
+
+ dfs_aspace_unlock(aspace);
+ }
+
+ return 0;
+}
+
+off_t dfs_aspace_fpos(struct rt_varea *varea, void *vaddr)
+{
+ return (off_t)(intptr_t)vaddr - (off_t)(intptr_t)varea->start + varea->offset * ARCH_PAGE_SIZE;
+}
+
+void *dfs_aspace_vaddr(struct rt_varea *varea, off_t fpos)
+{
+ return varea->start + fpos - varea->offset * ARCH_PAGE_SIZE;
+}
+
+int dfs_aspace_mmap_read(struct dfs_file *file, struct rt_varea *varea, void *data)
+{
+ int ret = 0;
+
+ if (file && varea)
+ {
+ struct rt_aspace_io_msg *msg = (struct rt_aspace_io_msg *)data;
+ if (msg)
+ {
+ off_t fpos = dfs_aspace_fpos(varea, msg->fault_vaddr);
+ return dfs_aspace_read(file, msg->buffer_vaddr, ARCH_PAGE_SIZE, &fpos);
+ }
+ }
+
+ return ret;
+}
+
+int dfs_aspace_mmap_write(struct dfs_file *file, struct rt_varea *varea, void *data)
+{
+ int ret = 0;
+
+ if (file && varea)
+ {
+ struct rt_aspace_io_msg *msg = (struct rt_aspace_io_msg *)data;
+ if (msg)
+ {
+ off_t fpos = dfs_aspace_fpos(varea, msg->fault_vaddr);
+ return dfs_aspace_write(file, msg->buffer_vaddr, ARCH_PAGE_SIZE, &fpos);
+ }
+ }
+
+ return ret;
+}
+
+#endif
diff --git a/components/dfs/dfs_v2/src/dfs_posix.c b/components/dfs/dfs_v2/src/dfs_posix.c
index 3319efe2bf..77ffe20516 100644
--- a/components/dfs/dfs_v2/src/dfs_posix.c
+++ b/components/dfs/dfs_v2/src/dfs_posix.c
@@ -1216,53 +1216,46 @@ FINSH_FUNCTION_EXPORT_ALIAS(chdir, cd, change current working directory);
*/
int access(const char *path, int amode)
{
- int fd, ret = -1, flags = 0;
- struct stat sb;
+ struct stat st;
if (path == NULL)
{
- rt_set_errno(-EBADF);
+ rt_set_errno(-EINVAL);
return -1;
}
- if (amode == F_OK)
+ if (stat(path, &st) < 0)
{
- if (stat(path, &sb) < 0)
- return -1; /* already sets errno */
- else
- return 0;
- }
-
- /* ignore R_OK,W_OK,X_OK condition */
- if (dfs_file_isdir(path) == 0)
- {
- flags |= O_DIRECTORY;
+ rt_set_errno(-ENOENT);
+ return -1;
}
- if (amode & R_OK)
+ if (amode == F_OK)
{
- flags |= O_RDONLY;
+ return 0;
}
- if (amode & W_OK)
+ if ((amode & R_OK) && !(st.st_mode & S_IRUSR))
{
- flags |= O_WRONLY;
+ rt_set_errno(-EACCES);
+ return -1;
}
- if (amode & X_OK)
+ if ((amode & W_OK) && !(st.st_mode & S_IWUSR))
{
- flags |= O_EXEC;
+ rt_set_errno(-EACCES);
+ return -1;
}
- fd = open(path, flags, 0);
- if (fd >= 0)
+ if ((amode & X_OK) && !(st.st_mode & S_IXUSR))
{
- ret = 0;
- close(fd);
+ rt_set_errno(-EACCES);
+ return -1;
}
- return ret;
+ return 0;
}
+
/**
* this function is a POSIX compliant version, which will set current
* working directory.
diff --git a/components/dfs/dfs_v2/src/dfs_seq_file.c b/components/dfs/dfs_v2/src/dfs_seq_file.c
new file mode 100644
index 0000000000..58e80f8c4e
--- /dev/null
+++ b/components/dfs/dfs_v2/src/dfs_seq_file.c
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ */
+
+#include <dfs_seq_file.h>
+#include <dfs_dentry.h>
+
+#define DBG_TAG "DFS.seq"
+#define DBG_LVL DBG_WARNING
+#include <rtdbg.h>
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+static void dfs_seq_overflow(struct dfs_seq_file *seq)
+{
+ seq->count = seq->size;
+}
+
+static void *dfs_seq_alloc(unsigned long size)
+{
+ return rt_calloc(1, size);
+}
+
+int dfs_seq_open(struct dfs_file *file, const struct dfs_seq_ops *ops)
+{
+ struct dfs_seq_file *seq;
+
+ if (!ops)
+ {
+ LOG_E("dfs_seq_open: ops = null, pathname: %s\n", file->dentry->pathname);
+ return -EINVAL;
+ }
+
+ if (file->data)
+ {
+ LOG_W("dfs_seq_open: file->data != null\n");
+ }
+
+ seq = rt_calloc(1, sizeof(struct dfs_seq_file));
+ if (!seq)
+ return -ENOMEM;
+
+ file->data = seq;
+
+ rt_mutex_init(&seq->lock, "dfs_seq", RT_IPC_FLAG_PRIO);
+
+ seq->ops = ops;
+ seq->file = file;
+
+ return 0;
+}
+
+static int dfs_seq_traverse(struct dfs_seq_file *seq, off_t offset)
+{
+ off_t pos = 0;
+ int error = 0;
+ void *p;
+
+ seq->index = 0;
+ seq->count = seq->from = 0;
+ if (!offset)
+ return 0;
+
+ if (!seq->buf)
+ {
+ seq->buf = dfs_seq_alloc(seq->size = PAGE_SIZE);
+ if (!seq->buf)
+ return -ENOMEM;
+ }
+ p = seq->ops->start(seq, &seq->index);
+ while (p)
+ {
+ error = seq->ops->show(seq, p);
+ if (error < 0)
+ break;
+ if (error)
+ {
+ error = 0;
+ seq->count = 0;
+ }
+ if (dfs_seq_is_full(seq))
+ goto Eoverflow;
+
+ p = seq->ops->next(seq, p, &seq->index);
+ if (pos + seq->count > offset)
+ {
+ seq->from = offset - pos;
+ seq->count -= seq->from;
+ break;
+ }
+ pos += seq->count;
+ seq->count = 0;
+ if (pos == offset)
+ break;
+ }
+ seq->ops->stop(seq, p);
+ return error;
+
+Eoverflow:
+ seq->ops->stop(seq, p);
+ rt_free(seq->buf);
+ seq->count = 0;
+ seq->buf = dfs_seq_alloc(seq->size <<= 1);
+ return !seq->buf ? -ENOMEM : -EAGAIN;
+}
+
+ssize_t dfs_seq_read(struct dfs_file *file, void *buf, size_t size, off_t *pos)
+{
+ struct dfs_seq_file *seq = file->data;
+ size_t copied = 0;
+ size_t n;
+ void *p;
+ int err = 0;
+
+ if (!size)
+ return 0;
+
+ rt_mutex_take(&seq->lock, RT_WAITING_FOREVER);
+
+ /*
+ * if request is to read from zero offset, reset iterator to first
+ * record as it might have been already advanced by previous requests
+ */
+ if (*pos == 0)
+ {
+ seq->index = 0;
+ seq->count = 0;
+ }
+
+ /* Don't assume ki_pos is where we left it */
+ if (*pos != seq->read_pos)
+ {
+ while ((err = dfs_seq_traverse(seq, *pos)) == -EAGAIN)
+ ;
+ if (err)
+ {
+ /* With prejudice... */
+ seq->read_pos = 0;
+ seq->index = 0;
+ seq->count = 0;
+ goto Done;
+ }
+ else
+ {
+ seq->read_pos = *pos;
+ }
+ }
+
+ /* grab buffer if we didn't have one */
+ if (!seq->buf)
+ {
+ seq->buf = dfs_seq_alloc(seq->size = PAGE_SIZE);
+ if (!seq->buf)
+ goto Enomem;
+ }
+ // something left in the buffer - copy it out first
+ if (seq->count)
+ {
+ n = seq->count > size ? size : seq->count;
+ rt_memcpy((char *)buf + copied, seq->buf + seq->from, n);
+ size -= n;
+ seq->count -= n;
+ seq->from += n;
+ copied += n;
+ if (seq->count) // hadn't managed to copy everything
+ goto Done;
+ }
+ // get a non-empty record in the buffer
+ seq->from = 0;
+ p = seq->ops->start(seq, &seq->index);
+ while (p)
+ {
+ err = seq->ops->show(seq, p);
+ if (err < 0) // hard error
+ break;
+ if (err) // ->show() says "skip it"
+ seq->count = 0;
+ if (!seq->count)
+ { // empty record
+ p = seq->ops->next(seq, p, &seq->index);
+ continue;
+ }
+ if (!dfs_seq_is_full(seq)) // got it
+ goto Fill;
+ // need a bigger buffer
+ seq->ops->stop(seq, p);
+ rt_free(seq->buf);
+ seq->count = 0;
+ seq->buf = dfs_seq_alloc(seq->size <<= 1);
+ if (!seq->buf)
+ goto Enomem;
+ p = seq->ops->start(seq, &seq->index);
+ }
+ // EOF or an error
+ seq->ops->stop(seq, p);
+ seq->count = 0;
+ goto Done;
+Fill:
+ // one non-empty record is in the buffer; if they want more,
+ // try to fit more in, but in any case we need to advance
+ // the iterator once for every record shown.
+ while (1)
+ {
+ size_t offs = seq->count;
+ off_t pos = seq->index;
+
+ p = seq->ops->next(seq, p, &seq->index);
+ if (pos == seq->index)
+ {
+ LOG_W(".next function %p did not update position index\n", seq->ops->next);
+ seq->index++;
+ }
+ if (!p) // no next record for us
+ break;
+ if (seq->count >= size)
+ break;
+ err = seq->ops->show(seq, p);
+ if (err > 0)
+ { // ->show() says "skip it"
+ seq->count = offs;
+ }
+ else if (err || dfs_seq_is_full(seq))
+ {
+ seq->count = offs;
+ break;
+ }
+ }
+ seq->ops->stop(seq, p);
+ n = seq->count > size ? size : seq->count;
+ rt_memcpy((char *)buf + copied, seq->buf, n);
+ size -= n;
+ copied += n;
+ seq->count -= n;
+ seq->from = n;
+Done:
+ if (!copied)
+ {
+ copied = seq->count ? -EFAULT : err;
+ }
+ else
+ {
+ *pos += copied;
+ seq->read_pos += copied;
+ }
+ rt_mutex_release(&seq->lock);
+ return copied;
+Enomem:
+ err = -ENOMEM;
+ goto Done;
+}
+
+ssize_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
+{
+ struct dfs_seq_file *seq = file->data;
+ off_t retval = -EINVAL;
+
+ rt_mutex_take(&seq->lock, RT_WAITING_FOREVER);
+
+ switch (whence)
+ {
+ case SEEK_CUR:
+ offset += file->fpos;
+ case SEEK_SET:
+ if (offset < 0)
+ break;
+ retval = offset;
+ if (offset != seq->read_pos)
+ {
+ while ((retval = dfs_seq_traverse(seq, offset)) == -EAGAIN);
+ if (retval)
+ {
+ /* with extreme prejudice... */
+ retval = 0;
+ seq->read_pos = 0;
+ seq->index = 0;
+ seq->count = 0;
+ }
+ else
+ {
+ seq->read_pos = offset;
+ retval = offset;
+ }
+ }
+ }
+
+ rt_mutex_release(&seq->lock);
+
+ return retval;
+}
+
+int dfs_seq_release(struct dfs_file *file)
+{
+ struct dfs_seq_file *seq = file->data;
+
+ if (seq)
+ {
+ rt_mutex_detach(&seq->lock);
+ if (seq->buf)
+ {
+ rt_free(seq->buf);
+ }
+ rt_free(seq);
+ }
+
+ return 0;
+}
+
+void dfs_seq_vprintf(struct dfs_seq_file *seq, const char *f, va_list args)
+{
+ int len;
+
+ if (seq->count < seq->size)
+ {
+ len = vsnprintf(seq->buf + seq->count, seq->size - seq->count, f, args);
+ if (seq->count + len < seq->size)
+ {
+ seq->count += len;
+ return;
+ }
+ }
+ dfs_seq_overflow(seq);
+}
+
+void dfs_seq_printf(struct dfs_seq_file *seq, const char *f, ...)
+{
+ va_list args;
+
+ va_start(args, f);
+ dfs_seq_vprintf(seq, f, args);
+ va_end(args);
+}
+
+/**
+ * write char to buffer
+ */
+void dfs_seq_putc(struct dfs_seq_file *seq, char c)
+{
+ if (seq->count < seq->size)
+ {
+ seq->buf[seq->count++] = c;
+ }
+}
+
+/**
+ * write string to buffer
+ */
+void dfs_seq_puts(struct dfs_seq_file *seq, const char *s)
+{
+ int len = strlen(s);
+
+ if (seq->count + len >= seq->size)
+ {
+ dfs_seq_overflow(seq);
+ return;
+ }
+ rt_memcpy(seq->buf + seq->count, s, len);
+ seq->count += len;
+}
+
+/**
+ * write arbitrary data to buffer
+ */
+int dfs_seq_write(struct dfs_seq_file *seq, const void *data, size_t len)
+{
+ if (seq->count + len < seq->size)
+ {
+ rt_memcpy(seq->buf + seq->count, data, len);
+ seq->count += len;
+ return 0;
+ }
+ dfs_seq_overflow(seq);
+ return -1;
+}
+
+/**
+ * write padding spaces to buffer
+ */
+void dfs_seq_pad(struct dfs_seq_file *seq, char c)
+{
+ int size = seq->pad_until - seq->count;
+
+ if (size > 0)
+ {
+ if (size + seq->count > seq->size)
+ {
+ dfs_seq_overflow(seq);
+ return;
+ }
+ rt_memset(seq->buf + seq->count, ' ', size);
+ seq->count += size;
+ }
+
+ if (c)
+ {
+ dfs_seq_putc(seq, c);
+ }
+}
+
+#if 1
+/* test demo */
+
+static char *txt[4] = {
+ "text1",
+ "text2",
+ "text3",
+ "text4",
+};
+
+static void *seq_test_start(struct dfs_seq_file *seq, off_t *index)
+{
+ off_t i = *index; // seq->index
+
+ if (i >= 0 && i < 4)
+ {
+ return txt[i];
+ }
+
+ return RT_NULL;
+}
+
+static void seq_test_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_test_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+ off_t i = *index + 1; // seq->index
+
+ *index = i;
+
+ if (i >= 0 && i < 4)
+ {
+ return txt[i];
+ }
+
+ return RT_NULL;
+}
+
+static int seq_test_show(struct dfs_seq_file *seq, void *data)
+{
+ const char *text = (const char *)data;
+
+ dfs_seq_setwidth(seq, 20);
+ dfs_seq_puts(seq, "puts ");
+ dfs_seq_putc(seq, 'c');
+ dfs_seq_write(seq, " write", 6);
+ dfs_seq_printf(seq, " %s", text);
+ dfs_seq_pad(seq, 0);
+
+ return 0;
+}
+
+static const struct dfs_seq_ops _test_ops = {
+ .start = seq_test_start,
+ .stop = seq_test_stop,
+ .next = seq_test_next,
+ .show = seq_test_show,
+};
+
+static int dfs_seq_test(int argc, char **argv)
+{
+ struct dfs_file file = {0};
+ int ret = dfs_seq_open(&file, &_test_ops);
+
+ if (ret == 0)
+ {
+ char buf[256] = {0};
+ off_t pos = (argc > 1) ? atoi(argv[1]) : 0;
+ ssize_t len = (argc > 2) ? atoi(argv[2]) : 255;
+
+ if (len > 255)
+ {
+ len = 255;
+ rt_kprintf("buf len is %d, max read is 255\n", 256, len);
+ }
+
+ len = dfs_seq_read(&file, buf, len, &pos);
+ buf[len] = '\0';
+
+ rt_kprintf("show: \"%s\" len: %d\n", buf, len);
+ dfs_seq_release(&file);
+ }
+
+ return 0;
+}
+MSH_CMD_EXPORT_ALIAS(dfs_seq_test, seq_test, seq_test[pos][read_len]);
+#endif
diff --git a/components/dfs/dfs_v2/src/dfs_vnode.c b/components/dfs/dfs_v2/src/dfs_vnode.c
index d3af9b3970..21778e683c 100644
--- a/components/dfs/dfs_v2/src/dfs_vnode.c
+++ b/components/dfs/dfs_v2/src/dfs_vnode.c
@@ -10,6 +10,9 @@
#include <dfs_file.h>
#include <dfs_mnt.h>
+#ifdef RT_USING_PAGECACHE
+#include "dfs_pcache.h"
+#endif
#define DBG_TAG "DFS.vnode"
#define DBG_LVL DBG_WARNING
@@ -58,7 +61,12 @@ int dfs_vnode_destroy(struct dfs_vnode* vnode)
if (rt_atomic_load(&(vnode->ref_count)) == 1)
{
LOG_I("free a vnode: %p", vnode);
-
+#ifdef RT_USING_PAGECACHE
+ if (vnode->aspace)
+ {
+ dfs_aspace_destroy(vnode->aspace);
+ }
+#endif
if (vnode->mnt)
{
DLOG(msg, "vnode", vnode->mnt->fs_ops->name, DLOG_MSG, "fs_ops->free_vnode");
@@ -106,7 +114,12 @@ void dfs_vnode_unref(struct dfs_vnode *vnode)
{
rt_atomic_sub(&(vnode->ref_count), 1);
DLOG(note, "vnode", "vnode ref_count=%d", rt_atomic_load(&(vnode->ref_count)));
-
+#ifdef RT_USING_PAGECACHE
+ if (vnode->aspace)
+ {
+ dfs_aspace_destroy(vnode->aspace);
+ }
+#endif
if (rt_atomic_load(&(vnode->ref_count)) == 0)
{
LOG_I("free a vnode: %p", vnode);