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
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