LiteOS的VFS和ramfs

与世无争的帅哥 提交于 2020-02-07 02:53:14

(简单做个笔记)

VFS和ramfs

LiteOS提供了VFS和各类文件系统
(摘自百度百科)VFS(virtual File System)的作用就是采用标准的Unix系统调用读写位于不同物理介质上的不同文件系统,即为各类文件系统提供了一个统一的操作界面和应用编程接口。
ramfs是建立在内存中的一个非常简单的文件系统,通过它可以了解LiteOS的文件系统机制

ramfs_init


使用文件系统前,通过ramfs_init()注册ramfs
los_vfs_init初始化VFS,作用是注册一个文件系统的互斥量
los_fs_register(&ramfs_fs)注册ramfs
ramfs_fs是一个file_system结构体变量,file_system定义如下

struct file_system
{
    const char            fs_name [LOS_FS_MAX_NAME_LEN];
    struct file_ops     * fs_fops;
    struct file_system  * fs_next;
    volatile uint32_t     fs_refs;
};

这是一个链表
file_ops结构体的部分定义如下

struct file_ops
{
    int     (*open)     (struct file *, const char *, int);
    int     (*close)    (struct file *);
    ...
    ...
};

定义了各个系统调用的函数指针
ramfs初始化ramfs_fs如下

static struct file_system ramfs_fs =
{
    "ramfs",
    &ramfs_ops,
    NULL,
    0
};

其中ramfs_ops中的各个函数指针指向以ramfs开头的每个具体实现函数
在los_fs_register中,首先进行一些常规的检查,然后将ramfs_fs挂在链表file_systems里面
接下来在ramfs_init()中调用了ramfs_mount("/ramfs/", 16 * 1024)挂载文件系统,后一个参数的意思是在内存分配16KB作为“硬盘”

ramfs_mount


在这个函数中,首先初始化一个挂载点结构体ramfs_mount_point的变量,ramfs_mount_point定义如下

struct ramfs_mount_point
{
    struct ramfs_element       root;
    void                      *memory;
};

root是文件树树根,memory是分配的16KB在内存中的具体位置,其中ramfs_element的定义如下

struct ramfs_element
{
    char                           name [LOS_MAX_FILE_NAME_LEN];
    uint32_t                       type;
    struct ramfs_element          *sabling;
    struct ramfs_element          *parent;
    volatile uint32_t              refs;
    union
    {
        struct
        {
            size_t                 size;
            char                  *content;
        } f;
        struct
        {
            struct ramfs_element *child;
        } d;
    };
};

用于记录每个文件的信息
回到ramfs_mount,初始化时赋值root的文件名为“/ramfs/”,memory分配16KB
调用LOS_MemInit初始化分配的内存为动态内存池,便于管理
最后调用los_fs_mount (const char *fsname, const char *path, void *data)将ramfs挂载到mount_point结构体链表mount_points中,mount_point结构体定义如下

struct mount_point
{
    struct file_system  * m_fs;
    struct mount_point  * m_next;
    const char          * m_path;
    volatile uint32_t     m_refs;
    UINT32                m_mutex;
    void                * m_data;   /* used by fs private data for this mount point (like /sdb1, /sdb2), */
};

los_fs_mount返回,los_ramfs_init结束,此时可以通过目录"/ramfs/"访问ramfs中的文件

系统调用的执行过程


以下面的代码为例

VOID ramfs_demo(VOID){
	//首先挂载ramfs到"/ramfs/"
	if(ramfs_init() == LOS_NOK){
		trace_printf("ramfs_init error!\n");
		return ;
	}
	//下面使用正常的uinx风格文件系统调用即可
	int fd;
	if((fd = open("/ramfs/newfile", O_WRONLY | O_CREAT)) == -1){
		trace_printf("can't open new file!\n");
		return ;
	}
	//写入字符串
	const char *str_write = "Hello, LiteOS!";
	write(fd, str_write, strlen(str_write));

	close(fd);

	if((fd = open("/ramfs/newfile", O_RDONLY)) == -1){
		trace_printf("can't open file!\n");
		return ;
	}

	char str_read[20] = {0};

	//读入字符串
	read(fd, str_read, 20);

	trace_printf("read string from file: %s\n",str_read);

	close(fd);
}
数据结构

los_vfs.c初始化了四个重要的变量

struct file          files [LOS_MAX_FILES];
UINT32               fs_mutex = LOS_ERRNO_MUX_PTR_NULL;
struct mount_point *mount_points = NULL;
struct file_system *file_systems = NULL;

后面两个分别是挂载点和文件系统的链表,上面已经说过,fs_mutex是互斥信号量,files是一个打开文件表,记录当前打开的文件信息,file的结构体定义如下

struct file
{
    struct file_ops    * f_fops;
    UINT32               f_flags;
    UINT32               f_status;
    off_t                f_offset;
    struct mount_point * f_mp;      /* can get private mount data here */
    UINT32               f_owner;   /* the task that openned this file */
    void               * f_data;
};
open()调用

LiteOS对系统调用做了UNIX风格的封装,open()调用的代码如下

int open (const char *path, int flags,...)
{
    int ret = los_open (path, flags);
    return MAP_TO_POSIX_RET(ret);
}

在los_open中,211行首先在files数组中获得一个空表项,219行找到文件所在的文件系统挂载点,243行通过file_ops结构体中的函数指针调用真正的文件系统的open调用,也就是los_ramfs.c中的ramfs_open()
ramfs_open()根据传入的flags执行相应动作,这里是创建一个新文件,所以在文件树中找不到文件,所以238行开始创建一个新节点,并将file变量中的指针指向文件地址(这里是内存地址),回到los_open(),将files数组中表项的下标作为描述符fd返回

其他的调用

类似open(),都是封装了los_xxx()函数,然后通过file_ops结构体中的函数指针调用相应的文件系统的底层调用,不再赘述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!