diff options
| author | geniusgogo <[email protected]> | 2023-10-17 13:07:59 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-10-17 13:07:59 +0800 |
| commit | ecd29fda6005ef19c625f194f9311259ba907a78 (patch) | |
| tree | d0e272f5783ac4a3048238e14a37bcd88b5dc3e6 /components/dfs | |
| parent | 7d64cdcf58969b1b2b7e9cfb3aac9e46cb456ae3 (diff) | |
Sync dfs lwp (#8123)
Diffstat (limited to 'components/dfs')
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); |
