天天看點

一個exfat U盤引起的systen crash

    最近遇到一個奇葩的問題,客戶回報,在Android 系統的TV上,插入exfat格式的U盤,然後就system crash了,經過一系列分析後,我們找到了原因,把分析過程分享下,希望對有類似的問題的朋友參考:

    由于kernel列印的資訊比較多,我們截取比較重要的資訊分析:

一個exfat U盤引起的systen crash

這裡out_of_memory了, 記憶體耗盡了,我們繼續看看下面的列印,看看是哪個程序導緻的記憶體消耗

一個exfat U盤引起的systen crash

這裡我們發現了fsck.exfat程序消耗了比較大的記憶體, 213754*4k(page size)= 834M, 我們是1G的記憶體

為了驗證fsck.exfat在校驗過程的記憶體消耗,我們儲存從插入U盤,到system crash過程的記憶體消耗

一個exfat U盤引起的systen crash
一個exfat U盤引起的systen crash

從插入U盤後,我們可以看到fsck.exfat背景消耗的記憶體在一直增加,最後消耗到800M+後就system crash了.

由于fsck.exfat 标準的開源的檔案系統校驗工具,應該不存在問題,我們備份了U盤的内容,打算把U盤格式化下,再驗證,就在我們備份U盤内容的時候,發現了U盤的問題,其中某個檔案異常了,出現了無限循環的路徑位址, Windows電腦彈出了提示資訊:

一個exfat U盤引起的systen crash

    就是這個檔案,我們在備份的時候異常了,貌似有個無限循環的路徑位址,是不是就是這個原因導緻的我們的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記憶體耗盡。

一個exfat U盤引起的systen crash

繼續閱讀