Search code examples
linux-kernelkernel-moduleprocfs

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 I try to make the hello kernel module from that link but ended up with this error.


Solution

  • As said in the comments from tsyvarev, in your kernel version "5.13.0-37", the prototype of proc_create() changed. You need to look at the header files of your kernel version. For example, under an Ubuntu distribution, you can find the header file in /usr/src/linux-headers-5.13.0-37-generic/include/linux/proc_fs.h:

    $ 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);
    [...]
    

    Hence, you can modify the source code of hello.c as:

    /**
     * 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");
    

    The compilation result is:

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

    The execution is:

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