eager2learn
eager2learn

Reputation: 1488

Writing to proc file / give parameter by calling kernel module

I'm supposed to change a configuration parameter of the kernel by using a kernel module. The kernel module should create a proc file and then I should be able to change the parameter by using the cat command, e.g. cat "foobar" > /proc/prompt is supposed to set the parameter to "foobar", where prompt is the name of the proc file that was created in the module.

Furthermore I should be able to initialize the parameter by passing it as an argument when calling the module.

These two articles were basically the only relevant sources that I have found:

http://www.tldp.org/LDP/lkmpg/2.6/html/x769.html for writing to a proc file and http://www.tldp.org/LDP/lkmpg/2.6/html/x323.html for initializing the parameter from the command line.

Now I have a couple of questions, first of all this is the module thus far:

#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/proc_fs.h>

#include "sar_main.h"

#define PROCFS_NAME "sarlkm"

char procfs_buffer[PROCFS_MAX_SIZE];

static unsigned long procfs_buffer_size = 0

struct proc_dir_entry *proc_file_entry;


int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data){
    int ret;

    printk(KERN_INFO "procfile_read (/proc/%s) aufgerufen \n",  PROCFS_NAME);

    if (offset > 0){
        ret = 0;
    }
    else{
        memcpy(buffer, procfs_buffer, procfs_buffer_size);
        ret = procfs_buffer_size;
    }
    return ret;
}

int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data){

    procfs_buffer_size = count;
    if (procfs_buffer_size > PROCFS_MAX_SIZE){
        procfs_buffer_size = PROCFS_MAX_SIZE;
    }
    if ( copy_from_user(procfs_buffer, buffer, procfs_buffer)){
        return -EFAULT;
    }
    return procfs_buffer_size;
}




static int __init sar_init(void)
{
    prompt_proc = create_proc_entry(PROCFS_NAME, 0644, NULL);

    if (prompt_proc = NULL){
        remove_proc_entry(PROCFS_NAME, &proc_root);
        printk(KERN_ALERT "Error: Konnte proc file nicht kreieren")
        return -ENOMEM;
    }

    prompt_proc->read_proc = procfile_read;
    prompt_proc->write_proc = procfile_write;

    printk(KERN_INFO "proc/%s wurde erfolgreich kreiert", PROCFS_NAME);
    return 0;
}

static void __exit sar_cleanup(void)
{
    remove_proc_entry(PROCFS_NAME, &proc_root);
    printk(KERN_INFO "proc/%s gelöscht", PROCFS_NAME);
}

module_init(sar_init);
module_exit(sar_cleanup);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

I think I should say that I don't really understand why the read and write functions are supposed to work when using the cat command. My main question is where exactly is the configuration parameter stored in the proc file? If I would write "foobar" to the proc file using cat and then use cat proc/prompt to read the parameter, how does the read function actually get the new value of the parameter, i.e. where is "foobar" stored in the procfile?

If I would try to initialize the parameter using a command line argument I would have to use a global variable in which to store the value of the parameter, but then how could I use that global variable in the read function, so that cat proc/prompt actually gives out the value that was given to the module from the command line?

Upvotes: 1

Views: 4737

Answers (2)

yurenchen
yurenchen

Reputation: 2491

you can treat xxx_write or xxx_read in driver just as a interface implement,

when you call write or read in user space, the kernel will invoke xxx_write or xxx_read in kernel space.

so you need to store it yourself when write call,
and fetch them back when read call,
in xxx_write xxx_read

enter image description here

Upvotes: 1

cadaniluk
cadaniluk

Reputation: 15229

The cat command internally calls the read() system call to read data from a file (see man strace).

read() passes the arguments to the VFS and the VFS finally calls your custom procfile_read() routine with the passed arguments (and some additional ones passed by the VFS code). If you want to know more about this, look at the fs directory in kernel sources, especially file read_write.c.

Your particular reading function copies, if some conditions are met, the parameter value (which is stored in procfs_buffer to answer one of your questions) into the user-supplied buffer allocated by cat, which is called buffer in your particular code. It is the same one as passed by the read() system call like in:

read(proc_fd, userspace_buf, 10);    /* userspace_buf is buffer! */

Error checking omitted for clearness's sake.

To pass the value to the proc file you have two options:

  • Use module_param() and write it to your buffer; can only be done once because the module is only loadable once (or unload/reload it every time you want to change the parameter but that sounds inconvenient)
  • Invoke write() from userspace (like in cat) and modify the buffer as often as you want to (this is currently used by your code)

BTW, I really think your reading function should check the pointer to the user data, i.e. use copy_to_user(), not memcpy().

For further information, read Linux Device Drivers. There's only an old edition available at the moment but an updated one is being written.

Upvotes: 3

Related Questions