1
0
Эх сурвалжийг харах

[components][fs]sync procfs (#9206)

* add procfs

* fix ref count check error
zms123456 3 сар өмнө
parent
commit
4343d32df4
22 өөрчлөгдсөн 3327 нэмэгдсэн , 0 устгасан
  1. 3 0
      components/dfs/Kconfig
  2. 166 0
      components/dfs/dfs_v2/filesystems/procfs/README.md
  3. 11 0
      components/dfs/dfs_v2/filesystems/procfs/SConscript
  4. 733 0
      components/dfs/dfs_v2/filesystems/procfs/proc.c
  5. 75 0
      components/dfs/dfs_v2/filesystems/procfs/proc.h
  6. 53 0
      components/dfs/dfs_v2/filesystems/procfs/proc_cmdline.c
  7. 86 0
      components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c
  8. 307 0
      components/dfs/dfs_v2/filesystems/procfs/proc_devices.c
  9. 85 0
      components/dfs/dfs_v2/filesystems/procfs/proc_filesystems.c
  10. 41 0
      components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c
  11. 66 0
      components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c
  12. 101 0
      components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
  13. 107 0
      components/dfs/dfs_v2/filesystems/procfs/proc_net.c
  14. 215 0
      components/dfs/dfs_v2/filesystems/procfs/proc_partitions.c
  15. 449 0
      components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
  16. 66 0
      components/dfs/dfs_v2/filesystems/procfs/proc_self.c
  17. 114 0
      components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
  18. 100 0
      components/dfs/dfs_v2/filesystems/procfs/proc_tty.c
  19. 38 0
      components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c
  20. 45 0
      components/dfs/dfs_v2/filesystems/procfs/proc_version.c
  21. 447 0
      components/dfs/dfs_v2/filesystems/procfs/procfs.c
  22. 19 0
      components/dfs/dfs_v2/filesystems/procfs/procfs.h

+ 3 - 0
components/dfs/Kconfig

@@ -185,6 +185,9 @@ if RT_USING_SMART
         bool "Using Pseudo-Teletype Filesystem (UNIX98 PTY)"
         depends on RT_USING_DFS_DEVFS
         default y
+    config RT_USING_DFS_PROCFS
+        bool "Enable proc file system"
+        default n
 endif
 
     config RT_USING_DFS_CROMFS

+ 166 - 0
components/dfs/dfs_v2/filesystems/procfs/README.md

@@ -0,0 +1,166 @@
+# 进程文件系统 (procfs)
+
+## 数据结构
+
+```c
+struct proc_dentry
+{
+    rt_uint32_t mode;
+    rt_atomic_t ref_count;
+
+    struct proc_dentry *parent;
+    struct dfs_vfs_node node;
+
+    const struct dfs_file_ops *fops;
+    const struct proc_ops *ops;
+
+    char *name;
+    void *data;
+};
+```
+
+```log
+root { mode: S_IFDIR, ref_count: 1, parent: root, name: /, child->next: file1->node }
+    |
+    |—— file1 { mode: S_IFREG, ref_count: 1, parent: root, name: file1, node->next: link1->node }
+    |—— link1 { mode: S_IFLNK, ref_count: 1, parent: root, name: link1, data: fullpath, node->next: dir1->node }
+    |—— dir1 { mode: S_IFDIR, ref_count: 1, parent: root, name: dir1, node->next: file3->node, child->next: file2->node }
+    |    |
+    |    |—— dir2 { mode: S_IFDIR, ref_count: 1, parent: dir1, name: dir2, node->next: link2->node }
+    |    |—— link2 { mode: S_IFLNK, ref_count: 1, parent: dir1, name: link2, data: fullpath, node->next: file2->node }
+    |    |—— file2 { mode: S_IFREG, ref_count: 1, parent: dir1, name: file2 }
+    |
+    |—— file3 { mode: S_IFREG, ref_count: 1, parent: root, name: file3 }
+```
+
+## API 介绍
+
+```c
+struct proc_dentry *dfs_proc_find(const char *name);
+
+struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                    const struct dfs_file_ops *fops, void *data);
+struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent);
+struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent);
+
+struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                     const struct dfs_file_ops *fops, void *data);
+
+struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest);
+
+struct proc_dentry *proc_acquire(struct proc_dentry *dentry);
+void proc_release(struct proc_dentry *dentry);
+
+void proc_remove(struct proc_dentry *dentry);
+```
+
+- dfs_proc_find
+
+  查找指定节点,并返回节点数据指针
+
+  | 入参 | 说明                                                 |
+  | ---- | ---------------------------------------------------- |
+  | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2” |
+
+- proc_mkdir_data
+
+  创建一个目录,并返回节点数据指针
+
+  | 入参   | 说明                                                         |
+  | ------ | ------------------------------------------------------------ |
+  | name   | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
+  | mode   | 权限配置                                                     |
+  | parent | 指定创建目录的起始节点                                       |
+  | fops   | 文件操作接口配置                                             |
+  | data   | 私有数据                                                     |
+
+- proc_mkdir_mode
+
+  创建一个目录,并返回节点数据指针
+
+  | 入参   | 说明                                                         |
+  | ------ | ------------------------------------------------------------ |
+  | name   | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
+  | mode   | 权限配置                                                     |
+  | parent | 指定创建目录的起始节点                                       |
+
+- proc_mkdir
+
+  创建一个目录,并返回节点数据指针
+
+  | 入参 | 说明                                                         |
+  | ---- | ------------------------------------------------------------ |
+  | name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
+  | mode | 权限配置                                                     |
+
+- proc_create_data
+
+  创建一个文件,并返回节点数据指针
+
+  | 入参   | 说明                                                         |
+  | ------ | ------------------------------------------------------------ |
+  | name   | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
+  | mode   | 权限配置                                                     |
+  | parent | 指定创建文件的起始节点                                       |
+  | fops   | 文件操作接口配置                                             |
+  | data   | 私有数据                                                     |
+
+- proc_symlink
+
+  创建一个符号链接,并返回节点数据指针
+
+  | 入参   | 说明                                                         |
+  | ------ | ------------------------------------------------------------ |
+  | name   | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
+  | parent | 指定创建文件的起始节点                                       |
+  | dest   | 链接的目标文件完整路径                                       |
+
+- proc_acquire
+
+  引用一个节点,并返回节点数据指针
+
+  | 入参   | 说明           |
+  | ------ | -------------- |
+  | dentry | 需要引用的节点 |
+
+- proc_release
+
+  释放一个节点
+
+  | 入参   | 说明           |
+  | ------ | -------------- |
+  | dentry | 需要释放的节点 |
+
+- proc_remove
+
+  删除一个节点包含子节点
+
+  | 入参   | 说明           |
+  | ------ | -------------- |
+  | dentry | 需要删除的节点 |
+
+## msh 调试命令
+
+- proc_dump
+
+  遍历打印指定节点含子节点的信息(名称、引用计数),比如 `proc_dump /dir1` 或者 `proc_dump`
+
+- proc_remove
+
+  删除指定节点含子节点,比如 `proc_remove /dir1` 或者 `proc_remove /file3`
+
+- proc_symlink
+
+  创建一个符号链接,`proc_symlink /link3 /mnt`
+
+- proc_echo
+
+  创建一个空文件,`proc_echo /file4`
+
+- proc_mkdir
+
+  创建一个空目录,`proc_mkdir /dir3`
+
+- proc_pid
+
+ 创建一个 pid 目录,`proc_pid /101`

+ 11 - 0
components/dfs/dfs_v2/filesystems/procfs/SConscript

@@ -0,0 +1,11 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_PROCFS'], CPPPATH = CPPPATH)
+
+Return('group')

+ 733 - 0
components/dfs/dfs_v2/filesystems/procfs/proc.c

@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+/*
+ * This is the root in the proc tree..
+ */
+static struct proc_dentry _proc_root = {
+    .mode       = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH),
+    .ref_count  = 1,
+
+    .parent = &_proc_root,
+    .node.sibling = RT_LIST_OBJECT_INIT(_proc_root.node.sibling),
+    .node.subnode = RT_LIST_OBJECT_INIT(_proc_root.node.subnode),
+
+    .fops = RT_NULL,
+
+    .name = "/",
+    .data = RT_NULL,
+};
+
+static int _proc_find(struct proc_dentry **parent, const char *name)
+{
+    struct proc_dentry *dentry = RT_NULL, *tmp;
+
+    dfs_vfs_for_each_subnode(dentry, tmp, (*parent), node)
+    {
+        if (dentry == RT_NULL)
+        {
+            break;
+        }
+
+        if (rt_strcmp(dentry->name, name) == 0)
+        {
+            *parent = dentry;
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+static int proc_find(struct proc_dentry **parent, const char **name, rt_bool_t force_lookup)
+{
+    int ret = 0;
+    char *tmp = RT_NULL;
+
+    if (!(*parent))
+    {
+        *parent = &_proc_root;
+    }
+
+    tmp = rt_strdup(*name);
+    if (tmp)
+    {
+        char *begin = tmp, *end = RT_NULL;
+        if (*begin == '/')
+        {
+            begin++;
+            if (*begin == '\0')
+            {
+                rt_free(tmp);
+                *parent = proc_acquire(*parent);
+                return ret;
+            }
+        }
+
+        while (1)
+        {
+            end = rt_strstr(begin, "/");
+            if (end)
+            {
+                *end = '\0';
+                ret = _proc_find(parent, begin);
+                if (ret < 0 || !S_ISDIR((*parent)->mode))
+                {
+                    *parent = RT_NULL;
+                    ret = -1;
+                    break;
+                }
+                begin = end + 1;
+            }
+            else if (force_lookup)
+            {
+                ret = _proc_find(parent, begin);
+                if (ret < 0)
+                {
+                    if ((*parent)->ops && (*parent)->ops->lookup)
+                    {
+                        *parent = (*parent)->ops->lookup(*parent, begin);
+                        if (*parent == RT_NULL)
+                        {
+                            ret = -1;
+                        }
+                    }
+                    else
+                    {
+                        *parent = RT_NULL;
+                    }
+                }
+                else
+                {
+                    *parent = proc_acquire(*parent);
+                }
+                break;
+            }
+            else
+            {
+                *parent = proc_acquire(*parent);
+                break;
+            }
+        }
+
+        *name = *name + (begin - tmp);
+
+        rt_free(tmp);
+    }
+
+    return ret;
+}
+
+static void *single_start(struct dfs_seq_file *seq, off_t *index)
+{
+    return NULL + (*index == 0);
+}
+
+static void *single_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    ++*index;
+    return NULL;
+}
+
+static void single_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static int proc_open(struct dfs_file *file)
+{
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (entry->single_show)
+    {
+        struct dfs_seq_ops *seq_ops = (struct dfs_seq_ops *)rt_calloc(1, sizeof(struct dfs_seq_ops));
+        if (seq_ops)
+        {
+            int ret = 0;
+
+            seq_ops->start = single_start;
+            seq_ops->next = single_next;
+            seq_ops->stop = single_stop;
+            seq_ops->show = entry->single_show;
+
+            ret = dfs_seq_open(file, seq_ops);
+            if (ret != 0)
+            {
+                rt_free(seq_ops);
+            }
+            return ret;
+        }
+    }
+
+    return dfs_seq_open(file, entry->seq_ops);
+}
+
+static int proc_close(struct dfs_file *file)
+{
+    struct dfs_seq_file *seq = file->data;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (seq && entry->single_show && seq->ops)
+    {
+        rt_free((void *)seq->ops);
+        seq->ops = RT_NULL;
+    }
+
+    return dfs_seq_release(file);
+}
+
+static const struct dfs_file_ops proc_file_ops = {
+    .open   = proc_open,
+    .read   = dfs_seq_read,
+    .lseek  = dfs_seq_lseek,
+    .close  = proc_close,
+};
+
+static struct proc_dentry *proc_create(struct proc_dentry **parent, const char *name, mode_t mode)
+{
+    int ret = 0;
+    struct proc_dentry *dentry = RT_NULL;
+
+    ret = proc_find(parent, &name, 0);
+    if (ret >= 0)
+    {
+        dentry = *parent;
+        ret = proc_find(&dentry, &name, 1);
+        if (ret < 0)
+        {
+            dentry = rt_calloc(1, sizeof(struct proc_dentry));
+            if (dentry)
+            {
+                dentry->mode = mode;
+                dentry->ref_count = 1;
+                dentry->name = rt_strdup(name);
+                dfs_vfs_init_node(&dentry->node);
+            }
+        }
+        else
+        {
+            proc_release(dentry);
+            dentry = RT_NULL;
+        }
+    }
+
+    return dentry;
+}
+
+/**
+ * @brief    The dentry reference count is incremented by one
+ *
+ * @param    dentry
+ *
+ * @return   dentry
+ */
+struct proc_dentry *proc_acquire(struct proc_dentry *dentry)
+{
+    if (dentry)
+    {
+        dentry->ref_count += 1;
+    }
+
+    return dentry;
+}
+
+/**
+ * @brief    The dentry reference count is minus one, or release
+ *
+ * @param    dentry
+ *
+ * @return   none
+ */
+void proc_release(struct proc_dentry *dentry)
+{
+    if (dentry)
+    {
+        if (dentry->ref_count == 1)
+        {
+            if (dentry->name)
+            {
+                rt_free(dentry->name);
+            }
+
+            if (S_ISLNK(dentry->mode) && dentry->data)
+            {
+                rt_free(dentry->data);
+            }
+
+            rt_free(dentry);
+        }
+        else
+        {
+            dentry->ref_count -= 1;
+        }
+    }
+}
+
+static struct proc_dentry *proc_register(struct proc_dentry *parent, struct proc_dentry *child)
+{
+    child->parent = parent;
+    dfs_vfs_append_node(&parent->node, &child->node);
+    child->ref_count += 1;
+    child->pid = parent->pid;
+
+    return child;
+}
+
+/**
+ * @brief    Make a dir
+ *
+ * @param    name fullpath based on _proc_root or parent
+ * @param    mode permission configuration
+ * @param    parent can be empty
+ * @param    fops
+ * @param    data
+ *
+ * @return   dentry
+ */
+struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                    const struct dfs_file_ops *fops, void *data)
+{
+    struct proc_dentry *dentry, *_parent = parent;
+
+    if (mode == 0)
+        mode = (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
+
+    dentry = proc_create(&_parent, name, S_IFDIR | mode);
+    if (dentry)
+    {
+        dentry->fops = fops;
+        dentry->data = data;
+
+        dentry = proc_register(_parent, dentry);
+    }
+    proc_release(_parent);
+
+    return dentry;
+}
+
+/**
+ * @brief    Make a dir
+ *
+ * @param    name fullpath based on _proc_root or parent
+ * @param    mode permission configuration
+ * @param    parent can be empty
+ *
+ * @return   dentry
+ */
+struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent)
+{
+    return proc_mkdir_data(name, mode, parent, NULL, NULL);
+}
+
+/**
+ * @brief    Make a dir
+ *
+ * @param    name fullpath based on _proc_root or parent
+ * @param    parent can be empty
+ *
+ * @return   dentry
+ */
+struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent)
+{
+    return proc_mkdir_data(name, 0, parent, NULL, NULL);
+}
+
+static struct proc_dentry *proc_create_reg(const char *name, mode_t mode, struct proc_dentry **parent)
+{
+    struct proc_dentry *dentry = RT_NULL;
+
+    if ((mode & S_IFMT) == 0)
+        mode |= S_IFREG;
+    if ((mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)) == 0)
+        mode |= S_IRUSR | S_IRGRP | S_IROTH;
+
+    if (!S_ISREG(mode))
+    {
+        *parent = RT_NULL;
+        return dentry;
+    }
+
+    return proc_create(parent, name, mode);
+}
+
+/**
+ * @brief    Make a file
+ *
+ * @param    name fullpath based on _proc_root or parent
+ * @param    mode permission configuration
+ * @param    parent can be empty
+ * @param    fops
+ * @param    data
+ *
+ * @return   dentry
+ */
+struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                     const struct dfs_file_ops *fops, void *data)
+{
+    struct proc_dentry *dentry, *_parent = parent;
+
+    dentry = proc_create_reg(name, mode, &_parent);
+    if (dentry)
+    {
+        dentry->fops = fops ? fops : &proc_file_ops;
+        dentry->data = data;
+
+        dentry = proc_register(_parent, dentry);
+    }
+    proc_release(_parent);
+
+    return dentry;
+}
+
+/**
+ * @brief    Make a file
+ *
+ * @param    name fullpath based on _proc_root or parent
+ * @param    mode permission configuration
+ * @param    parent can be empty
+ * @param    show
+ * @param    data
+ *
+ * @return   dentry
+ */
+struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                            int (*show)(struct dfs_seq_file *, void *), void *data)
+{
+    struct proc_dentry *dentry, *_parent = parent;
+
+    dentry = proc_create_reg(name, mode, &_parent);
+    if (dentry)
+    {
+        dentry->fops = &proc_file_ops;
+        dentry->single_show = show;
+        dentry->data = data;
+
+        dentry = proc_register(_parent, dentry);
+    }
+    proc_release(_parent);
+
+    return dentry;
+}
+
+/**
+ * @brief    Make a symlink
+ *
+ * @param    name fullpath based on _proc_root or parent
+ * @param    parent can be empty
+ * @param    dest  link file fullpath
+ *
+ * @return   dentry
+ */
+struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest)
+{
+    struct proc_dentry *dentry, *_parent = parent;
+
+    dentry = proc_create(&_parent, name, (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH)
+                         | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH)));
+    if (dentry)
+    {
+        dentry->data = (void *)rt_strdup(dest);
+        if (dentry->data)
+        {
+            dentry = proc_register(_parent, dentry);
+        }
+        else
+        {
+            proc_release(dentry);
+            dentry = NULL;
+        }
+    }
+    proc_release(_parent);
+
+    return dentry;
+}
+
+static void remove_proc_subtree(struct proc_dentry *dentry)
+{
+    struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
+
+    dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
+    {
+        if (iter == RT_NULL)
+        {
+            break;
+        }
+
+        if (tmp)
+        {
+            proc_release(tmp);
+            tmp = RT_NULL;
+        }
+
+        tmp = iter;
+
+        if (S_ISDIR(dentry->mode))
+        {
+            remove_proc_subtree(iter);
+        }
+    }
+
+    if (tmp)
+    {
+        proc_release(tmp);
+        tmp = RT_NULL;
+    }
+}
+
+/**
+ * @brief    remove a dentry
+ *
+ * @param    dentry
+ *
+ * @return   none
+ */
+void proc_remove(struct proc_dentry *dentry)
+{
+    if (dentry && dentry != &_proc_root)
+    {
+        if (S_ISDIR(dentry->mode))
+        {
+            remove_proc_subtree(dentry);
+        }
+
+        dfs_vfs_remove_node(&dentry->node);
+        proc_release(dentry);
+    }
+}
+
+/**
+ * @brief    find dentry exist
+ *
+ * @param    name fullpath based on _proc_root
+ *
+ * @return   dentry
+ */
+struct proc_dentry *dfs_proc_find(const char *name)
+{
+    struct proc_dentry *dentry = RT_NULL;
+
+    proc_find(&dentry, &name, 1);
+
+    return dentry;
+}
+
+/**
+ * @brief    remove a dentry on parent
+ *
+ * @param    name fullpath based on parent
+ * @param    parent
+ *
+ * @return   none
+ */
+void proc_remove_dentry(const char *name, struct proc_dentry *parent)
+{
+    struct proc_dentry *dentry = parent;
+
+    if (proc_find(&dentry, &name, 1) >= 0)
+    {
+        proc_remove(dentry);
+        proc_release(dentry);
+    }
+}
+
+#define _COLOR_RED      "\033[31m"
+#define _COLOR_GREEN    "\033[32m"
+#define _COLOR_BLUE     "\033[34m"
+#define _COLOR_CYAN     "\033[36m"
+#define _COLOR_WHITE    "\033[37m"
+#define _COLOR_NORMAL   "\033[0m"
+
+static void dump_proc_subtree(struct proc_dentry *dentry, int tab)
+{
+    struct proc_dentry *iter = RT_NULL, *tmp;
+
+    dfs_vfs_for_each_subnode(iter, tmp, dentry, node)
+    {
+        if (iter == RT_NULL)
+        {
+            break;
+        }
+
+        for(int i = 0; i < tab; i ++)
+        {
+            rt_kprintf("%-4s", i + 1 >= tab ? "|-" : " ");
+        }
+
+        if (S_ISDIR(iter->mode))
+        {
+            rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
+            dump_proc_subtree(iter, tab + 1);
+        }
+        else if (S_ISLNK(iter->mode))
+        {
+            rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
+        }
+        else
+        {
+            rt_kprintf("%-20s %d\n", iter->name, iter->ref_count);
+        }
+    }
+}
+
+static void proc_dump(struct proc_dentry *dentry)
+{
+    if (dentry)
+    {
+        if (S_ISDIR(dentry->mode))
+        {
+            rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
+            dump_proc_subtree(dentry, 1);
+        }
+        else if (S_ISLNK(dentry->mode))
+        {
+            rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
+        }
+        else
+        {
+            rt_kprintf("%-20s %d\n", dentry->name, dentry->ref_count);
+        }
+    }
+}
+
+static int msh_proc_dump(int argc, char** argv)
+{
+    const char *name = argc > 1 ? argv[1] : "/";
+    struct proc_dentry *dentry = RT_NULL;
+
+    int ret = proc_find(&dentry, &name, 1);
+    if (ret >= 0)
+    {
+        proc_dump(dentry);
+    }
+    proc_release(dentry);
+
+    return 0;
+}
+MSH_CMD_EXPORT_ALIAS(msh_proc_dump, proc_dump, proc dump);
+
+static int msh_proc_remove(int argc, char** argv)
+{
+    if (argc > 1)
+    {
+        const char *name = argv[1];
+        struct proc_dentry *dentry = RT_NULL;
+
+        int ret = proc_find(&dentry, &name, 1);
+        if (ret >= 0)
+        {
+            if (dentry != &_proc_root)
+            {
+                proc_remove(dentry);
+            }
+            else
+            {
+                struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
+
+                dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
+                {
+                    if (iter == RT_NULL)
+                    {
+                        break;
+                    }
+
+                    if (tmp)
+                    {
+                        proc_remove(tmp);
+                    }
+
+                    tmp = iter;
+                }
+
+                if (tmp)
+                {
+                    proc_remove(tmp);
+                }
+            }
+        }
+        proc_release(dentry);
+    }
+    else
+    {
+        rt_kprintf("proc_remove path\n");
+    }
+
+    return 0;
+}
+MSH_CMD_EXPORT_ALIAS(msh_proc_remove, proc_remove, proc remove);
+
+static int msh_proc_symlink(int argc, char** argv)
+{
+    if (argc > 2)
+    {
+        struct proc_dentry *entry = proc_symlink(argv[1], 0, argv[2]);
+        if (entry)
+        {
+            proc_release(entry);
+        }
+    }
+    else
+    {
+        rt_kprintf("proc_symlink path dest\n");
+    }
+
+    return 0;
+}
+MSH_CMD_EXPORT_ALIAS(msh_proc_symlink, proc_symlink, proc symlink);
+
+static int msh_proc_echo(int argc, char** argv)
+{
+    if (argc > 1)
+    {
+        for(int i = 1; i <= argc - 1; i ++)
+        {
+            struct proc_dentry *entry = proc_create_data(argv[i], 0, 0, 0, 0);
+            if (entry)
+            {
+                proc_release(entry);
+            }
+        }
+    }
+    else
+    {
+        rt_kprintf("proc_echo path\n");
+    }
+
+    return 0;
+}
+MSH_CMD_EXPORT_ALIAS(msh_proc_echo, proc_echo, proc echo);
+
+static int msh_proc_mkdir(int argc, char** argv)
+{
+    if (argc > 1)
+    {
+        for(int i = 1; i <= argc - 1; i ++)
+        {
+            struct proc_dentry *entry = proc_mkdir(argv[i], 0);
+            if (entry)
+            {
+                proc_release(entry);
+            }
+        }
+    }
+    else
+    {
+        rt_kprintf("proc_mkdir path\n");
+    }
+
+    return 0;
+}
+MSH_CMD_EXPORT_ALIAS(msh_proc_mkdir, proc_mkdir, proc mkdir);

+ 75 - 0
components/dfs/dfs_v2/filesystems/procfs/proc.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef __PROC_H__
+#define __PROC_H__
+
+#include <dfs_file.h>
+#include <dfs_seq_file.h>
+#include <dfs_vfs.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct proc_dentry;
+
+struct proc_ops
+{
+    struct proc_dentry *(*lookup)(struct proc_dentry *parent, const char *name);
+    int (*readlink)(struct proc_dentry *dentry, char *buf, int len);
+};
+
+struct proc_dentry
+{
+    rt_uint32_t mode;
+    rt_atomic_t ref_count;
+
+    struct proc_dentry *parent;
+    struct dfs_vfs_node node;
+
+    const struct dfs_file_ops *fops;
+    const struct proc_ops *ops;
+    const struct dfs_seq_ops *seq_ops;
+    int (*single_show)(struct dfs_seq_file *seq, void *data);
+
+    int pid;
+
+    char *name;
+    void *data;
+};
+
+struct proc_dentry *dfs_proc_find(const char *name);
+
+struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                    const struct dfs_file_ops *fops, void *data);
+struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent);
+struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent);
+
+struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                     const struct dfs_file_ops *fops, void *data);
+struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent,
+                                            int (*show)(struct dfs_seq_file *, void *), void *data);
+
+struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest);
+
+struct proc_dentry *proc_acquire(struct proc_dentry *dentry);
+void proc_release(struct proc_dentry *dentry);
+
+void proc_remove(struct proc_dentry *dentry);
+void proc_remove_dentry(const char *name, struct proc_dentry *parent);
+
+int proc_pid(int pid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 53 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_cmdline.c

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+static char *__proc_cmdline = NULL;
+
+int proc_cmdline_save(const char *cmdline)
+{
+    if (__proc_cmdline)
+    {
+        free(__proc_cmdline);
+        __proc_cmdline = NULL;
+    }
+
+    __proc_cmdline = strdup(cmdline);
+
+    return 0;
+}
+
+static int single_show(struct dfs_seq_file *seq, void *data)
+{
+    if (__proc_cmdline)
+    {
+        dfs_seq_puts(seq, __proc_cmdline);
+    }
+
+    return 0;
+}
+
+int proc_cmdline_init(void)
+{
+    struct proc_dentry *dentry = proc_create_single_data("cmdline", 0, NULL, single_show, NULL);
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_cmdline_init);

+ 86 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c

@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+
+    return NULL + (i == 0);
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+
+    *index = i;
+
+    return NULL;
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    /* data: The return value of the start or next*/
+    dfs_seq_puts(seq, "rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)\n--need your own function--\n");
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)
+{
+    return &seq_ops;
+}
+
+static int proc_open(struct dfs_file *file)
+{
+    return dfs_seq_open(file, cpuinfo_get_seq_ops());
+}
+
+static int proc_close(struct dfs_file *file)
+{
+    return dfs_seq_release(file);
+}
+
+static const struct dfs_file_ops file_ops = {
+    .open   = proc_open,
+    .read   = dfs_seq_read,
+    .lseek  = dfs_seq_lseek,
+    .close  = proc_close,
+};
+
+int proc_cpuinfo_init(void)
+{
+    struct proc_dentry *dentry = proc_create_data("cpuinfo", 0, NULL, &file_ops, NULL);
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_cpuinfo_init);

+ 307 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_devices.c

@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+#include <rthw.h>
+#include <rtthread.h>
+#include <string.h>
+
+
+#define LIST_FIND_OBJ_NR 8
+
+struct device_show
+{
+    char *buf;
+    int size;
+    int len;
+    int index;
+};
+
+typedef struct
+{
+    rt_list_t *list;
+    rt_list_t **array;
+    rt_uint8_t type;
+    int nr;             /* input: max nr, can't be 0 */
+    int nr_out;         /* out: got nr */
+} list_get_next_t;
+
+static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
+{
+    struct rt_object_information *info;
+    rt_list_t *list;
+
+    info = rt_object_get_information((enum rt_object_class_type)type);
+    list = &info->object_list;
+
+    p->list = list;
+    p->type = type;
+    p->array = array;
+    p->nr = nr;
+    p->nr_out = 0;
+}
+
+static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
+{
+    int first_flag = 0;
+    rt_base_t level;
+    rt_list_t *node, *list;
+    rt_list_t **array;
+    struct rt_object_information *info;
+    int nr;
+
+    arg->nr_out = 0;
+
+    if (!arg->nr || !arg->type)
+    {
+        return (rt_list_t *)RT_NULL;
+    }
+
+    list = arg->list;
+    info = rt_list_entry(list, struct rt_object_information, object_list);
+
+    if (!current) /* find first */
+    {
+        node = list;
+        first_flag = 1;
+    }
+    else
+    {
+        node = current;
+    }
+
+    level = rt_spin_lock_irqsave(&info->spinlock);
+
+    if (!first_flag)
+    {
+        struct rt_object *obj;
+        /* The node in the list? */
+        obj = rt_list_entry(node, struct rt_object, list);
+        if ((obj->type & ~RT_Object_Class_Static) != arg->type)
+        {
+            rt_spin_unlock_irqrestore(&info->spinlock, level);
+            return (rt_list_t *)RT_NULL;
+        }
+    }
+
+    nr = 0;
+    array = arg->array;
+    while (1)
+    {
+        node = node->next;
+
+        if (node == list)
+        {
+            node = (rt_list_t *)RT_NULL;
+            break;
+        }
+        nr++;
+        *array++ = node;
+        if (nr == arg->nr)
+        {
+            break;
+        }
+    }
+
+    rt_spin_unlock_irqrestore(&info->spinlock, level);
+    arg->nr_out = nr;
+    return node;
+}
+
+static char *const device_type_str[RT_Device_Class_Unknown] =
+{
+    "Character Device",
+    "Block Device",
+    "Network Interface",
+    "MTD Device",
+    "CAN Device",
+    "RTC",
+    "Sound Device",
+    "Graphic Device",
+    "I2C Bus",
+    "USB Slave Device",
+    "USB Host Bus",
+    "USB OTG Bus",
+    "SPI Bus",
+    "SPI Device",
+    "SDIO Bus",
+    "PM Pseudo Device",
+    "Pipe",
+    "Portal Device",
+    "Timer Device",
+    "Miscellaneous Device",
+    "Sensor Device",
+    "Touch Device",
+    "Phy Device",
+    "Security Device",
+    "WLAN Device",
+    "Pin Device",
+    "ADC Device",
+    "DAC Device",
+    "WDT Device",
+    "PWM Device",
+    "Bus Device",
+};
+
+static void save_info(struct device_show *dev, char *dev_name)
+{
+    char tmp[256] = {0};
+    int len;
+
+    dev->index ++;
+
+    rt_snprintf(tmp, 256, "%d %s\n", dev->index, dev_name);
+    tmp[255] = 0;
+
+    len = rt_strlen(tmp);
+    if (dev->size > dev->len + len)
+    {
+        strcat(dev->buf, tmp);
+        dev->len += len;
+    }
+    else
+    {
+        if (dev->buf == RT_NULL)
+        {
+            dev->buf = rt_calloc(1, 4096);
+        }
+        else
+        {
+            dev->buf = rt_realloc(dev->buf, dev->size + 4096);
+        }
+        if (dev->buf)
+        {
+            dev->size += 4096;
+            strcat(dev->buf, tmp);
+            dev->len += len;
+        }
+    }
+}
+
+static void list_device(struct device_show *dev)
+{
+    rt_base_t level;
+    list_get_next_t find_arg;
+    struct rt_object_information *info;
+    rt_list_t *obj_list[LIST_FIND_OBJ_NR];
+    rt_list_t *next = (rt_list_t *)RT_NULL;
+
+    list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
+    info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
+
+    do
+    {
+        next = list_get_next(next, &find_arg);
+        {
+            int i;
+            for (i = 0; i < find_arg.nr_out; i++)
+            {
+                struct rt_object *obj;
+                struct rt_device *device;
+
+                obj = rt_list_entry(obj_list[i], struct rt_object, list);
+                level = rt_spin_lock_irqsave(&info->spinlock);
+                if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
+                {
+                    rt_spin_unlock_irqrestore(&info->spinlock, level);
+                    continue;
+                }
+
+                rt_spin_unlock_irqrestore(&info->spinlock, level);
+
+                device = (struct rt_device *)obj;
+
+                if (device->type < RT_Device_Class_Unknown)
+                {
+                    save_info(dev + device->type, device->parent.name);
+                }
+            }
+        }
+    }
+    while (next != (rt_list_t *)RT_NULL);
+}
+
+static int show_info(struct dfs_seq_file *seq)
+{
+    struct device_show _show[RT_Device_Class_Unknown] = {0};
+
+    list_device(_show);
+
+    for (int i = 0; i < RT_Device_Class_Unknown; i++)
+    {
+        if (_show[i].buf)
+        {
+            dfs_seq_printf(seq, "%s:\n", device_type_str[i]);
+            dfs_seq_write(seq, _show[i].buf, _show[i].len);
+            dfs_seq_putc(seq, '\n');
+
+            rt_free(_show[i].buf);
+        }
+    }
+
+    return 0;
+}
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+
+    return NULL + (i == 0);
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+
+    *index = i;
+
+    return NULL;
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    /* data: The return value of the start or next*/
+    show_info(seq);
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+int proc_devices_init(void)
+{
+    struct proc_dentry *dentry = proc_create_data("devices", 0, NULL, NULL, NULL);
+    if (dentry)
+    {
+        dentry->seq_ops = &seq_ops;
+    }
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_devices_init);

+ 85 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_filesystems.c

@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+#include <dfs_fs.h>
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+    struct dfs_filesystem_type *fs = dfs_filesystems();
+
+    if (fs)
+    {
+        while (i--)
+        {
+            fs = fs->next;
+            if (!fs)
+            {
+                break;
+            }
+        }
+    }
+
+    return fs;
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+    struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data;
+
+    *index = i;
+
+    return fs->next;
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    /* data: The return value of the start or next*/
+    struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data;
+
+    dfs_seq_printf(seq, "%-9s%s\n", (fs->fs_ops->flags == FS_NEED_DEVICE) ? "" : "nodev", fs->fs_ops->name);
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+int proc_filesystems_init(void)
+{
+    struct proc_dentry *dentry = proc_create_data("filesystems", 0, NULL, NULL, NULL);
+    if (dentry)
+    {
+        dentry->seq_ops = &seq_ops;
+    }
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_filesystems_init);

+ 41 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+#include <mm_page.h>
+
+
+extern void rt_memory_info(rt_size_t *total,
+                            rt_size_t *used,
+                            rt_size_t *max_used);
+
+static int single_show(struct dfs_seq_file *seq, void *data)
+{
+    dfs_seq_printf(seq, "0.13 0.16 0.17 1/1035 380436\n");
+
+    return 0;
+}
+
+int proc_loadavg_init(void)
+{
+    struct proc_dentry *dentry = proc_create_single_data("loadavg", 0, NULL, single_show, NULL);
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_loadavg_init);

+ 66 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c

@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+#include <mm_page.h>
+
+
+extern void rt_memory_info(rt_size_t *total,
+                            rt_size_t *used,
+                            rt_size_t *max_used);
+
+static int single_show(struct dfs_seq_file *seq, void *data)
+{
+    rt_size_t total, used, max_used, freed;
+    rt_size_t total_sum = 0;
+    rt_size_t total_freed = 0;
+
+    rt_memory_info(&total, &used, &max_used);
+    total_sum = total_sum + total;
+    total_freed = total_freed + total - used;
+
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "MemMaxUsed:", max_used / 1024);
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "MemAvailable:", (total - used) / 1024);
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "Cached:", 0);
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "SReclaimable:", 0);
+
+    rt_page_get_info(&total, &freed);
+    total_sum = total_sum + total * RT_MM_PAGE_SIZE;
+    total_freed = total_freed + freed * RT_MM_PAGE_SIZE;
+
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "MemTotal:", total_sum / 1024);
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "MemFree:", total_freed / 1024);
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "LowPageTotal:", total * RT_MM_PAGE_SIZE / 1024);
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "lowPageFree:", freed * RT_MM_PAGE_SIZE/ 1024);
+
+    rt_page_high_get_info(&total, &freed);
+
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageTotal:", total * RT_MM_PAGE_SIZE / 1024);
+    dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageFree:", freed * RT_MM_PAGE_SIZE / 1024);
+
+    return 0;
+}
+
+int proc_meminfo_init(void)
+{
+    struct proc_dentry *dentry = proc_create_single_data("meminfo", 0, NULL, single_show, NULL);
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_meminfo_init);

+ 101 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c

@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+#include <dfs_mnt.h>
+
+
+const char *mnt_flag(int flag)
+{
+    /*if (flag & MNT_READONLY)
+    {
+        return "ro";
+    }*/
+
+    return "rw";
+}
+
+static struct dfs_mnt* mnt_show(struct dfs_mnt *mnt, void *parameter)
+{
+    struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
+
+    if (mnt)
+    {
+        if (mnt->dev_id)
+        {
+            dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->dev_id->parent.name, mnt->fullpath,
+                            mnt->fs_ops->name, mnt_flag(mnt->flags));
+        }
+        else
+        {
+            dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->fs_ops->name, mnt->fullpath,
+                            mnt->fs_ops->name, mnt_flag(mnt->flags));
+        }
+    }
+
+    return RT_NULL;
+}
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+
+    return NULL + (i == 0);
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+
+    *index = i;
+
+    return NULL;
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    /* data: The return value of the start or next*/
+    dfs_mnt_foreach(mnt_show, seq);
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+int proc_mounts_init(void)
+{
+    struct proc_dentry *dentry = proc_create_data("mounts", 0, NULL, NULL, NULL);
+    if (dentry)
+    {
+        dentry->seq_ops = &seq_ops;
+    }
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_mounts_init);

+ 107 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_net.c

@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+#ifdef RT_USING_LWIP
+#include "lwip/opt.h"
+#endif
+
+#if LWIP_ROUTE
+extern int inet_route_foreach(void (*func)(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter), void *parameter);
+#endif
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+
+    return NULL + (i == 0);
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+
+    *index = i;
+
+    return NULL;
+}
+
+static void route_show(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter)
+{
+    struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
+    /* "Iface\tDestination\tGateway "
+        "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
+        "\tWindow\tIRTT"); */
+    /* "%63s%lx%lx%X%d%d%d%lx%d%d%d\n" */
+    dfs_seq_printf(seq, "%s ", name);
+    dfs_seq_printf(seq, "%lx ", ip_addr);
+    dfs_seq_printf(seq, "%lx ", 0);
+    dfs_seq_printf(seq, "%X ", 1);
+    dfs_seq_printf(seq, "%d ", 0);
+    dfs_seq_printf(seq, "%d ", 0);
+    dfs_seq_printf(seq, "%d ", 0);
+    dfs_seq_printf(seq, "%lx ", netmask);
+    dfs_seq_printf(seq, "%d ", 0);
+    dfs_seq_printf(seq, "%d ", 0);
+    dfs_seq_printf(seq, "%d\n", 0);
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    /* data: The return value of the start or next*/
+    dfs_seq_printf(seq, "\n");
+#if LWIP_ROUTE
+    inet_route_foreach(route_show, seq);
+#endif
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+int proc_net_init(void)
+{
+    struct proc_dentry *dentry;
+
+    dentry = proc_mkdir("net", NULL);
+    if (!dentry)
+        return -1;
+
+    proc_release(dentry);
+
+    dentry = proc_create_data("net/route", 0, NULL, NULL, NULL);
+    if (dentry)
+    {
+        dentry->seq_ops = &seq_ops;
+    }
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_net_init);

+ 215 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_partitions.c

@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+#include <rthw.h>
+#include <rtthread.h>
+#include <string.h>
+
+
+#define LIST_FIND_OBJ_NR 8
+
+typedef struct
+{
+    rt_list_t *list;
+    rt_list_t **array;
+    rt_uint8_t type;
+    int nr;             /* input: max nr, can't be 0 */
+    int nr_out;         /* out: got nr */
+} list_get_next_t;
+
+static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
+{
+    struct rt_object_information *info;
+    rt_list_t *list;
+
+    info = rt_object_get_information((enum rt_object_class_type)type);
+    list = &info->object_list;
+
+    p->list = list;
+    p->type = type;
+    p->array = array;
+    p->nr = nr;
+    p->nr_out = 0;
+}
+
+static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
+{
+    int first_flag = 0;
+    rt_base_t level;
+    rt_list_t *node, *list;
+    rt_list_t **array;
+    struct rt_object_information *info;
+    int nr;
+
+    arg->nr_out = 0;
+
+    if (!arg->nr || !arg->type)
+    {
+        return (rt_list_t *)RT_NULL;
+    }
+
+    list = arg->list;
+    info = rt_list_entry(list, struct rt_object_information, object_list);
+
+    if (!current) /* find first */
+    {
+        node = list;
+        first_flag = 1;
+    }
+    else
+    {
+        node = current;
+    }
+
+    level = rt_spin_lock_irqsave(&info->spinlock);
+
+    if (!first_flag)
+    {
+        struct rt_object *obj;
+        /* The node in the list? */
+        obj = rt_list_entry(node, struct rt_object, list);
+        if ((obj->type & ~RT_Object_Class_Static) != arg->type)
+        {
+            rt_spin_unlock_irqrestore(&info->spinlock, level);
+            return (rt_list_t *)RT_NULL;
+        }
+    }
+
+    nr = 0;
+    array = arg->array;
+    while (1)
+    {
+        node = node->next;
+
+        if (node == list)
+        {
+            node = (rt_list_t *)RT_NULL;
+            break;
+        }
+        nr++;
+        *array++ = node;
+        if (nr == arg->nr)
+        {
+            break;
+        }
+    }
+
+    rt_spin_unlock_irqrestore(&info->spinlock, level);
+    arg->nr_out = nr;
+    return node;
+}
+
+static int show_info(struct dfs_seq_file *seq)
+{
+    rt_base_t level;
+    list_get_next_t find_arg;
+    struct rt_object_information *info;
+    rt_list_t *obj_list[LIST_FIND_OBJ_NR];
+    rt_list_t *next = (rt_list_t *)RT_NULL;
+
+    list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
+    info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
+
+    do
+    {
+        next = list_get_next(next, &find_arg);
+        {
+            int i;
+            for (i = 0; i < find_arg.nr_out; i++)
+            {
+                struct rt_object *obj;
+                struct rt_device *device;
+
+                obj = rt_list_entry(obj_list[i], struct rt_object, list);
+                level = rt_spin_lock_irqsave(&info->spinlock);
+                if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
+                {
+                    rt_spin_unlock_irqrestore(&info->spinlock, level);
+                    continue;
+                }
+
+                rt_spin_unlock_irqrestore(&info->spinlock, level);
+
+                device = (struct rt_device *)obj;
+
+                if (device->type == RT_Device_Class_Block)
+                {
+                    struct rt_device_blk_geometry geometry = { 0 };
+
+                    rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
+
+                    dfs_seq_printf(seq, "%4d  %7d %14llu   %s\n", 0, 0,
+                        geometry.sector_count, device->parent.name);
+                }
+            }
+        }
+    } while (next != (rt_list_t *)RT_NULL);
+
+    return 0;
+}
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+
+    return NULL + (i == 0);
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+
+    *index = i;
+
+    return NULL;
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    dfs_seq_puts(seq, "major    minor        #blocks  name\n\n");
+    /* data: The return value of the start or next*/
+    show_info(seq);
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+int proc_partitions_init(void)
+{
+    struct proc_dentry *dentry = proc_create_data("partitions", 0, NULL, NULL, NULL);
+    if (dentry)
+    {
+        dentry->seq_ops = &seq_ops;
+    }
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_partitions_init);

+ 449 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_pid.c

@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+#define __RT_IPC_SOURCE__
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include "lwp_internal.h"
+#include <dfs_dentry.h>
+#include "lwp_internal.h"
+
+#if defined(RT_USING_SMART)
+
+#include "lwp.h"
+#include "lwp_pid.h"
+#include <lwp_user_mm.h>
+
+struct pid_dentry
+{
+    const char *name;
+    mode_t mode;
+    const struct dfs_file_ops *fops;
+    const struct proc_ops *ops;
+    const struct dfs_seq_ops *seq_ops;
+    int (*single_show)(struct dfs_seq_file *seq, void *data);
+    void *data;
+};
+
+static char stat_transform(int __stat)
+{
+    switch (__stat)
+    {
+    case RT_THREAD_RUNNING:
+        return 'R';
+    default:
+        return 'T';
+    }
+}
+
+static int stat_single_show(struct dfs_seq_file *seq, void *data)
+{
+    struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
+    rt_list_t *list;
+    int mask = 0;
+    rt_thread_t thread;
+    rt_uint64_t user_time_lwp = 0;
+    rt_uint64_t system_time_lwp = 0;
+    int lwp_oncpu = RT_CPUS_NR;
+    int lwp_oncpu_ok = 0;
+    struct rt_lwp *lwp = RT_NULL;
+    char** argv = RT_NULL;
+    char *filename = RT_NULL;
+    char *dot = RT_NULL;
+
+    lwp_pid_lock_take();
+
+    lwp = lwp_from_pid_locked(dentry->pid);
+    argv = lwp_get_command_line_args(lwp);
+
+    if (lwp)
+    {
+        dfs_seq_printf(seq,"%d ",dentry->pid);
+        if (argv)
+        {
+            filename = strrchr(argv[0], '/');
+            dot = strchr(argv[0], '.');
+
+            if (filename != NULL)
+            {
+                filename++;
+            }
+            else
+            {
+                filename = argv[0];
+            }
+
+            if (dot != NULL)
+            {
+                *dot = '\0';
+            }
+
+            if (filename != NULL)
+            {
+                dfs_seq_printf(seq,"(%s) ", filename);
+            }
+            else
+            {
+                dfs_seq_printf(seq,"(%s) ", argv[0]);
+            }
+
+            lwp_free_command_line_args(argv);
+        }
+        else
+        {
+            dfs_seq_printf(seq,"(%s) ", "");
+        }
+
+        if (lwp->terminated)
+        {
+            dfs_seq_printf(seq,"%c ",'Z');
+        }
+        else
+        {
+            list = lwp->t_grp.next;
+            while (list != &lwp->t_grp)
+            {
+                thread = rt_list_entry(list, struct rt_thread, sibling);
+                user_time_lwp = user_time_lwp + thread->user_time;
+                system_time_lwp = system_time_lwp + thread->system_time;
+
+                #if RT_CPUS_NR > 1
+                    #define ONCPU(thread) RT_SCHED_CTX(thread).oncpu
+                #else
+                    #define ONCPU(thread) 0
+                #endif
+                if (lwp_oncpu_ok == 0)
+                {
+                    lwp_oncpu = ONCPU(thread);
+                    lwp_oncpu_ok = 1;
+                }
+                if (stat_transform(RT_SCHED_CTX(thread).stat) == 'R')
+                {
+                    lwp_oncpu = ONCPU(thread);
+                    mask = 1;
+                }
+                list = list->next;
+            }
+
+            if (mask == 1)
+            {
+                dfs_seq_printf(seq,"%c ",'R');
+            }
+            else
+            {
+                dfs_seq_printf(seq,"%c ",'S');
+            }
+        }
+        lwp_pid_lock_release();
+
+        if (lwp->parent != NULL)
+            dfs_seq_printf(seq,"%d ",lwp->parent->pid);
+        else
+            dfs_seq_printf(seq,"0 ");
+
+        dfs_seq_printf(seq, "1 1 0 -1 4194560 48245 133976064 732 425574 ");
+        dfs_seq_printf(seq,"%llu ",user_time_lwp);//utime
+        dfs_seq_printf(seq,"%llu ",system_time_lwp);//stime
+        dfs_seq_printf(seq, "1204291 518742 20 0 1 0 50 ");
+        dfs_seq_printf(seq, "%d ",rt_aspace_count_vsz(lwp->aspace));//VSZ
+        dfs_seq_printf(seq, "1422 18446744073709551615 ");
+        dfs_seq_printf(seq, "1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 ");
+        dfs_seq_printf(seq, "%d ", lwp_oncpu);//CPU
+        dfs_seq_printf(seq, "0 0 0 0 0 0 0 0 0 0 0 0 0");
+        dfs_seq_printf(seq,"\n");
+    }
+    else
+    {
+        lwp_pid_lock_release();
+    }
+
+    return 0;
+}
+
+static int cmdline_single_show(struct dfs_seq_file *seq, void *data)
+{
+    struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
+    struct rt_lwp *lwp;
+    char** argv;
+
+    lwp_pid_lock_take();
+    lwp = lwp_from_pid_locked(dentry->pid);
+    argv = lwp_get_command_line_args(lwp);
+    lwp_pid_lock_release();
+
+    if (argv)
+    {
+        for (int i = 0; argv[i] != NULL; i++)
+        {
+            dfs_seq_printf(seq, "%s ", argv[i]);
+        }
+        dfs_seq_puts(seq, "\n");
+
+        lwp_free_command_line_args(argv);
+    }
+    else
+    {
+        dfs_seq_puts(seq, "error\n");
+    }
+
+    return 0;
+}
+
+struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *name)
+{
+    struct proc_dentry *dentry = RT_NULL;
+    char num[DIRENT_NAME_MAX];
+    struct rt_lwp *lwp;
+    struct dfs_fdtable *table;
+
+    lwp_pid_lock_take();
+    lwp = lwp_from_pid_locked(parent->pid);
+    table = lwp ? &lwp->fdt : RT_NULL;
+    lwp_pid_lock_release();
+
+    if (!table)
+    {
+        return RT_NULL;
+    }
+
+    dfs_file_lock();
+    for (int i = 0; i < table->maxfd; i++)
+    {
+        struct dfs_file *file = table->fds[i];
+        if (file)
+        {
+            rt_snprintf(num, DIRENT_NAME_MAX, "%d", i);
+            if (rt_strcmp(num, name) == 0)
+            {
+                dentry = rt_calloc(1, sizeof(struct proc_dentry));
+                if (dentry)
+                {
+                    dentry->mode = (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH));
+                    dentry->ref_count = 1;
+                    dentry->name = rt_strdup(name);
+                    dentry->data = (void *)dfs_dentry_full_path(file->dentry);
+
+                    if (dentry->data == RT_NULL)
+                    {
+                        //todo add vnode->data
+                        if (file->vnode->type == FT_SOCKET)
+                            dentry->data = (void *)rt_strdup("socket");
+                        else if (file->vnode->type == FT_USER)
+                            dentry->data = (void *)rt_strdup("user");
+                        else if (file->vnode->type == FT_DEVICE)
+                            dentry->data = (void *)rt_strdup("device");
+                        else
+                            dentry->data = (void *)rt_strdup("unknown");
+                    }
+
+                    dentry->pid = parent->pid;
+                    break;
+                }
+            }
+        }
+    }
+    dfs_file_unlock();
+
+    return dentry;
+}
+
+int proc_pid_fd_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
+{
+    int ret = 0, index = 0;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+    struct rt_lwp *lwp;
+    struct dfs_fdtable *table;
+
+    lwp_pid_lock_take();
+    lwp = lwp_from_pid_locked(entry->pid);
+    LWP_LOCK(lwp);
+    table = lwp ? &lwp->fdt : RT_NULL;
+
+    if (!table->fds)
+    {
+        LWP_UNLOCK(lwp);
+        lwp_pid_lock_release();
+        return 0;
+    }
+
+    count = (count / sizeof(struct dirent));
+    if (count == 0)
+    {
+        LWP_UNLOCK(lwp);
+        lwp_pid_lock_release();
+        return -EINVAL;
+    }
+
+    dfs_file_lock();
+    for (int i = 0; i < table->maxfd; i++)
+    {
+        struct dfs_file *df = table->fds[i];
+        if (df)
+        {
+            if (index >= file->fpos)
+            {
+                struct dirent *d = dirp + index - file->fpos;
+
+                d->d_type = DT_SYMLINK;
+                d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
+                rt_snprintf(d->d_name, DIRENT_NAME_MAX, "%d", i);
+                d->d_namlen = rt_strlen(d->d_name);
+
+                ret++;
+            }
+
+            index++;
+            if (index - file->fpos >= count)
+            {
+                break;
+            }
+        }
+    }
+    dfs_file_unlock();
+    LWP_UNLOCK(lwp);
+    lwp_pid_lock_release();
+
+    if (ret > 0)
+    {
+        file->fpos = index;
+        ret = ret * sizeof(struct dirent);
+    }
+
+    return ret;
+}
+
+static const struct proc_ops proc_pid_fd_ops = {
+    .lookup = proc_pid_fd_lookup,
+};
+
+static const struct dfs_file_ops proc_pid_fd_fops = {
+    .getdents = proc_pid_fd_getdents,
+};
+
+int proc_pid_exe_readlink(struct proc_dentry *dentry, char *buf, int len)
+{
+    struct rt_lwp *lwp;
+
+    lwp = lwp_self();
+    len = rt_snprintf(buf, len, "%s", lwp ? lwp->exe_file : "null");
+
+    return len;
+}
+
+static const struct proc_ops proc_pid_exe_ops = {
+    .readlink = proc_pid_exe_readlink,
+};
+
+int proc_pid_cwd_readlink(struct proc_dentry *dentry, char *buf, int len)
+{
+    struct rt_lwp *lwp;
+
+    lwp = lwp_self();
+    len = rt_snprintf(buf, len, "%s", lwp ? lwp->working_directory : "null");
+
+    return len;
+}
+
+static const struct proc_ops proc_pid_cwd_ops = {
+    .readlink = proc_pid_cwd_readlink,
+};
+
+static struct pid_dentry pid_dentry_base[] = {
+    {"cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0},
+    {"cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0},
+    {"exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0},
+    {"fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0},
+    {"mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts"},
+    {"stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0},
+};
+
+int proc_pid(int pid)
+{
+    char pid_str[64] = {0};
+    struct proc_dentry *dentry;
+
+    rt_snprintf(pid_str, 64, "%d", pid);
+    pid_str[63] = 0;
+
+    dentry = proc_mkdir(pid_str, 0);
+    if (dentry)
+    {
+        struct proc_dentry *ent;
+
+        dentry->pid = pid;
+        for (int j = 0; j < sizeof(pid_dentry_base) / sizeof(struct pid_dentry); j++)
+        {
+            if (S_ISDIR(pid_dentry_base[j].mode))
+            {
+                ent = proc_mkdir_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
+                                      pid_dentry_base[j].fops, pid_dentry_base[j].data);
+            }
+            else if (S_ISLNK(pid_dentry_base[j].mode))
+            {
+                if (pid_dentry_base[j].data == RT_NULL)
+                {
+                    pid_dentry_base[j].data = "NULL";
+                }
+
+                ent = proc_symlink(pid_dentry_base[j].name, dentry, pid_dentry_base[j].data);
+            }
+            else
+            {
+                ent = proc_create_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
+                                       pid_dentry_base[j].fops, pid_dentry_base[j].data);
+            }
+
+            if (ent)
+            {
+                if (pid_dentry_base[j].ops)
+                {
+                    ent->ops = pid_dentry_base[j].ops;
+                }
+
+                if (pid_dentry_base[j].seq_ops)
+                {
+                    ent->seq_ops = pid_dentry_base[j].seq_ops;
+                }
+
+                if (pid_dentry_base[j].single_show)
+                {
+                    ent->single_show = pid_dentry_base[j].single_show;
+                }
+
+                proc_release(ent);
+            }
+        }
+        proc_release(dentry);
+    }
+
+    return 0;
+}
+
+int msh_proc_pid(int argc, char **argv)
+{
+    if (argc > 1)
+    {
+        for (int i = 1; i <= argc - 1; i++)
+        {
+            proc_pid(atoi(argv[i]));
+        }
+    }
+
+    return 0;
+}
+MSH_CMD_EXPORT_ALIAS(msh_proc_pid, proc_pid, proc pid);
+
+#endif

+ 66 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_self.c

@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+#if defined(RT_USING_SMART)
+
+#include <lwp.h>
+
+
+int proc_self_readlink(struct proc_dentry *dentry, char *buf, int len)
+{
+    struct rt_lwp *lwp  = RT_NULL;
+
+    lwp = lwp_self();
+    if (lwp)
+    {
+        rt_snprintf(buf, len, "%d", lwp_to_pid(lwp));
+        buf[len - 1] = 0;
+        return rt_strlen(buf);
+    }
+    else
+    {
+        rt_snprintf(buf, len, "null");
+        buf[len - 1] = 0;
+        return rt_strlen(buf);
+    }
+
+    return -1;
+}
+
+static const struct proc_ops proc_pid_fd_ops = {
+    .readlink = proc_self_readlink,
+};
+
+int proc_self_init(void)
+{
+    struct proc_dentry *ent;
+
+    ent = proc_symlink("self", NULL, "NULL");
+    if (ent)
+    {
+        ent->ops = &proc_pid_fd_ops;
+    }
+    proc_release(ent);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_self_init);
+
+#endif

+ 114 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_stat.c

@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+
+    return NULL + (i == 0);
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+
+    *index = i;
+
+    return NULL;
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    int i;
+    rt_cpu_t pcpu;
+    rt_uint64_t user_total = 0;
+    rt_uint64_t system_total = 0;
+    rt_uint64_t idle_total = 0;
+
+    for (i = 0; i < RT_CPUS_NR; i++)
+    {
+        pcpu   = rt_cpu_index(i);
+        user_total = user_total + pcpu->cpu_stat.user;
+        system_total = system_total + pcpu->cpu_stat.system;
+        idle_total = idle_total + pcpu->cpu_stat.idle;
+    }
+    dfs_seq_printf(seq, "cpu  %llu 0 %llu %llu 0 0 0 0 0 0\n", user_total, system_total, idle_total);
+
+    for (i = 0; i < RT_CPUS_NR; i++)
+    {
+        pcpu   = rt_cpu_index(i);
+        dfs_seq_printf(seq, "cpu%d ",i);
+        dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.user);//user
+        dfs_seq_printf(seq, "0 ");//nice
+        dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.system);//system
+        dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.idle);//idle
+        dfs_seq_printf(seq, "0 ");//iowait
+        dfs_seq_printf(seq, "0 ");//irq
+        dfs_seq_printf(seq, "0 ");//softirq
+        dfs_seq_printf(seq, "0 0 0\n");//steal,guest,guest_nice
+
+    }
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+rt_weak const struct dfs_seq_ops *stat_get_seq_ops(void)
+{
+    return &seq_ops;
+}
+
+static int proc_open(struct dfs_file *file)
+{
+    return dfs_seq_open(file, stat_get_seq_ops());
+}
+
+static int proc_close(struct dfs_file *file)
+{
+    return dfs_seq_release(file);
+}
+
+static const struct dfs_file_ops file_ops = {
+    .open   = proc_open,
+    .read   = dfs_seq_read,
+    .lseek  = dfs_seq_lseek,
+    .close  = proc_close,
+};
+
+int proc_stat_init(void)
+{
+    struct proc_dentry *dentry = proc_create_data("stat", 0, NULL, &file_ops, NULL);
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_stat_init);

+ 100 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_tty.c

@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+
+static void *seq_start(struct dfs_seq_file *seq, off_t *index)
+{
+    off_t i = *index; // seq->index
+
+    return NULL + (i == 0);
+}
+
+static void seq_stop(struct dfs_seq_file *seq, void *data)
+{
+}
+
+static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
+{
+    /* data: The return value of the start or next*/
+    off_t i = *index + 1; // seq->index
+
+    *index = i;
+
+    return NULL;
+}
+
+static int seq_show(struct dfs_seq_file *seq, void *data)
+{
+    /* data: The return value of the start or next*/
+    dfs_seq_puts(seq, "todo\n");
+
+    return 0;
+}
+
+static const struct dfs_seq_ops seq_ops = {
+    .start  = seq_start,
+    .stop   = seq_stop,
+    .next   = seq_next,
+    .show   = seq_show,
+};
+
+void proc_tty_register_driver(void *driver)
+{
+    //todo
+}
+
+void proc_tty_unregister_driver(void *driver)
+{
+    //todo
+}
+
+int proc_tty_init(void)
+{
+    struct proc_dentry *dentry;
+
+    dentry = proc_mkdir("tty", NULL);
+    if (!dentry)
+        return -1;
+
+    proc_release(dentry);
+
+    dentry = proc_mkdir("tty/ldisc", NULL);
+    proc_release(dentry);
+
+    dentry = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
+    proc_release(dentry);
+
+    dentry = proc_create_data("tty/ldiscs", 0, NULL, NULL, NULL);
+    if (dentry)
+    {
+        dentry->seq_ops = &seq_ops;
+    }
+    proc_release(dentry);
+
+    dentry = proc_create_data("tty/drivers", 0, NULL, NULL, NULL);
+    if (dentry)
+    {
+        dentry->seq_ops = &seq_ops;
+    }
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_tty_init);

+ 38 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+
+static int single_show(struct dfs_seq_file *seq, void *data)
+{
+    dfs_seq_printf(seq, "%lu.%02lu %lu.%02lu\n",
+                   (unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100,
+                   (unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100);
+
+    return 0;
+}
+
+int proc_uptime_init(void)
+{
+    struct proc_dentry *dentry = proc_create_single_data("uptime", 0, NULL, single_show, NULL);
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_uptime_init);

+ 45 - 0
components/dfs/dfs_v2/filesystems/procfs/proc_version.c

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "proc.h"
+#include "procfs.h"
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs_dentry.h>
+
+
+static int single_show(struct dfs_seq_file *seq, void *data)
+{
+    dfs_seq_puts(seq, "\n \\ | /\n");
+#ifdef RT_USING_SMART
+    dfs_seq_puts(seq, "- RT -     Thread Smart Operating System\n");
+#else
+    dfs_seq_puts(seq, "- RT -     Thread Operating System\n");
+#endif
+    dfs_seq_printf(seq, " / | \\     %d.%d.%d build %s %s\n",
+                    (rt_int32_t)RT_VERSION_MAJOR, (rt_int32_t)RT_VERSION_MINOR, (rt_int32_t)RT_VERSION_PATCH,
+                    __DATE__, __TIME__);
+    dfs_seq_puts(seq, " 2006 - 2022 Copyright by RT-Thread team\n");
+
+    return 0;
+}
+
+int proc_version_init(void)
+{
+    struct proc_dentry *dentry = proc_create_single_data("version", 0, NULL, single_show, NULL);
+    proc_release(dentry);
+
+    return 0;
+}
+INIT_ENV_EXPORT(proc_version_init);

+ 447 - 0
components/dfs/dfs_v2/filesystems/procfs/procfs.c

@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dfs.h>
+#include <dfs_fs.h>
+#include <dfs_file.h>
+#include <dfs_posix.h>
+#include <dfs_mnt.h>
+#include <dfs_dentry.h>
+
+#include "proc.h"
+#include "procfs.h"
+
+#define PROC_DEBUG(...) //rt_kprintf
+
+static int dfs_procfs_open(struct dfs_file *file)
+{
+    rt_err_t ret = RT_EOK;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+
+    RT_ASSERT(file->ref_count > 0);
+
+    // this file is opened and in an fdtable
+    if (file->ref_count > 1)
+    {
+        file->fpos = 0;
+        return ret;
+    }
+
+    if (entry->fops && entry->fops->open)
+    {
+        ret = entry->fops->open(file);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_close(struct dfs_file *file)
+{
+    rt_err_t ret = RT_EOK;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    RT_ASSERT(file->vnode->ref_count > 0);
+    if (file->vnode->ref_count > 1)
+    {
+        return ret;
+    }
+
+    if (entry && entry->fops && entry->fops->close)
+    {
+        ret = entry->fops->close(file);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static ssize_t dfs_procfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
+{
+    ssize_t ret = -RT_ERROR;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (entry && entry->fops && entry->fops->read)
+    {
+        ret = entry->fops->read(file, buf, count, pos);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static ssize_t dfs_procfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
+{
+    ssize_t ret = -RT_ERROR;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (entry && entry->fops && entry->fops->write)
+    {
+        ret = entry->fops->write(file, buf, count, pos);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_ioctl(struct dfs_file *file, int cmd, void *args)
+{
+    int ret = -RT_ERROR;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (entry && entry->fops && entry->fops->ioctl)
+    {
+        ret = entry->fops->ioctl(file, cmd, args);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
+{
+    int ret = 0;
+    rt_uint32_t index = 0;
+    struct dirent *d;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (entry)
+    {
+        struct proc_dentry *iter = RT_NULL, *tmp;
+
+        /* make integer count */
+        count = (count / sizeof(struct dirent));
+        if (count == 0)
+        {
+            return -EINVAL;
+        }
+
+        dfs_vfs_for_each_subnode(iter, tmp, entry, node)
+        {
+            if (iter == RT_NULL)
+            {
+                break;
+            }
+
+            if (index >= file->fpos)
+            {
+                d = dirp + index - file->fpos;
+
+                if (S_ISDIR(entry->mode))
+                {
+                    d->d_type = DT_DIR;
+                }
+                else if (S_ISLNK(entry->mode))
+                {
+                    d->d_type = DT_SYMLINK;
+                }
+                else
+                {
+                    d->d_type = DT_REG;
+                }
+
+                d->d_namlen = rt_strlen(iter->name);
+                d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
+                rt_strncpy(d->d_name, iter->name, rt_strlen(iter->name) + 1);
+
+                ret ++;
+            }
+
+            index++;
+            if (index - file->fpos >= count)
+            {
+                break;
+            }
+        }
+
+        if (ret > 0)
+        {
+            file->fpos = index;
+        }
+
+        if (entry->fops && entry->fops->getdents && ret < count)
+        {
+            int r;
+
+            file->fpos -= index;
+
+            r = entry->fops->getdents(file, dirp + ret, (count - ret) * sizeof(struct dirent));
+
+            ret = ret * sizeof(struct dirent);
+
+            if (r > 0)
+            {
+                ret += r;
+            }
+
+            file->fpos += index;
+        }
+        else
+        {
+            ret = ret * sizeof(struct dirent);
+        }
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_poll(struct dfs_file *file, struct rt_pollreq *req)
+{
+    int ret = -RT_ERROR;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (entry && entry->fops && entry->fops->poll)
+    {
+        ret = entry->fops->poll(file, req);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_flush(struct dfs_file *file)
+{
+    int ret = -RT_ERROR;
+    struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
+
+    if (entry && entry->fops && entry->fops->flush)
+    {
+        ret = entry->fops->flush(file);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
+{
+    RT_ASSERT(mnt != RT_NULL);
+
+    return RT_EOK;
+}
+
+static int dfs_procfs_umount(struct dfs_mnt *mnt)
+{
+    RT_ASSERT(mnt != RT_NULL);
+
+    return RT_EOK;
+}
+
+static int dfs_procfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
+{
+    int ret = 0;
+    struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
+
+    if (entry)
+    {
+        if (S_ISLNK(entry->mode) && entry->data)
+        {
+            if (entry->ops && entry->ops->readlink)
+            {
+                ret = entry->ops->readlink(entry, buf, len);
+            }
+            else
+            {
+                rt_strncpy(buf, (const char *)entry->data, len);
+                buf[len - 1] = '\0';
+                ret = rt_strlen(buf);
+            }
+        }
+
+        proc_release(entry);
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_unlink(struct dfs_dentry *dentry)
+{
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, -1);
+    return -RT_ERROR;
+}
+
+static int dfs_procfs_stat(struct dfs_dentry *dentry, struct stat *st)
+{
+    int ret = RT_EOK;
+    struct dfs_vnode *vnode;
+
+    if (dentry && dentry->vnode)
+    {
+        vnode = dentry->vnode;
+
+        st->st_dev = (dev_t)(dentry->mnt->dev_id);
+        st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
+
+        st->st_gid = vnode->gid;
+        st->st_uid = vnode->uid;
+        st->st_mode = vnode->mode;
+        st->st_nlink = vnode->nlink;
+        st->st_size = vnode->size;
+        st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
+        st->st_mtim.tv_sec = vnode->mtime.tv_sec;
+        st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
+        st->st_ctim.tv_sec = vnode->ctime.tv_sec;
+        st->st_atim.tv_nsec = vnode->atime.tv_nsec;
+        st->st_atim.tv_sec = vnode->atime.tv_sec;
+    }
+
+    PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
+
+    return ret;
+}
+
+static int dfs_procfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
+{
+    if (mnt && buf)
+    {
+        buf->f_bsize = 512;
+        buf->f_blocks = 2048 * 64; // 64M
+        buf->f_bfree = buf->f_blocks;
+        buf->f_bavail = buf->f_bfree;
+    }
+
+    PROC_DEBUG(" %s %d\n", __func__, __LINE__);
+
+    return RT_EOK;
+}
+
+static struct dfs_vnode *dfs_procfs_lookup(struct dfs_dentry *dentry)
+{
+    struct dfs_vnode *vnode = RT_NULL;
+    struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
+
+    if (entry)
+    {
+        vnode = dfs_vnode_create();
+        if (vnode)
+        {
+            vnode->nlink = 1;
+            vnode->size = 0;
+            if (S_ISDIR(entry->mode))
+            {
+                vnode->mode = entry->mode;
+                vnode->type = FT_DIRECTORY;
+            }
+            else if (S_ISLNK(entry->mode))
+            {
+                vnode->mode = entry->mode;
+                vnode->type = FT_SYMLINK;
+            }
+            else
+            {
+                vnode->mode = entry->mode;
+                vnode->type = FT_REGULAR;
+            }
+
+            vnode->data = entry;
+            vnode->mnt = dentry->mnt;
+        }
+
+        proc_release(entry);
+    }
+
+    PROC_DEBUG(" %s %d >> %s\n", __func__, __LINE__, dentry->pathname);
+
+    return vnode;
+}
+
+static struct dfs_vnode *dfs_procfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
+{
+    return RT_NULL;
+}
+
+static int dfs_procfs_free_vnode(struct dfs_vnode *vnode)
+{
+    return 0;
+}
+
+static const struct dfs_file_ops _procfs_fops =
+{
+    .open = dfs_procfs_open,
+    .close = dfs_procfs_close,
+    .lseek = generic_dfs_lseek,
+    .read = dfs_procfs_read,
+    .write = dfs_procfs_write,
+    .ioctl = dfs_procfs_ioctl,
+    .getdents = dfs_procfs_getdents,
+    .poll = dfs_procfs_poll,
+    .flush = dfs_procfs_flush,
+};
+
+static const struct dfs_filesystem_ops _procfs_ops =
+{
+    .name = "procfs",
+
+    .default_fops = &_procfs_fops,
+
+    .mount = dfs_procfs_mount,
+    .umount = dfs_procfs_umount,
+    .readlink   = dfs_procfs_readlink,
+    .unlink = dfs_procfs_unlink,
+    .stat = dfs_procfs_stat,
+    .statfs = dfs_procfs_statfs,
+    .lookup = dfs_procfs_lookup,
+    .create_vnode = dfs_procfs_create_vnode,
+    .free_vnode = dfs_procfs_free_vnode,
+};
+
+static struct dfs_filesystem_type _procfs =
+{
+    .fs_ops = &_procfs_ops,
+};
+
+int dfs_procfs_init(void)
+{
+    /* register procfs file system */
+    dfs_register(&_procfs);
+
+    return 0;
+}
+INIT_COMPONENT_EXPORT(dfs_procfs_init);
+
+int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos)
+{
+    if (file->fpos >= file->vnode->size)
+    {
+        return 0;
+    }
+
+    if (file->data)
+    {
+        count = file->vnode->size - file->fpos >= count ? count : file->vnode->size - file->fpos;
+        rt_strncpy(buf, file->data + file->fpos, count);
+
+        file->fpos += count;
+        *pos = file->fpos;
+    }
+    else
+    {
+        return 0;
+    }
+
+    return count;
+}

+ 19 - 0
components/dfs/dfs_v2/filesystems/procfs/procfs.h

@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#ifndef __PROC_FS_H__
+#define __PROC_FS_H__
+
+#include <dfs_file.h>
+
+int dfs_procfs_init(void);
+
+int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos);
+
+#endif