几个Linux 内核模块的例子
本文写几个Linux 内核模块的例子.
系列:
打印系统进程的 kernel 模块
文件名: printthread.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/oom.h>
static int __init tprocs_init(void)
{
struct task_struct *p, *t;
pr_info("print_threads: tid, pid, command, state\n\n");
for_each_process_thread(p, t) {
pr_info("tgid=%d, thread_pid=%d, parent_pid=%d, comm=%s, state=%d\n",
t->tgid, t->pid, t->real_parent->pid, t->comm, READ_ONCE(t->__state));
}
return 0;
}
static void __exit tprocs_exit(void)
{
pr_info("print_threads has left the building...\n");
}
module_init(tprocs_init);
module_exit(tprocs_exit);
MODULE_LICENSE("GPL v2");
打印当前进程及它的子进程
文件名: list_children.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/oom.h>
void list_children(struct task_struct *parent) {
struct task_struct *child;
struct list_head *list;
// Iterate through the list of children
list_for_each(list, &parent->children) {
child = list_entry(list, struct task_struct, sibling);
// Print information about the child process
printk(KERN_INFO "Child process: %s [%d]\n", child->comm, child->pid);
}
}
static int __init pprocs_init(void)
{
struct task_struct *p;
pr_info("print_procs: pid, command, state\n\n");
for_each_process(p) {
pr_info("pid=%d, comm=%s, state=%d\n",
p->pid, p->comm, READ_ONCE(p->__state));
list_children(p);
}
return 0;
}
static void __exit pprocs_exit(void)
{
pr_info("print_procs has left the building...\n");
}
module_init(pprocs_init);
module_exit(pprocs_exit);
MODULE_LICENSE("GPL v2");
dump 某个进程的内存信息
文件名 dumpprocmm.c
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/kstrtox.h>
#include <linux/sched.h>
#include <linux/mm_types.h>
#include <linux/mm_types_task.h>
#include <linux/mm.h>
#include <linux/pid.h>
#include <linux/slab.h>
static struct proc_dir_entry *parent;
static int flag1 = 1;
static int flag2 = 1;
char buff_array[32] = "123";
char mm_array[500] = "initial value\n";
static int open_proc(struct inode *inode, struct file *file)
{
printk(KERN_ALERT "Open dump_something.....\n");
return 0;
}
static int release_proc(struct inode *inode, struct file *file)
{
printk(KERN_ALERT "Close dump_something.....\n");
return 0;
}
static ssize_t read_proc1(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
{
printk(KERN_ALERT "Read dump_something.....\n");
if (flag1)
{
flag1 = 0;
printk(KERN_ALERT "flag1 is 0 \n");
}
else
{
flag1 = 1;
printk(KERN_ALERT "flag1 is 1, now to 0, return 0 \n");
return 0;
}
if (copy_to_user(buffer, buff_array, strlen(buff_array)))
{
printk(KERN_ERR "Data Send: Err!\n");
return -EFAULT;
}
printk(KERN_ALERT "return strlen is %zu \n", strlen(buff_array));
return strlen(buff_array);
}
static ssize_t read_proc2(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
{
printk(KERN_ALERT "Read dump_something.....\n");
if (flag2)
{
flag2 = 0;
printk(KERN_ALERT "2 flag2 is 0 \n");
}
else
{
flag2 = 1;
printk(KERN_ALERT "2 flag2 is 1, return 0 \n");
return 0;
}
if (copy_to_user(buffer, mm_array, strlen(mm_array)))
{
printk(KERN_ERR "Data Send: Err!\n");
return -EFAULT;
}
printk(KERN_ALERT "2 return strlen is %zu \n", strlen(buff_array));
return strlen(mm_array);
}
static struct task_struct *get_task_struct_from_pid(const char *pid_buffer)
{
pid_t pid;
struct task_struct *task = NULL;
// Convert the PID string to an integer
if (kstrtoint(pid_buffer, 10, &pid) != 0)
{
printk(KERN_ERR "Invalid PID: %s\n", pid_buffer);
return NULL;
}
// Get the task_struct pointer from the PID
task = pid_task(find_vpid(pid), PIDTYPE_PID);
if (task == NULL)
{
printk(KERN_ERR "Process with PID %d not found\n", pid);
return NULL;
}
return task;
}
static void get_memory_information(struct mm_struct *mm, char *info_buffer)
{
unsigned long total_vm = mm->total_vm;
unsigned long anon = get_mm_counter(mm, MM_ANONPAGES);
unsigned long file = get_mm_counter(mm, MM_FILEPAGES);
unsigned long swap = get_mm_counter(mm, MM_SWAPENTS);
snprintf(info_buffer, 400, "Total virtual memory: %lu kB\nRssAnon: %lu kB\nRssFile: %lu kB\nVmSwap: %lu kB\n",
total_vm << (PAGE_SHIFT - 10), anon << (PAGE_SHIFT - 10), file << (PAGE_SHIFT - 10), swap << (PAGE_SHIFT - 10));
}
static ssize_t write_proc1(struct file *filp, const char *buffer, size_t len, loff_t *off)
{
printk(KERN_ALERT "try to write to pid file.....\n");
if (len >= sizeof(buff_array))
{
printk(KERN_ERR "Invalid PID: Length exceeds buffer size\n");
return -EINVAL;
}
if (copy_from_user(buff_array, buffer, len))
{
printk(KERN_ERR "Data Write: Err!\n");
return -EFAULT;
}
buff_array[len] = '\0';
struct task_struct *task = get_task_struct_from_pid(buff_array);
if (!task)
return -EINVAL;
struct mm_struct *mm = task->mm;
// Check if mm_struct is present
if (mm != NULL)
{
// Access memory information
unsigned long rss = get_mm_rss(mm);
// Print memory information
printk(KERN_INFO "Process memory information:\n");
printk(KERN_INFO "Resident set size (RSS): %lu\n", rss);
get_memory_information(mm, mm_array);
}
return len;
}
static ssize_t write_proc2(struct file *filp, const char *buffer, size_t len, loff_t *off)
{
printk(KERN_ALERT "try to write to dump_mm file.....\n");
return 0;
}
static const struct proc_ops proc_fops1 = {
.proc_open = open_proc,
.proc_read = read_proc1,
.proc_write = write_proc1,
.proc_release = release_proc,
};
static const struct proc_ops proc_fops2 = {
.proc_open = open_proc,
.proc_read = read_proc2,
.proc_write = write_proc2,
.proc_release = release_proc,
};
static int __init hello_init(void)
{
printk(KERN_ALERT "Hello !\n");
/* Create proc directory under /proc */
parent = proc_mkdir("dumpprocmm", NULL);
if (NULL == parent)
{
printk(KERN_ERR "Failed creating proc entry dumpprocmm");
return -ENOMEM;
}
/* Create proc file under /proc/dumpprocmm */
proc_create("pid", 0666, parent, &proc_fops1);
proc_create("dump_mm", 0666, parent, &proc_fops2);
return 0;
}
static void __exit hello_exit(void)
{
proc_remove(parent);
printk(KERN_ALERT "Goodbye !\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIPTION("dump process memory");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Eric Tian");
执行
$ make all
$ sudo insmod dumpprocmm.ko
$ echo "755" > /proc/dumpprocmm/pid
$ cat /proc/dumpprocmm/pid
$ cat /proc/dumpprocmm/dump_mm