在 Dfs 中使用 cat cp 等命令时拔掉 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
- 点赞
- 收藏
- 关注作者
评论(0)