Linux内核源代码情景分析-特殊文件系统/proc-对/proc/self/cwd的访问

本文详细分析了Linux内核中对/proc/self/cwd的访问过程,从path_walk开始,经过多次循环查找,通过proc_pid_make_inode创建inode结构,最终在proc_base_lookup中完成实际操作,揭示了/proc/self/cwd的内部工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    继上篇文章Linux内核源代码情景分析-特殊文件系统/proc,我们对/proc/loadavg访问后,这篇文章是对/proc/self/cwd的访问。

int __user_walk(const char *name, unsigned flags, struct nameidata *nd)
{
	char *tmp;
	int err;

	tmp = getname(name);//在系统空间分配一个页面,并从用户空间把文件名复制到这个页面
	err = PTR_ERR(tmp);
	if (!IS_ERR(tmp)) {
		err = 0;
		if (path_init(tmp, flags, nd))
			err = path_walk(tmp, nd);
		putname(tmp);
	}
	return err;
}
    name就为 /proc/self/cwd,重要分析下path_walk函数,请参考Linux内核源代码情景分析-从路径名到目标节点

    第一次循环path_walk发现/proc是个安装节点而通过_follow_down找到了proc文件系统的根节点的dentry结构,nameidata结构中的指针dentry指向这个数据结构。、

    第二次循环搜索路径名中的下一个节点self,由于这个节点并不是路径名的最后一个节点,所以执行的代码如下:

dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//在内存中寻找该节点业已建立的dentry结构  
        if (!dentry) {//如果没有找到  
            dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);//那么就要建立该节点的dentry结构  
            err = PTR_ERR(dentry);  
            if (IS_ERR(dentry))  
                break;  
        }  
    参考 Linux内核源代码情景分析-特殊文件系统/proc,最终也要通过proc_root_lookup()调用proc_lookup(),试图为节点建立起其dentry结构和inode结构。可是由于/proc/self并没有一个固定的proc_dir_entry结构,所以对proc_lookup()的调用必然会失败,因而会进一步调用proc_pid_lookup(),代码如下:

static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
{
	if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
		int nlink = proc_root.nlink;

		nlink += nr_threads;

		dir->i_nlink = nlink;
	}

	if (!proc_lookup(dir, dentry))///由于/proc/self并没有一个固定的proc_dir_entry结构,所以对proc_lookup()的调用必然会失败
		return NULL;
	
	return proc_pid_lookup(dir, dentry);//会调用这个函数
}
struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
{
	struct inode *inode;
	struct proc_dir_entry * de;
	int error;

	error = -ENOENT;
	inode = NULL;
	de = (struct proc_dir_entry *) dir->u.generic_ip;
	if (de) {//找不到/proc/self节点
		for (de = de->subdir; de ; de = de->next) {
			if (!de || !de->low_ino)
				continue;
			if (de->namelen != dentry->d_name.len)
				continue;
			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
				int ino = de->low_ino;
				error = -EINVAL;
				inode = proc_get_inode(dir->i_sb, ino, de);
				break;
			}
		}
	}

	if (inode) {
		dentry->d_op = &proc_dentry_operations;
		d_add(dentry, inode);
		return NULL;
	}
	return ERR_PTR(error);//返回错误码
}

struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
{
	unsigned int pid, c;
	struct task_struct *task;
	const char *name;
	struct inode *inode;
	int len;

	pid = 0;
	name = dentry->d_name.name;
	len = dentry->d_name.le
static struct file *path_openat(struct nameidata *nd, const struct open_flags *op, unsigned flags) { struct file *file; int error; file = alloc_empty_file(op->open_flag, current_cred()); if (IS_ERR(file)) return file; if (unlikely(file->f_flags & __O_TMPFILE)) { error = do_tmpfile(nd, flags, op, file); } else if (unlikely(file->f_flags & O_PATH)) { error = do_o_path(nd, flags, file); } else { const char *s = path_init(nd, flags); while (!(error = link_path_walk(s, nd)) && (s = open_last_lookups(nd, file, op)) != NULL) ; if (!error) error = do_open(nd, file, op); terminate_walk(nd); } if (likely(!error)) { if (likely(file->f_mode & FMODE_OPENED)) return file; WARN_ON(1); error = -EINVAL; } fput(file); if (error == -EOPENSTALE) { if (flags & LOOKUP_RCU) error = -ECHILD; else error = -ESTALE; } return ERR_PTR(error); } 分析这段异常 == 异常报告v2.3(仅供参考) == 报告解读: MediaTek On-Line> Quick Start> NE/KE分析报告解读> KE分析报告 详细描述: path_openat()从错误地址(0xFFFFFFFFE27A3C70)读数据,请结合崩溃进程调用栈检查相关代码 平台 : MT6769V/CZ (0A8C28C8,EBA795BE) 版本 : alps-vf-mp-v0.mp1.tc16sp-pr2unknownRMX3910export_11_15.0.0.800/user build 异常时间: 541.036193秒, Sun Jun 8 15:12:55 WITA 2025 == 平台信息 == -- CPU 0 1 2 3 [4] 5 6 7 -- L opp: 0( 918mV, 1800MHz, 0C) 539.948857s B opp: 15( 650mV, 850MHz, 0C) 541.036187s CCI opp: 6( 762mV, 856MHz, 0C) 541.034279s -- LPDDR4(3600,8G)|Storage -- vcore dvfs opp: [-140462620.179732]12(700mV, 1534MHz) 已热重启: 1次 -- Low Power -- SPM last pc: 0xa8e == CPU信息 == 崩溃CPU信息: CPU4: Thread-7, pid: 5479, 优先级: 120 本地调用栈: vmlinux __d_entry_type(dentry=0xFFFFFFFFE27A3C70) </proc/self/cwd/kernel-6.6/include/linux/dcache.h:395> vmlinux d_can_lookup(dentry=0xFFFFFFFFE27A3C70) </proc/self/cwd/kernel-6.6/include/linux/dcache.h:410> vmlinux d_is_dir(dentry=0xFFFFFFFFE27A3C70) </proc/self/cwd/kernel-6.6/include/linux/dcache.h:420> vmlinux do_open(nd=0xFFFFFFC0940E3C70, file=0xFFFFFF801F75C500, op=0xFFFFFFC0940E3DA0) + 224 </proc/self/cwd/kernel-6.6/fs/namei.c:3610> vmlinux path_openat(nd=0xFFFFFFC0940E3D60, op=0xFFFFFFC0940E3DA0, flags=2483960812) + 2340 </proc/self/cwd/kernel-6.6/fs/namei.c:3791> vmlinux do_filp_open(op=0xFFFFFFC0940E3DC0) + 180 </proc/self/cwd/kernel-6.6/fs/namei.c:3818> vmlinux do_sys_openat2(how=0xFFFFFFC0940E3E10) + 128 </proc/self/cwd/kernel-6.6/fs/open.c:1442> vmlinux do_sys_open() + 56 </proc/self/cwd/kernel-6.6/fs/open.c:1457> vmlinux __do_sys_openat() + 56 </proc/self/cwd/kernel-6.6/fs/open.c:1473> vmlinux __se_sys_openat() + 56 </proc/self/cwd/kernel-6.6/fs/open.c:1468> vmlinux __arm64_sys_openat() + 108 </proc/self/cwd/kernel-6.6/fs/open.c:1468> vmlinux __invoke_syscall() + 48 </proc/self/cwd/kernel-6.6/arch/arm64/kernel/syscall.c:37> vmlinux invoke_syscall() + 84 </proc/self/cwd/kernel-6.6/arch/arm64/kernel/syscall.c:51> vmlinux el0_svc_common(sc_nr=463) + 124 </proc/self/cwd/kernel-6.6/arch/arm64/kernel/syscall.c:136> vmlinux do_el0_svc() + 24 </proc/self/cwd/kernel-6.6/arch/arm64/kernel/syscall.c:155> vmlinux el0_svc() + 52 </proc/self/cwd/kernel-6.6/arch/arm64/kernel/entry-common.c:683> vmlinux el0t_64_sync_handler() + 100 </proc/self/cwd/kernel-6.6/arch/arm64/kernel/entry-common.c:701> vmlinux 0xFFFFFFE609491584() </proc/self/cwd/kernel-6.6/arch/arm64/kernel/entry.S:525> == 栈结束 == 对应汇编指令: 行号 地址 指令 提示 /proc/self/cwd/kernel-6.6/arch/arm64/include/asm/current.h FFFFFFE6098332FC: MOV X21, X0 ; path_openat()参数 1可能有问题 /proc/self/cwd/kernel-6.6/fs/namei.c 3787: FFFFFFE6098333FC: B FFFFFFE609833B0C 3599: FFFFFFE609833B0C: /proc/self/cwd/kernel-6.6/include/linux/audit.h 0 : FFFFFFE609833B40: B FFFFFFE609833B60 /proc/self/cwd/kernel-6.6/fs/namei.c 3606: FFFFFFE609833B60: 3607: FFFFFFE609833B6C: TBNZ W24, #6, FFFFFFE609833BD0 0 : FFFFFFE609833BD0: 3608: FFFFFFE609833BDC: TBNZ W8, #4, FFFFFFE609833BE8 3610: FFFFFFE609833BE8: LDR X8, [X21, #0x8] ; 0xFFFFFFFFE27A3C70 <- [0xFFFFFFC0940E3C78] /proc/self/cwd/kernel-6.6/include/linux/dcache.h 395 : FFFFFFE609833BEC: LDR W9, [X8] ; 进程停止在这里 /proc/self/cwd/kernel-6.6/fs/namei.c 3818: FFFFFFE609833204: MOV X0, SP ; R31:0xFFFFFFC0940E3D60 FFFFFFE609833218: BL path_openat() 当时的寄存器值: X0: FFFFFF802D2DDDC0, X1: 0000000000000001, X2: 0000000000000000, X3: 000000000000000B X4: FFFFFFFE01CDA460, X5: FFFFFFE6069AC7B8, X6: 00747365745F6473, X7: 00747365745F6473 X8: FFFFFFFFE27A3C70, X9: FFFFFFFF00000000, X10: 0000000300000000, X11: 0000000300000000 X12: 0000000200000000, X13: 00000000684537D0, X14: FFFFFFE60B59A658, X15: 0000000000000328 X16: 000000006155CDD4, X17: 000000006155CDD4, X18: FFFFFFC091915048, X19: FFFFFF801F75C500 X20: 0000000000000000, X21: FFFFFFC0940E3C70, X22: FFFFFFC0940E3DA0, X23: FFFFFFE60B66BE00 X24: 00000000000200C2, X25: 0000000000000040, X26: 00000000000200C2, X27: FFFFFFC0940E3BF0 X28: FFFFFF802D2DDDC0, X29: FFFFFFC0940E3C10, X30: FFFFFFE609833B08, SP: FFFFFFC0940E3BC0 PC: FFFFFFE609833BEC
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值