Hongmeng light kernel source code analysis: Virtual File System VFS

Posted by gelwa on Thu, 27 Jan 2022 12:26:09 +0100

This article is shared from Huawei cloud community Hongmeng light kernel M-core source code analysis series 21 01 Virtual File System VFS , author: zhushy.

VFS (Virtual File System) is the virtual layer of the file system. It is not an actual file system, but a software adhesive layer on the heterogeneous file system, which provides users with a unified Unix like file operation interface. Because different types of file system interfaces are not unified, if there are multiple file system types in the system, different non-standard interfaces need to be used to access different file systems. By adding VFS layer to the system, it provides a unified abstract interface and shields the differences of heterogeneous file systems at the bottom, so that the system call accessing the file system does not care about the underlying storage medium and file system type, so as to improve the development efficiency. This paper first introduces the structure and global variables of VFS, and then analyzes the operation interface of VFS file in detail. The source code involved in this article can be found on the open source site https://gitee.com/openharmony/kernel_liteos_m obtain.

1. VFS structure definition

In the file components\fs\vfs\fs_operations.h defines the structure involved in VFS virtual file system operation. (1) the struct MountOps structure at encapsulates mount related operations, including mount, unload and file system statistics. (2) the struct FsMap structure at maps the file system type and its corresponding mount operation and file system operation. The supported file types include "fat" and "littlefs". Through this structure, the mount operation and file system operation interface of the corresponding file type can be obtained. (3) struct FileOps at encapsulates the operation interface of the file system, including file operation, directory operation, statistics and other corresponding interfaces.

⑴  struct MountOps {        int (*Mount)(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags,            const void *data);        int (*Umount)(const char* target);        int (*Umount2)(const char* target, int flag);        int (*Statfs)(const char *path, struct statfs *buf);    };
⑵  struct FsMap {        const char *fileSystemtype;        const struct MountOps *fsMops;        const struct FileOps *fsFops;    };
⑶  struct FileOps {        int (*Open)(const char *path, int openFlag, ...);        int (*Close)(int fd);        int (*Unlink)(const char *fileName);        int (*Rmdir)(const char *dirName);        int (*Mkdir)(const char *dirName, mode_t mode);        struct dirent *(*Readdir)(DIR *dir);        DIR *(*Opendir)(const char *dirName);        int (*Closedir)(DIR *dir);        int (*Read)(int fd, void *buf, size_t len);        int (*Write)(int fd, const void *buf, size_t len);        off_t (*Seek)(int fd, off_t offset, int whence);        int (*Getattr)(const char *path, struct stat *buf);        int (*Rename)(const char *oldName, const char *newName);        int (*Fsync)(int fd);        int (*Fstat)(int fd, struct stat *buf);        int (*Stat)(const char *path, struct stat *buf);        int (*Ftruncate)(int fd, off_t length);    };

2. Important internal global variables of VFS

In the file components \ FS \ VFS \ Los_ fs. There are two important global variables in C, and the array g defined at ⑴_ FsMap maintains file system type mapping information. The array size is 2. It supports "fat" and "littlefs" file types. (2) variable g at_ FS points to the array g according to the mounted file type_ FsMap type element in FsMap. (3) the function InitMountInfo() at will give the array g_fsmap performs initialization assignment. The file system mapping information of "fat" file type maintained by element 0 and the file system mapping information of "littlefs" file type maintained by element 1. Mount operation and file system operation variables g_fatfsMnt,g_fatfsFops,g_lfsMnt,g_lfsFops is defined in the corresponding file system file. (4) the function MountFindfs() at is used to obtain file mapping information from the array according to the file type.

⑴  static struct FsMap g_fsmap[MAX_FILESYSTEM_LEN] = {0};⑵  static struct FsMap *g_fs = NULL;
⑶  static void InitMountInfo(void)    {    #if (LOSCFG_SUPPORT_FATFS == 1)        extern struct MountOps g_fatfsMnt;        extern struct FileOps g_fatfsFops;        g_fsmap[0].fileSystemtype = strdup("fat");        g_fsmap[0].fsMops = &g_fatfsMnt;        g_fsmap[0].fsFops = &g_fatfsFops;    #endif    #if (LOSCFG_SUPPORT_LITTLEFS == 1)        extern struct MountOps g_lfsMnt;        extern struct FileOps g_lfsFops;        g_fsmap[1].fileSystemtype = strdup("littlefs");        g_fsmap[1].fsMops = &g_lfsMnt;        g_fsmap[1].fsFops = &g_lfsFops;    #endif    }
⑷  static struct FsMap *MountFindfs(const char *fileSystemtype)    {        struct FsMap *m = NULL;
        for (int i = 0; i < MAX_FILESYSTEM_LEN; i++) {            m = &(g_fsmap[i]);            if (m->fileSystemtype && strcmp(fileSystemtype, m->fileSystemtype) == 0) {                return m;            }        }
        return NULL;    }

3. VFS related operation interface

In the previous series of articles "Hongmeng light kernel M-core source code analysis series 19 Musl LibC", the relevant interfaces are introduced. Those interfaces will call the operation interfaces in the VFS file system. The purpose and usage of each interface are no longer described. Quickly record each operation interface.

3.1 mount and unload operation

Mount and unload operations include LOS_FsMount,LOS_FsUmount,LOS_FsUmount2 and other three operations. (1) before mounting the file system, you need to initialize the file system mapping information, which will only be operated once. (2) obtain the corresponding file type mapping information according to the file system type. From here, we can know that the LiteOS-M kernel can only support one file system at the same time, not only fat but also littlefs. (3) the corresponding file system mount interface at to realize the mount operation. The other two functions are also relatively simple. You can read the code yourself.

int LOS_FsMount(const char *source, const char *target,                    const char *filesystemtype, unsigned long mountflags,                    const void *data)    {        static int initFlag = 0;
⑴      if (initFlag == 0) {            InitMountInfo();            initFlag = 1;        }
⑵      g_fs = MountFindfs(filesystemtype);        if (g_fs == NULL) {            errno = ENODEV;            return FS_FAILURE;        }
        if (g_fs->fsMops == NULL || g_fs->fsMops->Mount == NULL) {            errno = ENOSYS;            return FS_FAILURE;        }
⑶      return g_fs->fsMops->Mount(source, target, filesystemtype, mountflags, data);    }
    int LOS_FsUmount(const char *target)    {        if (g_fs == NULL) {            errno = ENODEV;            return FS_FAILURE;        }        if (g_fs->fsMops == NULL || g_fs->fsMops->Umount == NULL) {            errno = ENOSYS;            return FS_FAILURE;        }        return g_fs->fsMops->Umount(target);    }
    int LOS_FsUmount2(const char *target, int flag)    {        if (g_fs == NULL) {            errno = ENODEV;            return FS_FAILURE;        }        if (g_fs->fsMops == NULL || g_fs->fsMops->Umount2 == NULL) {            errno = ENOSYS;            return FS_FAILURE;        }        return g_fs->fsMops->Umount2(target, flag);    }

3.2 file directory operation

The file directory operation interface encapsulated by VFS includes LOS_Open,LOS_Close,LOS_Read,LOS_Write,LOS_Opendir,LOS_Readdir,LOS_Closedir, wait. Encapsulate the file directory operation interface of specific file types. The code is relatively simple and can be read by yourself. Some code fragments are as follows.

......
int LOS_Unlink(const char *path){    if (g_fs == NULL) {        errno = ENODEV;        return FS_FAILURE;    }    if (g_fs->fsFops == NULL || g_fs->fsFops->Unlink == NULL) {        errno = ENOSYS;        return FS_FAILURE;    }    return g_fs->fsFops->Unlink(path);}
int LOS_Fstat(int fd, struct stat *buf){    if (g_fs == NULL) {        errno = ENODEV;        return FS_FAILURE;    }    if (g_fs->fsFops == NULL || g_fs->fsFops->Fstat == NULL) {        errno = ENOSYS;        return FS_FAILURE;    }    return g_fs->fsFops->Fstat(fd, buf);}
......
int LOS_Mkdir(const char *path, mode_t mode){    if (g_fs == NULL) {        errno = ENODEV;        return FS_FAILURE;    }    if (g_fs->fsFops == NULL || g_fs->fsFops->Mkdir == NULL) {        errno = ENOSYS;        return FS_FAILURE;    }    return g_fs->fsFops->Mkdir(path, mode);}
DIR *LOS_Opendir(const char *dirName){    if (g_fs == NULL) {        errno = ENODEV;        return NULL;    }    if (g_fs->fsFops == NULL || g_fs->fsFops->Opendir == NULL) {        errno = ENOSYS;        return NULL;    }    return g_fs->fsFops->Opendir(dirName);}......

3.3 random number file

The file / dev/random can be used to generate random numbers. When opening macro loscfg_ RANDOM_ LiteOS-M supports random number files in dev. It can be seen from (1) that the random number dependency file ~ / openharmony/base/security/huks/interfaces/innerkits/huks_lite/hks_client.h and hks_tmp_client.c. These files are used to generate random numbers. (2) random defined at_ DEV_ FD and RANDOM_DEV_PATH is the file descriptor of random number file and the path of random number file respectively.

#ifdef LOSCFG_RANDOM_DEV⑴  #include "hks_client.h"⑵  #define RANDOM_DEV_FD  CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS    #define RANDOM_DEV_PATH  "/dev/random"    #endif

3.3.1 random LOS_Open and LOS_Close

This function opens a file and gets the file descriptor for further operation. (1) indicates that for random number files, the open label option can only support the specified ones, otherwise an error code will be returned. (2) obtain the standard path at. If the acquisition fails, the error code is returned. ⑶ compare whether the standard path obtained at is RANDOM_DEV_PATH: when confirming that it is a random number path, start to judge at (4). If the access mode is read-only, an error is returned. If the open option label is directory, an error is returned. If not, the random number file descriptor is returned. (5) if the obtained standard path is "/" or "/ dev", different error codes will be returned according to different options.

int LOS_Open(const char *path, int oflag, ...){#ifdef LOSCFG_RANDOM_DEV    unsigned flags = O_RDONLY | O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_LARGEFILE | O_TRUNC | O_EXCL | O_DIRECTORY;⑴  if ((unsigned)oflag & ~flags) {        errno = EINVAL;        return FS_FAILURE;    }
    size_t pathLen = strlen(path) + 1;    char *canonicalPath = (char *)malloc(pathLen);    if (!canonicalPath) {        errno = ENOMEM;        return FS_FAILURE;    }⑵  if (GetCanonicalPath(NULL, path, canonicalPath, pathLen) == 0) {        FREE_AND_SET_NULL(canonicalPath);        errno = ENOMEM;        return FS_FAILURE;    }
⑶  if (strcmp(canonicalPath, RANDOM_DEV_PATH) == 0) {        FREE_AND_SET_NULL(canonicalPath);⑷      if ((O_ACCMODE & (unsigned)oflag) != O_RDONLY) {            errno = EPERM;            return FS_FAILURE;        }        if ((unsigned)oflag & O_DIRECTORY) {            errno = ENOTDIR;            return FS_FAILURE;        }        return RANDOM_DEV_FD;    }⑸  if (strcmp(canonicalPath, "/") == 0 || strcmp(canonicalPath, "/dev") == 0) {        FREE_AND_SET_NULL(canonicalPath);        if ((unsigned)oflag & O_DIRECTORY) {            errno = EPERM;            return FS_FAILURE;        }        errno = EISDIR;        return FS_FAILURE;    }    FREE_AND_SET_NULL(canonicalPath);#endif......}

For random number files, when closed, success is returned directly without additional operation. The code snippet is as follows:

int LOS_Close(int fd){#ifdef LOSCFG_RANDOM_DEV    if (fd == RANDOM_DEV_FD) {        return FS_SUCCESS;    }#endif......}

3.3.2 random LOS_Read and LOS_Write

Read and write random number files using LOS_Read and LOS_Write interface. When reading, check the incoming parameters at (1). If the number of bytes read is 0, 0 will be returned; If the read cache address is empty, - 1 is returned; If the bytes read are greater than 1024, 1024 is used. (2) call HKS at_ generate_ Random() generates random numbers. Since the random number file is read-only, an error code of - 1 will be returned if you try to write.

ssize_t LOS_Read(int fd, void *buf, size_t nbyte){#ifdef LOSCFG_RANDOM_DEV    if (fd == RANDOM_DEV_FD) {⑴      if (nbyte == 0) {            return FS_SUCCESS;        }        if (buf == NULL) {            errno = EINVAL;            return FS_FAILURE;        }        if (nbyte > 1024) { /* 1024, max random_size */            nbyte = 1024; /* hks_generate_random: random_size must <= 1024 */        }        struct hks_blob key = {HKS_BLOB_TYPE_RAW, (uint8_t *)buf, nbyte};⑵      if (hks_generate_random(&key) != 0) {            errno = EIO;            return FS_FAILURE;        }        return (ssize_t)nbyte;    }#endif......}
ssize_t LOS_Write(int fd, const void *buf, size_t nbyte){#ifdef LOSCFG_RANDOM_DEV    if (fd == RANDOM_DEV_FD) {        errno = EBADF; /* "/dev/random" is readonly */        return FS_FAILURE;    }#endif......}

Summary

This paper introduces the structure and global variables of VFS, analyzes the operation interface of VFS file, and analyzes the random number file. Hurry of time is related to ability. If there is any mistake, you are welcome to correct it. Thank you for reading. If you have any questions and suggestions, you can leave a message to me under the blog. Thank you.

reference material

  • Harmonyos device > documentation Guide > basic capabilities - virtual file system

Click follow to learn about Huawei's new cloud technology for the first time~

Topics: gitee harmonyos liteos