IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux tracepoint 的使用 -> 正文阅读

[系统运维]Linux tracepoint 的使用

前言

本文主要是写几个内核模块来使用 tracepoint ,用的是 Linux 内核源码的的 sample 例程,由于目前内核已经不提倡手动创建tracepoint,因此将tracpoint-sample从内核sample代码中删除,于是我用的是Linux 2.6.32 内核源码下的例程。

因此目前推荐用:
TRACE_EVENT使用的是 tracepoint 机制,kernel的绝大部分tracepoint都是trace event在使用。

TRACE_EVENT(name)

而不是:

DECLARE_TRACE(name)
DEFINE_TRACE(name)

一、代码例程

我在 centos 7下测试,由于centos 7内核版本是 3.10.0 ,而例程用的是 2.6.32版本的 sample ,相应的API有一点小变动,稍加修改,如下所示:

// sample.c

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/dcache.h>
#include "samples-trace.h"

//定义 struct tracepoint _tracepoint_subsys_event 结构体
//定义跟踪点:subsys_event
DEFINE_TRACE(subsys_event);

struct proc_dir_entry *pentry_sample;

/*
 * Here the caller only guarantees locking for struct file and struct inode.
 * Locking must therefore be done in the probe to use the dentry.
 */
//跟踪点回调函数 probe1
static void probe_subsys_event_1(void *ignore, struct inode *inode, struct file *file)
{
	path_get(&file->f_path);
	dget(file->f_path.dentry);
	printk(KERN_INFO "Event is encountered with filename: %s\n", file->f_path.dentry->d_name.name);
	dput(file->f_path.dentry);
	path_put(&file->f_path);
}

/*
 * Here the caller only guarantees locking for struct file and struct inode.
 * Locking must therefore be done in the probe to use the dentry.
 */
//跟踪点回调函数 probe2
static void probe_subsys_event_2(void *ignore, struct inode *inode, struct file *file)
{
	printk(KERN_INFO "Event is encountered with inode number: %lu\n", inode->i_ino);
}

// /proc/tracepoint-sample 文件的 open操作
static int sample_open(struct inode *inode, struct file *file)
{

    printk(KERN_INFO "open /proc/tracepoint-sample file\n");

    //调用跟踪点:subsys_event
	trace_subsys_event(inode, file);

	return -EPERM;
}

static int sample_release(struct inode *inode, struct file *file)
{

    printk(KERN_INFO "release /proc/tracepoint-sample file\n");

    //调用跟踪点:subsys_event
	trace_subsys_event(inode, file);

	return -EPERM;
}

//初始化 /proc/tracepoint-sample 文件的 open操作
static const struct file_operations mark_ops = {
    .owner = THIS_MODULE,
	.open = sample_open,
    .release = sample_release,
};

static int __init sample_init(void)
{
    int ret;

	printk(KERN_ALERT "sample init\n");

    //调用 proc_create 结构在 procfs 文件系统下创建 /proc/tracepoint-sample 文件
	pentry_sample = proc_create("tracepoint-sample", 0644, NULL, &mark_ops);
	if (!pentry_sample)
		return -EPERM;

    //给跟踪点:subsys_event 注册回调函数 probe1:probe_subsys_event_1
	ret = register_trace_subsys_event(probe_subsys_event_1, NULL);
	WARN_ON(ret);

    //给跟踪点:subsys_event 注册回调函数 probe2:probe_subsys_event_2
    ret = register_trace_subsys_event(probe_subsys_event_2, NULL);
	WARN_ON(ret);

	return 0;
}

static void __exit sample_exit(void)
{
	printk(KERN_ALERT "sample exit\n");

    unregister_trace_subsys_event(probe_subsys_event_1, NULL);

    unregister_trace_subsys_event(probe_subsys_event_2, NULL);
    
	remove_proc_entry("tracepoint-sample", NULL);
}

module_init(sample_init)
module_exit(sample_exit)

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Tracepoint sample");
// samples-trace.h

#ifndef _TP_SAMPLES_TRACE_H
#define _TP_SAMPLES_TRACE_H

#include <linux/proc_fs.h>	/* for struct inode and struct file */
#include <linux/tracepoint.h>

//声明 struct tracepoint _tracepoint_subsys_event 结构体
//声明跟踪点:subsys_event
DECLARE_TRACE(subsys_event,
	//跟踪点调用的函数原型,跟踪点的probe函数也是相同的函数参数
	//将跟踪点的参数传递给probe函数,就像使用这些参数调用回调函数一样
	TP_PROTO(struct inode *inode, struct file *file),
	//跟踪点调用的函数原型中相同的参数名称
	TP_ARGS(inode, file));
#endif
// Makefile

obj-m := sample.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

cat 命令会调用 open 函数,结果显示:

[root@localhost tracepoints]# insmod sample.ko
[root@localhost tracepoints]# cat /proc/tracepoint-sample
cat: /proc/tracepoint-sample: Operation not permitted
[root@localhost tracepoints]# dmesg -c
[138944.621698] sample init
[138961.491927] open /proc/tracepoint-sample file
[138961.491936] Event is encountered with filename: tracepoint-sample
[138961.491941] Event is encountered with inode number: 4026532284
[root@localhost tracepoints]# ls -li /proc/tracepoint-sample
4026532284 -rw-r--r--. 1 root root 0 Dec 23 21:27 /proc/tracepoint-sample

执行 open 函数的时候调用 跟踪点:subsys_event,依次执行注册的两个 probe 函数。

[root@localhost tracepoints]# strace -e trace=open cat /proc/tracepoint-sample
......
open("/proc/tracepoint-sample", O_RDONLY) = -1 EPERM (Operation not permitted)
......

二、文件操作

上述例程设计到一点文件系统相关知识.

2.1 proc_create

pentry_sample = proc_create("tracepoint-sample", 0644, NULL, &mark_ops);

proc_create内核函数用来在 procfs 文件系统创建一个文件,我们不能直接手动调用 touch 在 /proc下创建文件,通用 sysfs文件系统也是如此:

[root@localhost ~]# touch /proc/my_test
touch: cannot touch ‘/proc/my_test’: Permission denied
[root@localhost ~]# touch /sys/my_test
touch: cannot touch ‘/sys/my_test’: Permission denied

这两个文件系统都只能通过相应的内核函数才能创建文件。

对于proc_create,内核中很多,比如:

static int __init proc_cpuinfo_init(void)
{
	proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
	return 0;
}
module_init(proc_cpuinfo_init);
static int __init proc_meminfo_init(void)
{
	proc_create("meminfo", 0, NULL, &meminfo_proc_fops);
	return 0;
}
module_init(proc_meminfo_init);
static int __init proc_modules_init(void)
{
	proc_create("modules", 0, NULL, &proc_modules_operations);
	return 0;
}
module_init(proc_modules_init);

proc_create函数原型:

static inline struct proc_dir_entry *proc_create(
	const char *name, umode_t mode, struct proc_dir_entry *parent,
	const struct file_operations *proc_fops)
{
	return proc_create_data(name, mode, parent, proc_fops, NULL);
}

name:文件名
mode:文件权限
parent:文件父目录
proc_fops:文件对象操作

如果 parent 等于 NULL,那就默认为:/proc

/*
 * This is the root "inode" in the /proc tree..
 */
struct proc_dir_entry proc_root = {
	.low_ino	= PROC_ROOT_INO, 
	.namelen	= 5, 
	.mode		= S_IFDIR | S_IRUGO | S_IXUGO, 
	.nlink		= 2, 
	.count		= ATOMIC_INIT(1),
	.proc_iops	= &proc_root_inode_operations, 
	.proc_fops	= &proc_root_operations,
	.parent		= &proc_root,
	.name		= "/proc",
};

2.2 struct file_operations

struct file_operations为文件操作表:

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	int (*readdir) (struct file *, void *, filldir_t);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
			  loff_t len);
	int (*show_fdinfo)(struct seq_file *m, struct file *f);
};

我们的内核模块用到的 open 函数指针:

int (*open) (struct inode *, struct file *);

将文件对象 struct file 与其相应的索引节点 struct inode 关联起来,由系统调用 open 调用。

参考资料

Linux 3.10.0

https://blog.csdn.net/jasonactions/article/details/123470620
https://blog.csdn.net/Rong_Toa/article/details/116602224
https://blog.csdn.net/Rong_Toa/article/details/108879240

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 11:43:44  更:2022-12-25 11:44:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:26:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码