在 Dfs 中使用 cat cp 等命令时拔掉 U盘 死机问题

举报
斑馬斑馬 发表于 2021/09/03 15:09:45 2021/09/03
【摘要】 一、问题现象1、使用ls、cp、mv、cat、rm、mkdir、echo命令操作文件未结束之前拔掉U盘,自己写的自动卸载U盘程序会出现死机现象。二、问题原因1、每次进行文件操作需要用到互斥锁的,流程:文件系统上锁–文件操作–文件系统解锁。但是上述命令所调用的函数是没有使用互斥锁,操作文件的时候拔掉U盘触发dfs_unmount函数卸载U盘,最终现象为两个线程同时对U盘进行文件操作发生异常。三...

一、问题现象

1、使用ls、cp、mv、cat、rm、mkdir、echo命令操作文件未结束之前拔掉U盘,自己写的自动卸载U盘程序会出现死机现象。

二、问题原因

1、每次进行文件操作需要用到互斥锁的,流程:文件系统上锁–文件操作–文件系统解锁。但是上述命令所调用的函数是没有使用互斥锁,操作文件的时候拔掉U盘触发dfs_unmount函数卸载U盘,最终现象为两个线程同时对U盘进行文件操作发生异常。

三、解决方案

1、加上互斥锁即可,系统中已经有现成dfs的互斥锁函数dfs_lock和dfs_unlock,调用即可。在ls、cp、mv、cat、rm、mkdir、echo所调用的函数前进行dfs_lock,调用完成后dfs_unlock就可以解决问题。
2、按照上述进行解决其实使用cat时,拔掉U盘虽然不会死机,但是仍然会有异常发生,具体我会在后面讲到。
修改后的代码,我就不一一截图,直接上修改过的函数,这些函数都是在msh.c。

int cmd_ls(int argc, char **argv) {
    extern void ls(const char *pathname);
    dfs_lock();

    if (argc == 1) {
        #ifdef DFS_USING_WORKDIR
        ls(working_directory);
        #else
        ls("/");
        #endif
    }
    else {
        ls(argv[1]);
    }

	dfs_unlock();
    return 0;
}

int cmd_cp(int argc, char **argv) {
    void copy(const char *src, const char *dst);
    dfs_lock();

    if (argc != 3) {
        rt_kprintf("Usage: cp SOURCE DEST\n");
        rt_kprintf("Copy SOURCE to DEST.\n");
    }
    else {
        copy(argv[1], argv[2]);
    }

    dfs_unlock();
    return 0;
}

int cmd_mv(int argc, char **argv) {
    int res = 0;
    dfs_lock();

    if (argc != 3) {
        rt_kprintf("Usage: mv SOURCE DEST\n");
        rt_kprintf("Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n");
    }
    else {
        int fd;
        char *dest = RT_NULL;
        rt_kprintf("%s => %s\n", argv[1], argv[2]);
        fd = open(argv[2], O_DIRECTORY, 0);

        if (fd >= 0) {
            char *src;
            close(fd);
            /* it's a directory */
            dest = (char *)rt_malloc(DFS_PATH_MAX);
            if (dest == RT_NULL) {
                rt_kprintf("out of memory\n");
				res = -RT_ENOMEM;
                goto end;
            }
            src = argv[1] + rt_strlen(argv[1]);
            while (src != argv[1]) {
                if (*src == '/') break;
                src --;
            }
            rt_snprintf(dest, DFS_PATH_MAX - 1, "%s/%s", argv[2], src);
        }

        else {
            fd = open(argv[2], O_RDONLY, 0);
            if (fd >= 0) {
                close(fd);
                unlink(argv[2]);
            }
            dest = argv[2];
        }

        rename(argv[1], dest);
        if (dest != RT_NULL && dest != argv[2]) rt_free(dest);
    }
    end:
    dfs_unlock();
    return res;
}

int cmd_cat(int argc, char **argv) {
    int index;
    extern void cat(const char *filename);
    dfs_lock();

    if (argc == 1) {
        rt_kprintf("Usage: cat [FILE]...\n");
        rt_kprintf("Concatenate FILE(s)\n");
        goto end;
    }
    for (index = 1; index < argc; index ++) {
        cat(argv[index]);
    }

    end:
    dfs_unlock();
    return 0;
}

int cmd_rm(int argc, char **argv) {
    int index, n;
    char f = 0, r = 0, v = 0;
    dfs_lock();

    if (argc == 1) {
        rt_kprintf("Usage: rm option(s) FILE...\n");
        rt_kprintf("Remove (unlink) the FILE(s).\n");
        goto end;
    }

    if (argv[1][0] == '-') {
        for (n = 0; argv[1][n]; n++) {
            switch (argv[1][n]) {
                case 'f': f = 1; break;
                case 'r': r = 1; break;
                case 'v': v = 1; break;
                case '-': break;
                default:
                    rt_kprintf("Error: Bad option: %c\n", argv[1][n]);
					goto end;
            }
        }
        argc -= 1;
        argv = argv + 1;
    }

    for (index = 1; index < argc; index ++) {
        struct stat s;
        if (stat (argv[index], &s) == 0) {
            if (s.st_mode & S_IFDIR) {
                if (r == 0)
                    rt_kprintf("cannot remove '%s': Is a directory\n", argv[index]);
                else
                    directory_delete_for_msh(argv[index], f, v);
            }
            else if (s.st_mode & S_IFREG) {
                if (unlink(argv[index]) != 0) {
                    if (f == 0)
                        rt_kprintf("cannot remove '%s'\n", argv[index]);
                }
                else if (v) {
                    rt_kprintf("removed '%s'\n", argv[index]);
                }
            }
        }
        else if (f == 0) {
            rt_kprintf("cannot remove '%s': No such file or directory\n", argv[index]);
        }
    }
	
    end:
    dfs_unlock();
    return 0;
}

int cmd_mkdir(int argc, char **argv) {
    dfs_lock();
    if (argc == 1) {
        rt_kprintf("Usage: mkdir [OPTION] DIRECTORY\n");
        rt_kprintf("Create the DIRECTORY, if they do not already exist.\n");
    }
    else {
        mkdir(argv[1], 0);
    }

    dfs_unlock();
    return 0;
}

int cmd_df(int argc, char** argv) {
	dfs_lock();
    if (argc != 2) {
        df("/");
    }
    else {
        if ((strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0)) {
            rt_kprintf("df [path]\n");
        }
        else {
            df(argv[1]);
        }
    }

    dfs_unlock();
    return 0;
}

int cmd_echo(int argc, char** argv) {
    dfs_lock();
    if (argc == 2) {
        rt_kprintf("%s\n", argv[1]);
    }
    else if (argc == 3) {
        int fd;

        fd = open(argv[2], O_RDWR | O_APPEND | O_CREAT, 0);
        if (fd >= 0) {
            write (fd, argv[1], strlen(argv[1]));
            close(fd);
        }
        else {
            rt_kprintf("open file:%s failed!\n", argv[2]);
        }
    }
    else {
        rt_kprintf("Usage: echo \"string\" [filename]\n");
    }

    dfs_unlock();
    return 0;
}

四、cat问题现象

1、使用cat命令读取U盘文件并打印读到的数据时突然拔掉U盘,正常会因为读取失败而停止输出,实际上则不断的打印最后读到的一串数据。


五、cat问题原因

1、cat命令实质调用的核心函数是dfs_file_read,这个函数返回一个长度值,如果返回值小于0说明发生错误,但是接收这个返回值的却是一个uint32_t变量,导致出错时无法识别错误,反而识别成读取到长度非常大的数据,所以在不断打印。


六、cat解决方案

1、将length改成int类型即可

  

  
————————————————
版权声明:本文为CSDN博主「小破孩 != ERR」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41738023/article/details/114635299以及https://blog.csdn.net/weixin_41738023/article/details/114640177

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。