几个Linux 内核模块的例子

本文写几个Linux 内核模块的例子.

系列:

  1. 写一个 Linux 内核 hello world 模块
  2. 写一个有参数的 Linux 内核模块
  3. 写一个有依赖的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

标签: none

添加新评论