首页 > 其他分享 >[RT-Thread记录]DFS虚拟文件系统文件夹操作异常

[RT-Thread记录]DFS虚拟文件系统文件夹操作异常

时间:2024-08-25 16:58:10浏览次数:7  
标签:RT count Thread dfs vnode DFS file path fullpath

项目场景:

系统:RT-Thread 5.0.2

硬件:STM32H743


问题描述

1.文件系统打开文件夹再关闭后,申请的内存没有释放

2.elm-fatFs文件系统重复操作同一个文件夹,如复制,会引起系统崩溃


原因分析:

        DFS虚拟文件系统文件打开关闭逻辑错误,文件系统版本升级更新后,dfs_file结构体改变,使用dfs_file_open()打开文件夹,描述符引用计数使用dfs_vnode的ref_count,但在dfs_file_close()中判断了dfs_file的ref_count的值,导致文件夹打开后无法正常关闭;

        文件类型、设备类型等文件打开时会设置和计算dfs_file的ref_count的值,但文件夹只设置了dfs_vnode的ref_count;

1.文件相关结构体

struct dfs_vnode
{
    uint16_t type;               /* Type (regular or socket) */

    char *path;                  /* Name (below mount point) */
    char *fullpath;              /* Full path is hash key */
    int ref_count;               /* Descriptor reference count */
    rt_list_t list;              /* The node of vnode hash table */

    struct dfs_filesystem *fs;
    const struct dfs_file_ops *fops;
    uint32_t flags;              /* self flags, is dir etc.. */

    size_t   size;               /* Size in bytes */
    void *data;                  /* Specific file system data */
};

struct dfs_file
{
    uint16_t magic;              /* file descriptor magic number */
    uint32_t flags;              /* Descriptor flags */
    int ref_count;               /* Descriptor reference count */
    off_t    pos;                /* Current file position */
    struct dfs_vnode *vnode;     /* file node struct */
    void *data;                  /* Specific fd data */
};

 2.文件打开函数

int dfs_file_open(struct dfs_file *fd, const char *path, int flags)
{
    struct dfs_filesystem *fs;
    char *fullpath;
    int result;
    struct dfs_vnode *vnode = NULL;
    rt_list_t *hash_head;

    /* parameter check */
    if (fd == NULL)
        return -EINVAL;

    /* make sure we have an absolute path */
    fullpath = dfs_normalize_path(NULL, path);
    if (fullpath == NULL)
    {
        return -ENOMEM;
    }

    RT_LOG_D("open file:%s", fullpath);

    dfs_fm_lock();
    /* vnode find */
    vnode = dfs_vnode_find(fullpath, &hash_head);
    if (vnode)
    {
        vnode->ref_count++;
        fd->pos   = 0;
        fd->vnode = vnode;
        dfs_fm_unlock();
        rt_free(fullpath); /* release path */
    }
    else
    {
        /* find filesystem */
        fs = dfs_filesystem_lookup(fullpath);
        if (fs == NULL)
        {
            dfs_fm_unlock();
            rt_free(fullpath); /* release path */
            return -ENOENT;
        }

        vnode = rt_calloc(1, sizeof(struct dfs_vnode));
        if (!vnode)
        {
            dfs_fm_unlock();
            rt_free(fullpath); /* release path */
            return -ENOMEM;
        }
        vnode->ref_count = 1;

        RT_LOG_D("open in filesystem:%s", fs->ops->name);
        vnode->fs    = fs;             /* set file system */
        vnode->fops  = fs->ops->fops;  /* set file ops */

        /* initialize the fd item */
        vnode->type  = FT_REGULAR;
        vnode->flags = 0;

        if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
        {
            if (dfs_subdir(fs->path, fullpath) == NULL)
                vnode->path = rt_strdup("/");
            else
                vnode->path = rt_strdup(dfs_subdir(fs->path, fullpath));
            RT_LOG_D("Actual file path: %s", vnode->path);
        }
        else
        {
            vnode->path = fullpath;
        }
        vnode->fullpath = fullpath;

        /* specific file system open routine */
        if (vnode->fops->open == NULL)
        {
            dfs_fm_unlock();
            /* clear fd */
            if (vnode->path != vnode->fullpath)
            {
                rt_free(vnode->fullpath);
            }
            rt_free(vnode->path);
            rt_free(vnode);

            return -ENOSYS;
        }

        fd->pos   = 0;
        fd->vnode = vnode;

        /* insert vnode to hash */
        rt_list_insert_after(hash_head, &vnode->list);
    }

    fd->flags = flags;

    if ((result = vnode->fops->open(fd)) < 0)
    {
        vnode->ref_count--;
        if (vnode->ref_count == 0)
        {
            /* remove from hash */
            rt_list_remove(&vnode->list);
            /* clear fd */
            if (vnode->path != vnode->fullpath)
            {
                rt_free(vnode->fullpath);
            }
            rt_free(vnode->path);
            fd->vnode = NULL;
            rt_free(vnode);
        }

        dfs_fm_unlock();
        RT_LOG_D("%s open failed", fullpath);

        return result;
    }

    fd->flags |= DFS_F_OPEN;
    if (flags & O_DIRECTORY)
    {
        fd->vnode->type = FT_DIRECTORY;
        fd->flags |= DFS_F_DIRECTORY;
    }
    dfs_fm_unlock();

    RT_LOG_D("open successful");
    return 0;
}

 在文件打开函数中,会设置描述符引用计数dfs_vnode的ref_count,打开文件类型和设备类型会相应类型的打开处理中对dfs_file的ref_count进行计数

3.文件关闭函数

int dfs_file_close(struct dfs_file *fd)
{
    struct dfs_vnode *vnode = NULL;
    int result = 0;

    if (fd == NULL)
    {
        return -ENXIO;
    }

    if (fd->ref_count == 1)
    {
        dfs_fm_lock();
        vnode = fd->vnode;
        
        if (vnode->ref_count <= 0)
        {
            dfs_fm_unlock();
            return -ENXIO;
        }
        
        if (vnode->fops->close != NULL)
        {
        result = vnode->fops->close(fd);
        }
        
        if (vnode->ref_count == 1)
        {
            /* remove from hash */
            rt_list_remove(&vnode->list);
            fd->vnode = NULL;
            
            if (vnode->path != vnode->fullpath)
            {
            rt_free(vnode->fullpath);
            }
            rt_free(vnode->path);
            rt_free(vnode);
        }
        dfs_fm_unlock();
    }
    return result;
}

 文件关闭函数判断了dfs_file的ref_count的值,会导致文件夹直接跳过不关闭,dfs_vnode也得不到清理,再次打开会对dfs_vnode的ref_count进行累加;

4. elm-fatFs文件打开错误

打开函数int dfs_elm_open(struct dfs_file *file)会对dfs_vnode的ref_count的值进行判断

if (file->vnode->ref_count > 1)
{
    if (file->vnode->type == FT_DIRECTORY
            && !(file->flags & O_DIRECTORY))
    {
        return -ENOENT;
    }
    file->pos = 0;
    return 0;
}

 文件夹没有正常关闭,再次打开后,会在此处直接return 0,没有给file->data复制,后续的文件夹遍历查找、复制等操作会使用data的值,就会出现访问非法地址引起的崩溃;


解决方案:

方式1:修改DFS虚拟文件系统中文件关闭函数判断逻辑,使文件夹关闭能正常进入关闭释放资源处理;

方式2:增加文件夹打开中对dfs_file的ref_count的处理

 如有错漏,欢迎指正!

标签:RT,count,Thread,dfs,vnode,DFS,file,path,fullpath
From: https://blog.csdn.net/weixin_44172134/article/details/141530516

相关文章

  • pthread线程
    线程概念线程是轻量级进程,一般是一个进程中的多个任务。进程是系统中最小的资源分配单位进程是操作系统中资源分配的最小单位。每个进程都有自己的地址空间,并且拥有独立的资源(如内存、文件句柄等)进程之间通常是相互独立的,彼此不能直接访问对方的内存空间线程是系统中......
  • SmartDeviceControl_FreeRTOS_Hal_Zet6
    SmartDeviceControl_FreeRTOS_Hal_Zet6系统框图显示子设备框图我们不想让文件互相调用遇到的问题:OLED无响应,I2C无法工作解决:使用的是软件I2C,问题在于OLED的驱动中已经包含获取从机应答的函数更新:屏幕为2.8TFT-LCD使用FSMC来模拟8080并口驱动LCDFSMC_D0-FSMC_D......
  • 数论 Part : Dirichlet 卷积 & 莫比乌斯反演 & 杜教筛
    \(\text{-1前言}\)\(\text{-1.0日志}\)24.08.24:启动本文企划,正式着笔。\(\text{-1.1本文记号说明}\)本文使用\(\cdot\)表示乘号,\(*\)表示卷积,\(\mathbb{P}\)表示质数集。\(\text{0基础函数科技}\)单位函数\({\bf1}(x)=1\)。幂函数\(id^k(x)=x^k\)。恒等函数(幂......
  • 基于STM32F103的FreeRTOS系列(十一)·信号量·二值信号量与计数信号量详细使用以及移植
    目录1. 信号量简介1.1 同步和互斥1.1.1 同步1.1.2 互斥1.1.3 总结1.2 分类1.2.1 二值信号量1.2.2 计数信号量1.2.3 互斥信号量1.2.4 递归信号量2. 信号量控制块3. 常用信号量API函数3.1 创建信号量函数3.1.1 创建二值信号量 xSe......
  • 【大模型理论篇】Mixture of Experts(混合专家模型, MOE)
    1.MoE的特点及为什么会出现MoE1.1MoE特点         MixtureofExperts(MoE,专家混合)【1】架构是一种神经网络架构,旨在通过有效分配计算负载来扩展模型规模。MoE架构通过在推理和训练过程中仅使用部分“专家”(子模型),优化了资源利用率,从而能够处理复杂任务。   ......
  • USART之串口发送+接收应用案例
    文章目录前言一、电路接线图二、应用案例代码三、应用案例分析3.1USART模块初始化3.1.1RCC开启时钟3.1.2GPIO初始化3.1.3配置USART3.1.4开启中断、配置NVIC3.1.5开启USART3.2USART串口收发模块3.2.1Serial_SendByte(发送一个字节数据)3.2.2USART1_IRQHandler(串口......
  • Writing your first Django app, part 1
    使用以下代码查看django的版本信息。$python-mdjango--version进入项目文件夹创建一个名为mysite的django项目。$django-adminstartprojectmysite会创建一个项目目录mysite/manage.pymysite/__init__.pysettings.pyurls.......
  • Study Plan For Algorithms - Part11
    1.合并两个有序链表题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。classSolution:defmergeTwoLists(self,list1:Optional[ListNode],list2:Option......
  • WebRTC 实时通信:构建高效网页视频通话的秘诀
    标题:WebRTC实时通信:构建高效网页视频通话的秘诀WebRTC(WebReal-TimeCommunications),即网页实时通信技术,是一种支持浏览器间无需额外插件即可实现音视频实时通信的API。本文将深入探讨WebRTC的基本概念、关键技术,并通过示例代码展示如何在网页中实现实时视频通话功能,让您快......
  • 牛客小白月赛99 C-迷宫(DFS)
    题目描述给定一个n×m\mathrm{n\timesm}n×m的迷宫,迷宫由"#"与"."两种字符组成。其中"#"代表障碍物,"."表示空地。迷宫中还有一个起点"S"和一个终点"E",它们都可以视为空地。 由于近期迷宫发生了塌方,导致起点和终点之间可能并不连通。幸运的是,你拥有一种超能......