当前位置: 首页 > news >正文

获取inode的完整路径包含挂载的路径

一、背景

在之前的博客 缺页异常导致的iowait打印出相关文件的绝对路径-CSDN博客 里的 2.2.3 一节和 关于inode,dentry结合软链接及硬链接的实验-CSDN博客 里,我们讲到了在内核里通过inode获取inode对应的绝对路径的方法。对于根目录下的文件而言,这也是足够了,但是对于非根目录下的文件即有过挂载后的文件,这就不够了。我们后面的博客会讲到,我们有时候比如在shm相关的监控场景下,还是需要知道dentry的super_block的挂载目录的。

我们在第二章里先贴出能获取inode的dentry的包含挂载路径的完整路径的源码,并演示成果。在第三章里,我们给出相关的源码解释及原理分析。

二、源码及成果展示

2.1 内核部分的改动

在fs/namespace.c里添加一个export symbol的函数get_dentry_by_sb_currns:

struct dentry* get_dentry_by_sb_currns(struct super_block *sb)
{
	struct mnt_namespace *mnt_ns = current->nsproxy->mnt_ns;
	struct mount *mnt;
	struct dentry* dentry = NULL;
	lock_mount_hash();
	list_for_each_entry(mnt, &mnt_ns->list, mnt_list) {
		if (mnt->mnt.mnt_sb == sb) {
			dentry = mnt->mnt_mountpoint;
			break;
		}
	}
	unlock_mount_hash();
	return dentry;
}
EXPORT_SYMBOL_GPL(get_dentry_by_sb_currns);

2.2 内核模块代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/dcache.h>
#include <linux/namei.h>

// 模块参数
static char *filepath = "/tmp/testfile";  // 默认文件路径
module_param(filepath, charp, S_IRUGO);
MODULE_PARM_DESC(filepath, "Path of the file to open");

char buffer[4096];
char buffer_mount1[4096];
char buffer_mount2[4096];
char buffer_mount3[4096];

extern struct dentry* get_dentry_by_sb_currns(struct super_block *sb);

int getfullpath(struct inode *inode)
{
    struct dentry *dentry;
    printk("inode = %p\n", inode);
	hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
        char *path;
        path = dentry_path_raw(dentry, buffer, 4096);
        if (IS_ERR(path)){
            continue;   
        }
        printk("dentry name = %s , path = %s\n", dentry->d_name.name, path);

        {
            struct dentry* de = get_dentry_by_sb_currns(inode->i_sb);
            char *path1 = dentry_path_raw(de, buffer_mount1, 4096);
            char *path2 = NULL;
            char *path3 = NULL;
            printk("path1 = %s\n", path1);
            if (de->d_sb) {
                if (strcmp(path1, "/") != 0) {
                    de = get_dentry_by_sb_currns(de->d_sb);
                    path2 = dentry_path_raw(de, buffer_mount2, 4096);
                    printk("path2 = %s\n", path2);
                    if (de->d_sb) {
                        if (strcmp(path2, "/") != 0) {
                            de = get_dentry_by_sb_currns(de->d_sb);
                            path3 = dentry_path_raw(de, buffer_mount3, 4096);
                            printk("path3 = %s\n", path3);
                        }
                        else {
                            path2 = NULL;
                        }
                    }
                }
                else {
                    path1 = NULL;
                }
            }

            if (path2) {
                printk("dentry name = %s%s%s\n", path2, path1, path);
            }
            else if (path1) {
                printk("dentry name = %s%s\n", path1, path);
            }
            else {
                printk("dentry name = %s\n", path);
            }
        }

	}
    return 0;
}

static int __init my_module_init(void) {
    struct file *file;

    printk(KERN_INFO "Opening file: %s\n", filepath);

    // 打开文件
    file = filp_open(filepath, O_RDONLY, 0);
    printk(KERN_INFO "file[%p]\n", file);
    if (IS_ERR(file)) {
        printk(KERN_ERR "Error opening file: %ld\n", PTR_ERR(file));
        return PTR_ERR(file);
    }

    getfullpath(file->f_inode);

	// do {
    //     char *path;
    //     path = dentry_path_raw(file->f_path.dentry, buffer, PAGE_SIZE);
    //     if (IS_ERR(path)){
    //         break;
    //     }
    //     printk("[2] dentry name = %s , path = %s\n", file->f_path.dentry->d_name.name, path);
	// } while(0);

    // 关闭文件
    filp_close(file, NULL);
    return -EINVAL;
}

static void __exit my_module_exit(void) {
    printk(KERN_INFO "Module exiting\n");
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zhaoxin");
MODULE_DESCRIPTION("A simple module to read full path dentry from a file's inode");

2.3 成果展示

上面的模块代码只是为了打通演示,所以只是覆盖了两级mount的情况,我们下面展示根目录下的文件、mount过一级的目录下文件、mount过两级的目录下的文件,这三种情况:

2.3.1 根目录下的文件的情况

insmod testinode_fullpath.ko filepath=/home/aaa/zhaoxin/test.txt

运行后的dmesg的内容:

2.3.2 mount过一级的目录下的文件

insmod testinode_fullpath.ko filepath=/bigvolume/aa.txt

运行后的dmesg的内容:

2.3.3 mount过两级的目录下的文件

insmod testinode_fullpath.ko filepath=/dev/shm/aaa.txt

运行后的dmesg的内容:

三、源码解释及原理

3.1 增加的get_dentry_by_sb_currns函数的实现原理

之所以要把get_dentry_by_sb_currns函数放到fs/namespace.c里,是因为fs目录下的文件比如namespace.c文件包含了struct mount的定义,struct mount的定义是定义在fs目录下的:

该fs/mount.h属于fs下使用的一个结构体。不同于下图里的include/linux/mount.h(下图里的include/linux/mount.h是公共的mount.h,里面是没有包含struct mount的定义的):

看一下我们加的get_dentry_by_sb_currns函数的实现:

如上图红框,用的是当前任务的namespace里的mnt_ns来作为mount路径目录的namespace。

遍历该mnt_ns里的list来找匹配当前super_block的,并把mount里的mnt_mountpoint这个表示挂载位置的dentry给返回出来。

3.2 内核模块里使用get_dentry_by_sb_currns获取挂载点的路径

回到内核模块里,内核模块的代码其实是改造自之前的博客 关于inode,dentry结合软链接及硬链接的实验-CSDN博客 里的代码,在遍历查询的inode的所有dentry时,不仅通过dentry_path_raw获取到所属的super_block下的全路径之外,还获取super_block的挂载点的dentry路径,用的是get_dentry_by_sb_currns函数,如果发现挂载点的路径不是"/"的话,就继续找挂载点dentry的super_block的上一级挂载点,直到挂载点的dentry路径是"/"为止:

要注意,需要用挂载点的路径的字符串和"/"来比较,单用挂载点的d_sb的指针是不是NULL是不行的。

http://www.dtcms.com/a/113021.html

相关文章:

  • 蓝桥杯 完全平方数 刷题笔记
  • 优化 Web 性能:管理第三方资源(Third-Party Summary)
  • 数字内容体验A/B测试优化实战
  • 本地命令行启动服务并连接MySQL8
  • NLP/大模型八股专栏结构解析
  • [特殊字符] Pandas 常用操作对比:Python 运算符 vs Pandas 函数
  • JuiceFS设计框架剖析
  • 【C/C++】编译与链接过程详解
  • 最小生成树理论
  • ROM/FLASH/RAM
  • LeetCode刷题常见的Java排序
  • 安卓开发工程师-布局设计
  • 【深度学习】嘿马深度学习目标检测教程第1篇:商品目标检测要求、目标,1.1 项目演示【附代码文档】
  • 前端判断值相等的方法和区别
  • I.MX6ULL 交叉编译环境配置与使用
  • 纯免费的零基础建站教程
  • Android使用OpenGL和MediaCodec录制
  • JDK8卸载与安装教程(超详细)
  • 122.买卖股票的最佳时机 II
  • Day2:前端项目uniapp壁纸实战
  • #SVA语法滴水穿石# (013)关于内建系统函数
  • Git三剑客:工作区、暂存区、版本库深度解析
  • 王者荣耀的游戏匹配机制
  • 《UNIX网络编程卷1:套接字联网API》第6章 IO复用:select和poll函数
  • 《算法笔记》9.8小节——图算法专题->哈夫曼树 问题 C: 哈夫曼树
  • Java中与、|与||的区别详
  • 算法刷题记录——LeetCode篇(3.9) [第281~290题](持续更新)
  • Kafka 如何调优?
  • 使用MATIO库写入Matlab稀疏矩阵数据的示例程序
  • beego文件上传