一、关键字:

OpenHarmony 4.1Release 升级至 5.0.0Release ;sharefs ;死机重启 

二、问题描述

设备型号:黄鹂

系统版本:OpenHarmony 5.0.0

代码版本:OpenHarmony-5.0.0

问题现象:将 const.distributed_file_property.enabled 置为 false,重启设备后,不断死机重启,无法进入桌面。

三、原因分析

3.1 正常机制

openharmony系统针对未适配hmdfs的设备提供了另一套文件管理系统的选择,即 local_mount+sharefs_mount 。

在将 const.distributed_file_property.enabled 置为 false,重启设备后,设备可以正常进入桌面并实现相关功能。

3.2 异常机制

将 const.distributed_file_property.enabled 置为 false,重启设备后,不断死机重启,无法进入桌面。

3.2.1分析报错日志

根据日志中的首行信息可知,崩溃原因是出现了空指针:

Unable to handle kernel NULL pointer dereference at virtual address 000000000000000a

调用堆栈及关键信息如下:

[   15.310793][ T1485] pc : strchr+0x8/0x38
[   15.310803][ T1485] lr : match_token+0x94/0x270

[   15.327239][ T1485] Call trace:
[   15.327241][ T1485]  strchr+0x8/0x38
[   15.327245][ T1485]  sharefs_parse_options+0xc8/0x154
[   15.327250][ T1485]  sharefs_fill_super+0x11c/0x234
[   15.337940][ T1485]  mount_nodev+0x7c/0xf0
[   15.337945][ T1485]  sharefs_mount+0x4c/0x80
[   15.337949][ T1485]  legacy_get_tree+0x5c/0xc8
[   15.337953][ T1485]  vfs_get_tree+0x5c/0x134
[   15.337955][ T1485]  do_new_mount+0x164/0x380
[   15.344516][ T1485]  path_mount+0x288/0x508
[   15.344519][ T1485]  __arm64_sys_mount+0x204/0x530
[   15.344521][ T1485]  invoke_syscall+0x6c/0x15c
[   15.344525][ T1485]  el0_svc_common.llvm.16526140288913859248+0xd4/0x120
[   15.344528][ T1485]  do_el0_svc+0x34/0xac
[   15.344531][ T1485]  el0_svc+0x2c/0x94
[   15.362689][ T1485]  el0t_64_sync_handler+0x8c/0xf0
[   15.362691][ T1485]  el0t_64_sync+0x1b4/0x1b8

可见最终调用至 match_token+0x94 处时崩溃,通过反编译定位至110行。

3.2.2 添加判空及日志打印

根据前面的信息,常规思路是直接在 match_token 函数中添加对各入参的判空,如下所示:

 

重新编译后,系统仍无法开机,且无相关日志打印报错堆栈也未发生改变。此处笔者已有怀疑是发生了踩内存,但受限于工具和技术储备,并没有直接证据。

3.2.3 更深层调用分析

由于本身match_token()未定位到具体的空指针,因此分析 match_one()中的处理流程:

static int match_one(char *s, const char *p, substring_t args[])
{
	char *meta;
	int argc = 0;
	if (!p)
		return 1;
	while(1) {
		int len = -1;
		meta = strchr(p, '%');
		if (!meta)
			return strcmp(p, s) == 0;
		if (strncmp(p, s, meta-p))
			return 0;
		s += meta - p;
		p = meta + 1;
		if (isdigit(*p))
			len = simple_strtoul(p, (char **) &p, 10);
		else if (*p == '%') {
			if (*s++ != '%')
				return 0;
			p++;
			continue;
		}
		if (argc >= MAX_OPT_ARGS)
			return 0;

		args[argc].from = s;
		switch (*p++) {
		case 's': {
			size_t str_len = strlen(s);
			if (str_len == 0)
				return 0;
			if (len == -1 || len > str_len)
				len = str_len;
			args[argc].to = s + len;
			break;
		}
		case 'd':
			simple_strtol(s, &args[argc].to, 0);
			goto num;
		case 'u':
			simple_strtoul(s, &args[argc].to, 0);
			goto num;
		case 'o':
			simple_strtoul(s, &args[argc].to, 8);
			goto num;
		case 'x':
			simple_strtoul(s, &args[argc].to, 16);
		num:
			if (args[argc].to == args[argc].from)
				return 0;
			break;
		default:
			return 0;
		}
		s = args[argc].to;
		argc++;
	}
}

可以看到比较有可能出现空指针情况的就是数组指针p,因此在该函数中加了大量的非空判断。

但此举并没有解决问题。且添加的error打印均未触发输出,崩溃堆栈的偏移量也没有变化。尝试在正常流程中打印无用信息来确认日志是否正常生成时,日志均未能输出。因此怀疑此段代码本身存在异常。

3.2.4 内核代码结构分析

在5.0.0解耦工作中,我们采用了两套工程分别编译的方案,用于区分开闭源代码,内核中的部分ko均在另一套工程中编译生成。

对比两套工程中的内核代码,发现内核代码本身存在较大差异,之前的修改均仅在开源工程中修改,尝试同步至闭源工程再执行测试动作。发现设备能够正常开机。

四、方案优化

此前,所有内核的修改均需要同时往开源工程和闭源工程中合入,将ko编译代码挑出来放在产品化路径下,此外,将闭源工程的内核代码直接指向开源工程(闭源工程与开源工程直接使用同一套内核代码),并合入sharefs的相关patch,可以最小化解决问题。

五、sharefs适配

若系统未曾适配hmdfs及sharefs,可参考下述pr进行适配:

https://gitee.com/openharmony/kernel_linux_6.6/pulls/6

https://gitee.com/openharmony/kernel_linux_6.6/pulls/62

 

相关文件下载
panic.txt
12.58 KB
下载
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐