Linux proc内核hello world程序

Linux Proc kernel hello world program

    make -C /lib/modules/5.13.0-37-generic/build M=/home/a1085551/osc10e/ch2 modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-37-generic'
  CC [M]  /home/a1085551/osc10e/ch2/hello.o
/home/a1085551/osc10e/ch2/hello.c: In function ‘proc_init’:
/home/a1085551/osc10e/ch2/hello.c:42:41: error: passing argument 4 of ‘proc_create’ from incompatible pointer type [-Werror=incompatible-pointer-types]
   42 |         proc_create(PROC_NAME, 0, NULL, &proc_ops);
      |                                         ^~~~~~~~~
      |                                         |
      |                                         struct file_operations *
In file included from /home/a1085551/osc10e/ch2/hello.c:16:
./include/linux/proc_fs.h:110:24: note: expected ‘const struct proc_ops *’ but argument is of type ‘struct file_operations *’
  110 | struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops);
      |                        ^~~~~~~~~~~
/home/a1085551/osc10e/ch2/hello.c: In function ‘proc_read’:
/home/a1085551/osc10e/ch2/hello.c:89:9: warning: ignoring return value of ‘copy_to_user’, declared with attribute warn_unused_result [-Wunused-result]
   89 |         copy_to_user(usr_buf, buffer, rv);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:281: /home/a1085551/osc10e/ch2/hello.o] Error 1
make[1]: *** [Makefile:1879: /home/a1085551/osc10e/ch2] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-37-generic'
make: *** [Makefile:3: all] Error 2

https://github.com/greggagne/osc10e/tree/master/ch2 我尝试从那个 link 制作 hello 内核模块,但最终出现了这个错误。

tsyvarev的评论所述,在您的内核版本“5.13.0-37”中,proc_create()的原型发生了变化。您需要查看内核版本的头文件。例如,在 Ubuntu 分布下,您可以在 /usr/src/linux-headers-5.13.0-37-generic/include/linux/proc_fs.h:[=16 中找到头文件=]

$ cat /usr/src/linux-headers-5.13.0-37-generic/include/linux/proc_fs.h
[...]
struct proc_ops {
    unsigned int proc_flags;
    int (*proc_open)(struct inode *, struct file *);
    ssize_t (*proc_read)(struct file *, char __user *, size_t, loff_t *);
    ssize_t (*proc_read_iter)(struct kiocb *, struct iov_iter *);
    ssize_t (*proc_write)(struct file *, const char __user *, size_t, loff_t *);
    /* mandatory unless nonseekable_open() or equivalent is used */
    loff_t  (*proc_lseek)(struct file *, loff_t, int);
    int (*proc_release)(struct inode *, struct file *);
    __poll_t (*proc_poll)(struct file *, struct poll_table_struct *);
    long    (*proc_ioctl)(struct file *, unsigned int, unsigned long);
#ifdef CONFIG_COMPAT
    long    (*proc_compat_ioctl)(struct file *, unsigned int, unsigned long);
#endif
    int (*proc_mmap)(struct file *, struct vm_area_struct *);
    unsigned long (*proc_get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
} __randomize_layout;
[...]
struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops);
[...]

因此,您可以将hello.c的源码修改为:

/**
 * hello.c
 *
 * Kernel module that communicates with /proc file system.
 * 
 * The makefile must be modified to compile this program.
 * Change the line "simple.o" to "hello.o"
 *
 * Operating System Concepts - 10th Edition
 * Copyright John Wiley & Sons - 2018
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

#define BUFFER_SIZE 128

#define PROC_NAME "hello"
#define MESSAGE "Hello World\n"

/**
 * Function prototypes
 */
static ssize_t proc_read(struct file *file, char *buf, size_t count, loff_t *pos);

static struct proc_ops proc_ops = {
        .proc_read = proc_read,
};


/* This function is called when the module is loaded. */
static int proc_init(void)
{

        // creates the /proc/hello entry
        // the following function call is a wrapper for
        // proc_create_data() passing NULL as the last argument
        proc_create(PROC_NAME, 0, NULL, &proc_ops);

        printk(KERN_INFO "/proc/%s created\n", PROC_NAME);

    return 0;
}

/* This function is called when the module is removed. */
static void proc_exit(void) {

        // removes the /proc/hello entry
        remove_proc_entry(PROC_NAME, NULL);

        printk( KERN_INFO "/proc/%s removed\n", PROC_NAME);
}

/**
 * This function is called each time the /proc/hello is read.
 * 
 * This function is called repeatedly until it returns 0, so
 * there must be logic that ensures it ultimately returns 0
 * once it has collected the data that is to go into the 
 * corresponding /proc file.
 *
 * params:
 *
 * file:
 * buf: buffer in user space
 * count:
 * pos:
 */
static ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos)
{
        int rv = 0;
        char buffer[BUFFER_SIZE];
        static int completed = 0;

        if (completed) {
                completed = 0;
                return 0;
        }

        completed = 1;

        rv = sprintf(buffer, "Hello World\n");

        // copies the contents of buffer to userspace usr_buf
        copy_to_user(usr_buf, buffer, rv);

        return rv;
}


/* Macros for registering module entry and exit points. */
module_init( proc_init );
module_exit( proc_exit );

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hello Module");
MODULE_AUTHOR("SGG");

编译结果为:

$ make
make -C /lib/modules/5.13.0-37-generic/build M=... modules
make[1]: Entering directory '/usr/src/linux-headers-5.13.0-37-generic'
  LD [M]  /.../hello.ko
  BTF [M] /.../hello.ko
Skipping BTF generation for /.../hello.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.13.0-37-generic'

执行是:​​

$ sudo insmod hello.ko
$ lsmod | grep hello
hello                  16384  0
$ cat /proc/hello
Hello World