最近遇到一個奇葩的問題,客戶回報,在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記憶體耗盡。