Home > OS >  How to create a file with content using debugfs in kernel module?
How to create a file with content using debugfs in kernel module?

Time:01-11

With this debugfs API I can create a file in /sys/kernel/debug/parent/name, but it's empty, no matter which data I put in void *data parameter

struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, struct file_operations *fops);

According to documentation we need to implement file_operations ourself to handle file open and write. A snippet of code from mine:

static ssize_t myreader(struct file *fp, char __user *user_buffer, 
                                size_t count, loff_t *position) 
{ 
     return simple_read_from_buffer(user_buffer, count, position, ker_buf, len);
} 
 
static ssize_t mywriter(struct file *fp, const char __user *user_buffer, 
                                size_t count, loff_t *position) 
{ 
        if(count > len ) 
                return -EINVAL; 
  
        return simple_write_to_buffer(ker_buf, len, position, user_buffer, count); 
} 
 
static const struct file_operations fops_debug = { 
        .read = myreader, 
        .write = mywriter, 
}; 
 
static int __init init_debug(void) 
{ 
    dirret = debugfs_create_dir("dell", NULL); 
      
    fileret = debugfs_create_file("text", 0644, dirret, "HELLO WORLD", &fops_debug);
    debugfs_create_u64("number", 0644, dirret, &intvalue); 
 
    return (0); 
}

After installing this module to kernel, two files 'text' and 'number' will be created in the folder 'dell'. File 'number' contains the number I passed in as 'intvalue' as expected, but the other file 'text' is empty. It's written in document that data will be stored in the i_private field of the resulting inode structure My expectation: The string "HELLO WORLD" will be written in the file after module is loaded.

I think that the problem should be in the read and write operation functions. Is it possible to create a file with a particular content with the debugfs_create_file method?

CodePudding user response:

To answer your question, whatever you are expecting from your code is correct but it is not going to produce the expected result.
I believe there are other more efficient and correct ways of doing it, but to explain the current behavior:

  • You are initializing data as content of file text but you are reading from buffer ker_buf in user_buffer instead of file pointer using simple_read_from_buffer(user_buffer, count, position, ker_buf, len);
  • Similarly you are writing to kern_buf from user_buffer using simple_write_to_buffer(ker_buf, len, position, user_buffer, count);

With the existing code, if you want to achieve what you are trying to do, then you have to copy the string "HELLO WORLD" to kern_buf in init_debug()

Something like: strscpy(kern_buf, "HELLO WORLD", strlen("HELLO WORLD") 1);

static int __init init_debug(void) 
{ 
    dirret = debugfs_create_dir("dell", NULL); 
      
    fileret = debugfs_create_file("text", 0644, dirret, NULL, &fops_debug);
    debugfs_create_u64("number", 0644, dirret, &intvalue); 
    
    strscpy(kern_buf, "HELLO WORLD", strlen("HELLO WORLD") 1);
    return (0); 
}

Edit:

Referred some online materials and found out that the void *data provided to debugfs_create_file() during initialization gets stored in the i_private field and can be later retrieved from the i_private field of the resulting inode structure.

The inode of the respective file can be fetched from struct file *fp which is the first argument of read() or write() operations.

The struct inode is a member of struct file and i_private is a member of struct inode

To fetch void *data provided during file creation via debugfs_create_file() in read() you can do something similar to as shown below:

static ssize_t myreader(struct file *fp, char __user *user_buffer, 
                                size_t count, loff_t *position) 
{
    struct inode *l_inode = fp->f_inode;
    strscpy(user_buffer, (char *)l_inode->i_private, PAGE_SIZE);
    ...
    
}
  • Related