OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【文件系统】下

适配新的文件系统

基本概念

所谓对接VFS层,其实就是指实现VFS层定义的若干接口函数,可根据文件系统的特点和需要适配其中部分接口。一般情况下,支持文件读写,最小的文件系统适配看起来是这样的:

struct MountOps g_yourFsMountOps = {
    .Mount = YourMountMethod,
};

struct file_operations_vfs g_yourFsFileOps = {
  .read = YourReadMethod,
  .write = YourWriteMethod,
}

struct VnodeOps g_yourFsVnodeOps = {
    .Create = YourCreateMethod;
    .Lookup = YourLookupMethod;
    .Reclaim = YourReclaimMethod;
};

FSMAP_ENTRY(yourfs_fsmap, "your fs name", g_yourFsMountOps, TRUE, TRUE);  // 注册文件系统

说明:

  1. open和close接口不是必须要实现的接口,因为这两个接口是对文件的操作,对下层的文件系统一般是不感知的,只有当要适配的文件系统需要在open和close时做一些特别的操作时,才需要实现。

  2. 适配文件系统,对基础知识的要求较高,适配者需要对要适配的文件系统的原理和实现具有深刻的理解,本节中不会事无巨细地介绍相关的基础知识,如果您在适配的过程中遇到疑问,建议参考kernel/liteos_a/fs目录下已经适配好的文件系统的代码,可能就会豁然开朗。

适配Mount接口

Mount是文件系统第一个被调用的接口,该接口一般会读取驱动的参数,根据配置对文件系统的进行初始化,最后生成文件系统的root节点。Mount接口的定义如下:

int (*Mount)(struct Mount *mount, struct Vnode *blkDriver, const void *data);

其中,第一个参数struct Mount *mount是Mount点的信息,适配时需要填写的是下面的变量:

struct Mount {
    const struct MountOps *ops;        /* Mount相关的函数钩子 */
    struct Vnode *vnodeCovered;        /* Mount之后的文件系统root节点 */
    void *data;                        /* Mount点的私有数据 */
};

第二个参数struct Vnode *blkDriver是驱动节点,可以通过这个节点访问驱动。

第三个参数const void *data是mount命令传入的数据,可以根据文件系统的需要处理。

下面以JFFS2为例,详细看一下mount接口是如何适配的:

int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
{
    int ret;
    int partNo;
    mtd_partition *p = NULL;
    struct MtdDev *mtd = NULL;
    struct Vnode *pv = NULL;
    struct jffs2_inode *rootNode = NULL;

    LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);

    /* 首先是从驱动节点中获取文件系统需要的信息,例如jffs2读取的是分区的编号 */
    p = (mtd_partition *)((struct drv_data *)blkDriver->data)->priv;
    mtd = (struct MtdDev *)(p->mtd_info);

    if (mtd == NULL || mtd->type != MTD_NORFLASH) {
        LOS_MuxUnlock(&g_jffs2FsLock);
        return -EINVAL;
    }

    partNo = p->patitionnum;

    /* 然后生成一个文件系统的根Vnode,这里注意不要搞混rootNode和根Vnode,rootNode类型是inode,是jffs2内部维护的私有数据,而Vnode是VFS的概念,是通用的文件节点,
       这一步实际上就是把文件系统内部的私有信息保存到Vnode中,这样就可以通过Vnode直接找到文件系统中的对应文件。
     */
    ret = jffs2_mount(partNo, &rootNode);
    if (ret != 0) {
        LOS_MuxUnlock(&g_jffs2FsLock);
        return ret;
    }

    ret = VnodeAlloc(&g_jffs2Vops, &pv);
    if (ret != 0) {
        LOS_MuxUnlock(&g_jffs2FsLock);
        goto ERROR_WITH_VNODE;
    }

    /* 下面这段填写的是关于这个Vnode对应文件的相关信息,uid\gid\mode这部分信息,有的文件系统可能不支持,可以不填 */
    pv->type = VNODE_TYPE_DIR;
    pv->data = (void *)rootNode;
    pv->originMount = mnt;
    pv->fop = &g_jffs2Fops;
    mnt->data = p;
    mnt->vnodeCovered = pv;
    pv->uid = rootNode->i_uid;
    pv->gid = rootNode->i_gid;
    pv->mode = rootNode->i_mode;

    /* 这里的HashInsert是为了防止重复生成已经生成过的Vnode, 第二个参数一般会选择本文件系统内可以唯一确定某一个文件的信息,例如这里是jffs2内部inode的地址 */
    (void)VfsHashInsert(pv, rootNode->i_ino);

    g_jffs2PartList[partNo] = blkDriver;

    LOS_MuxUnlock(&g_jffs2FsLock);

    return 0;
ERROR_WITH_VNODE:
    return ret;
}
...
...
const struct MountOps jffs_operations = {
    .Mount = VfsJffs2Bind,
    ...
    ...
};

总结:

  1. 首先从驱动节点中获取需要的私有信息。

  2. 根据私有信息,生成文件系统的根节点。

适配Lookup接口

Lookup是查找文件的接口,它的函数原型是:

int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);

很好理解,就是从父节点parent开始,根据文件名name和文件名长度len,查找到对应的vnode返回给上层。

这个接口适配起来思路很清晰,给了父节点的信息和文件名,实现从父目录中查询名字为name的文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值