• deepin-anything 源码刨析


    前言:

    deepin-anything:最初是为了满足快速索引文件列表。
    kprobe:内核探针,可在内核调用函数前,埋点执行自定义逻辑。
    pt_args:内核探针注册接口参数2,用于获取映射的寄存器值结构体。

    内核侧模块 vfs_monitor

    文件列表项:

    ├── arg_extractor.c 		对应架构 pt_args 结构参数获取接口文件
    ├── arg_extractor.h
    ├── event.c					缓存VFS事件操作接口文件
    ├── event.h
    ├── event_merge.c			VFS事件合并操作接口,屏蔽原生linux Event对最终结果影响,del(X) + new(X) => remove del(X)
    ├── event_merge.h
    ├── Makefile
    ├── module.c				内核模块入口
    ├── vfs_change_consts.h		文件actions映射枚举
    ├── vfs_fsnotify.c			vfs文件变动逻辑处理主文件
    ├── vfs_fsnotify.h
    ├── vfs_genl.c				vfs_evnet入口操作文件
    ├── vfs_genl.h
    ├── vfs_kgenl.h
    ├── vfs_kretprobes.c		kprobe操作文件
    └── vfs_kretprobes.h		
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    module.c

        vfs_changed_func = vfs_notify_dentry_event;	//来自 vfs_genl.c 文件变动事件操作入口
        ret = init_vfs_genl();
        if (ret)
            goto init_vfs_genl_fail;
    
    #ifdef CONFIG_FSNOTIFY_BROADCAST
        ret = init_vfs_fsnotify(get_event_merge_entry(vfs_changed_func)); // 重定向vfs_notify_dentry_event函数指针
        if (ret)
            goto init_event_source_fail;
    #else
        ret = init_vfs_kretprobes(get_event_merge_entry(vfs_changed_func)); // 重定向vfs_notify_dentry_event函数指针
        if (ret)
            goto init_event_source_fail;
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • get_event_merge_entry 获取事件合并入口函数,来自 vfs_kretprobes.c
    void *get_event_merge_entry(void *vfs_changed_func)
    {
        vfs_changed_entry = vfs_changed_func;
    
        return do_event_merge;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • init_vfs_fsnotify
    static struct kretprobe *vfs_krps[] = {&do_mount_krp, &sys_umount_krp, &vfs_create_krp,
        &vfs_unlink_krp, &vfs_mkdir_krp, &vfs_rmdir_krp, &vfs_symlink_krp, &vfs_link_krp,
        &vfs_rename_krp, &security_inode_create_krp
    }; //所有的kprobe结构
    
    int init_vfs_kretprobes(void *vfs_changed_func)
    {
        int ret;
    
        ret = init_mnt_ns();
        if (ret)
            return ret;
    
        vfs_changed_entry = vfs_changed_func;
    
        ret = register_kretprobes(vfs_krps, sizeof(vfs_krps) / sizeof(void *)); // 注册kprobe流程
        if (ret < 0) {
            mpr_info("register_kretprobes failed, returned %d\n", ret);
            return ret;
        }
        mpr_info("register_kretprobes %ld ok\n", sizeof(vfs_krps) / sizeof(void *));
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • kprobe结构,来自 vfs_kretprobes.h
    #define _DECL_CMN_KRP(fn, symbol) static struct kretprobe fn##_krp = {\
            .entry_handler  = on_##fn##_ent,\
            .handler        = on_##fn##_ret,\
            .data_size      = sizeof(struct fn##_args),\
            .maxactive      = 64,\
            .kp.symbol_name = ""#symbol"",\
        };
    
    #define DECL_CMN_KRP(fn) _DECL_CMN_KRP(fn, fn)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    该部分定义 kprobe 结构体应用于注册探针。即do_mount_krp 埋点 path_mount 如下:

    #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
    DECL_CMN_KRP(do_mount);
    #else
    _DECL_CMN_KRP(do_mount, path_mount); // do_mount_krp 埋点 函数为  path_mount
    #endif
    
    #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
    DECL_CMN_KRP(sys_umount);
    #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) // 内核版本标识
    _DECL_CMN_KRP(sys_umount, ksys_umount); // sys_umount_krp 埋点函数为 ksys_umount
    #else
    _DECL_CMN_KRP(sys_umount, path_umount);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    该部分定义kprobe的函数入口与kprobe操作函数

    #define DECL_VFS_KRP(fn, act, de_i) static int on_##fn##_ent(struct kretprobe_instance *ri, struct pt_regs *regs)\
        {\
            return common_vfs_ent((struct vfs_event **)&(ri->data), (struct dentry *)get_arg(regs, de_i));\
        }\
        \
        static int on_##fn##_ret(struct kretprobe_instance *ri, struct pt_regs *regs)\
        {\
            return common_vfs_ret((struct vfs_event **)&(ri->data), regs, act);\
        }\
        \
        static struct kretprobe fn##_krp = {\
            .entry_handler  = on_##fn##_ent,\
            .handler        = on_##fn##_ret,\
            .data_size      = sizeof(struct vfs_event *),\
            .maxactive      = 64,\
            .kp.symbol_name = ""#fn"",\
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    宏调用如下

    DECL_VFS_KRP(vfs_create, ACT_NEW_FILE, 3); // 参数1为埋点符号,参数2文件操作,参数3获取参数寄存器 return regs->dx;
    DECL_VFS_KRP(vfs_unlink, ACT_DEL_FILE, 3);
    DECL_VFS_KRP(vfs_mkdir, ACT_NEW_FOLDER, 3);
    DECL_VFS_KRP(vfs_rmdir, ACT_DEL_FOLDER, 3);
    DECL_VFS_KRP(vfs_symlink, ACT_NEW_SYMLINK, 3);
    DECL_VFS_KRP(security_inode_create, ACT_NEW_FILE, 2); // return regs->si;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    vfs_changed_entry 函数绑定到 do_event_merge,init_vfs_kretprobes函数中:

    vfs_changed_entry = vfs_changed_func;
    
    • 1
  • 相关阅读:
    地雷数量求解
    推荐一个日历转换开源工具库,支持C#、Java、PHP等主流的语言
    浅谈:在ZK-rollup和以太坊上的帐户抽象
    分布式调度 Elastic-job
    visio将形状、图形、文字、符合进行任意角度旋转(已解决)
    Asp .Net Core 系列:基于 Castle DynamicProxy + Autofac 实践 AOP 以及实现事务、用户填充功能
    递归为什么这么难?一篇文章带你了解递归
    RK3588移植-opencv交叉编译aarch64
    数字孪生可视化平台多少钱?费用有哪些首选广州华锐互动
    聊聊Spring中循环依赖与三级缓存
  • 原文地址:https://blog.csdn.net/qq_24423085/article/details/133140141