最近遇到一个奇葩的问题,客户反馈,在Android 系统的TV上,插入exfat格式的U盘,然后就system crash了,经过一系列分析后,我们找到了原因,把分析过程分享下,希望对有类似的问题的朋友参考:
由于kernel打印的信息比较多,我们截取比较重要的信息分析:
这里out_of_memory了, 内存耗尽了,我们继续看看下面的打印,看看是哪个进程导致的内存消耗
这里我们发现了fsck.exfat进程消耗了比较大的内存, 213754*4k(page size)=834M, 我们是1G的内存
为了验证fsck.exfat在校验过程的内存消耗,我们保存从插入U盘,到system crash过程的内存消耗
从插入U盘后,我们可以看到fsck.exfat后台消耗的内存在一直增加,最后消耗到800M+后就system crash了.
由于fsck.exfat 标准的开源的文件系统校验工具,应该不存在问题,我们备份了U盘的内容,打算把U盘格式化下,再验证,就在我们备份U盘内容的时候,发现了U盘的问题,其中某个文件异常了,出现了无限循环的路径地址, Windows电脑弹出了提示信息:
就是这个文件,我们在备份的时候异常了,貌似有个无限循环的路径地址,是不是就是这个原因导致的我们的fsck出问题了呢,我们查看下fsck.exfat的源码:
static void dirck(struct exfat* ef, const char* path)
{
struct exfat_node* parent;
struct exfat_node* node;
struct exfat_iterator it;
int rc;
size_t path_length;
char* entry_path;
if (exfat_lookup(ef, &parent, path) != 0)
exfat_bug("directory `%s' is not found", path);
if (!(parent->flags & EXFAT_ATTRIB_DIR))
exfat_bug("`%s' is not a directory (0x%x)", path, parent->flags);
path_length = strlen(path);
entry_path = malloc(path_length + 1 + EXFAT_NAME_MAX);
if (entry_path == NULL)
{
exfat_error("out of memory");
return;
}
strcpy(entry_path, path);
strcat(entry_path, "/");
rc = exfat_opendir(ef, parent, &it);
if (rc != 0)
{
free(entry_path);
exfat_put_node(ef, parent);
exfat_error("failed to open directory `%s'", path);
return;
}
while ((node = exfat_readdir(ef, &it)))
{
exfat_get_name(node, entry_path + path_length + 1, EXFAT_NAME_MAX);
exfat_debug("%s: %s, %"PRIu64" bytes, cluster %u", entry_path,
IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
node->size, node->start_cluster);
if (node->flags & EXFAT_ATTRIB_DIR)
{
directories_count++;
dirck(ef, entry_path);
}
else
files_count++;
nodeck(ef, node);
exfat_put_node(ef, node);
}
exfat_closedir(ef, &it);
exfat_put_node(ef, parent);
free(entry_path);
}
static void fsck(struct exfat* ef)
{
exfat_print_info(ef->sb, exfat_count_free_clusters(ef));
dirck(ef, "");
}
显然,在fsck的时候,会调用dirck函数, 这个函数会递归运行,遇到这种无限循环的目录,肯定就出不来了,每次进入dirck函数都会malloc分配内存,这样就会导致内存耗尽,好像是这么回事。
我们把U盘格式化后,在插入板上,问题消失了,系统能够正常挂载exfat的U盘了,到此,问题找到了。这个是由于U盘文件系统管理出问题,导致的无限循环的目录,引发了fsck.exfat内存耗尽。