copy_to_user not working in kernel module - linux

I was trying to use copy_to_user in kernel module read function, but am not able to copy the data from kernel to user buffer. Please can anyone tell me if I am doing some mistake. My kernel version is 2.6.35. I am giving the portion of kernel module as well as the application being used to test it. Right now my focus is why this copy_to_user is not working. Any help will great.
///////////////////////////////////kernel module//////////////////////////////////////
#define BUF_LEN 80
static char msg[BUF_LEN];
static char *msg_Ptr;
static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
printk(KERN_ALERT "In open device call\n");
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static ssize_t device_read(struct file *filp,
char __user *buffer,
size_t length,
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
/*
* If we are at the end of the message,
* return 0 signifying end of file
*/
if (*msg_Ptr == 0)
return 0;
/*
* Actually put the data into the buffer
*/
else {
bytes_read=copy_to_user(buffer, msg, length);
if (bytes_read==-1);
{
printk(KERN_INFO "Error in else while copying the data \n");
}
}
return bytes_read;
}
////////////////////////////////////////application////////////////////////
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define BUF_SIZE 40
int main()
{
ssize_t num_bytes;
int fd, n=0;
char buf[BUF_SIZE];
fd=open("/dev/chardev", O_RDWR);
if(fd== -1){perror("Error while opening device");exit(1);}
printf("fd=%d\n",fd);
num_bytes=read(fd, buf, BUF_SIZE);
if(num_bytes==-1){perror("Error while reading"); exit(2);}
printf("The value fetched is %lu bytes\n", num_bytes);
while(n<=num_bytes)
{
printf("%c",buf[n]);
n++;
}
close(fd);
return 0;
}

There are a few problems in the code snippet you wrote. First of all, it is not a good thing to make the call try_module_get(THIS_MODULE);
This statement tries to increase the refcount of the module ... in the module itself ! Instead, you should set the owner field of the file_ops structure to THIS_MODULE in your init method. This way, the reference handling will happen outside the module code, in the VFS layer. You might take a look at Linux Kernel Modules: When to use try_module_get / module_put.
Then, as it was stated by Vineet you should retrieve the pointer from the file_ops private_data field.
And last but not least, here is the reason why it seems an error happened while ... Actually ... It did not :
The copy_to_user call returns 0 if it has successfully copied all the desired bytes into the destination memory area and a strictly positive value stating the number of bytes that were NOT copied in case of error. That said, when you run :
/* Kernel part */
bytes_read=copy_to_user(buffer, msg, length);
/*
* Wrong error checking :
* In the below statement, "-1" is viewed as an unsigned long.
* With a simple equality test, this will not bother you
* But this is dangerous with other comparisons like "<" or ">"
* (unsigned long)(-1) is at least 2^32 - 1 so ...
*/
if (-1 == bytes_read) {
/* etc. */
}
return bytes_read;
/* App part */
num_bytes=read(fd, buf, BUF_SIZE);
/* etc.. */
while(n<=num_bytes) {
printf("%c",buf[n]);
n++;
}
You should only get one character upon a successful copy, that is only a single "I" in your case.
Moreover, you use your msg_Ptr pointer as a safeguard but you never update it. This might result in a wrong call to copy_to_user.
copy_to_user checks the user-space pointer with a call to access_ok, but if the kernel-space pointer and the given length are not allright, this might end in a Kernel Oops/Panic.

I think you should update the file->private_data in open and then you have to fetch that in your structure. Because I guess the msg buffer ( kernel buffer ) is not getting proper refernce.

Related

Memory Leak. FInding line number

So this is a homework project first and foremost. My whole program is working, it was an intermediate/advancedintro project to deal with dynamic memory allocation. I can't figure out how to display the line numbers with the normal output. I've attempted to look at the other questions on stack about this topic but I cannot seem to figure out a reason that helps me. Any suggestions to how to make the line number appear?
Here is my "LeakWatcher.cpp"
#ifndef IMWATCHINGYOULEAK
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{ return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); }
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard
And my main()
int main()
{
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
try
{
Directory().Run();
}
catch ( ... )
{
cout << "Uncaught Exception" << endl;
}
_CrtDumpMemoryLeaks();
return 0;
}
Something that did occur to me based on your code is this. You say you placed all the debug macros into LeakWatcher.cpp and not LeakWatcher.h . I suspect this is your issue.
Create LeakWatcher.h with everything you currently have in your LeakWatcher.cpp. You don't need LeakWatcher.cpp so you should be able to remove it. Now use #include "LeakWatcher.h" at the top of all of your .cpp files. So it would look something like the following.
File LeakWatcher.h
#ifndef IMWATCHINGYOULEAK
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{ return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); }
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard
Then in a file like test.cpp you can do this (similar to your test code):
#include "LeakWatcher.h"
int main()
{
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
new int[40]; // This should be a memory leak
_CrtDumpMemoryLeaks(); // This should dump with line numbers and file names
return 0;
}
Of course this will only work if you are building debug versions of your project.
To get some other insights into overriding these heap routines, I found this MSDN Article valuable.
I presume you're asking about the actual algorithm of keeping track of memory that's been allocated but not released.
The typical approach of keeping track of where your memory allocation requests came from, for the purposes of producing diagnostic output is as follows:
Say you want to track the caller requested n_bytes worth of memory.
Allocate n_bytes+sizeof(const char *)+sizeof(int).
Store FILE and LINE in the first part of the allocated memory, and return the rest of the allocated memory as supposedly what's been allocated.
Something like this:
struct hdr {
const char *file;
int line;
};
void *my_allocation_request(const char *file, int line, size_t nbytes)
{
struct hdr *p=(struct hdr *)malloc(nbytes+sizeof(hdr));
p->file=file;
p->line=line;
// Here be dragons
return (void *)(p+1);
}
(presumably, your new operator gets punted here).
Similar, when something wants to deallocate a memory block
void my_deallocation_request(char *p)
{
struct hdr *h=reinterpret_cast<hdr *>(p+1);
// Here be dragons
free(h);
}
Before this can be a final solution, you'll also need to write a bit more code that goes into the "Here be dragons" part, and I think you could probably figure it out yourself:
A) Take each newly allocated memory and put it on a list of some kind (the first location of dragons).
B) Remove the allocated memory from a list of some kind (the second location of dragons).
Then, at the end of your program, you can go through anything that's left on the list. That's going to be your leaked memory, and you'll have the file and the line number where it was allocated from.
Note that you'll probably want to implement the linked list of unreleased memory blocks manually. Using some standard container will probably result in an infinite loop, due to container's very reasonable expectation of being able to allocate memory for its own use, which will loop back into your own new/delete intercepts, which will ask the container to allocate more memory, which will loop back into your own new/delete intercepts, etc...
There might be some implementation-specific issues here regarding alignment of allocated memory, but it's unlikely, and this hair-splitting can probably be ignored, for now.

Please help me to make this fake character linux device driver work

Hello I am trying to write to a fake char device driver using:
echo > /dev/
and reading it using:
cat /dev/
My problem is that I am getting continuously the first character written printed on the terminal when I do a read with the above mentioned "cat" read method after writing using the echo method above.
My aim is to get the entire set of characters written to the driver back...
I am using dynamic memory allocation for this purpose but not getting the final result after trying many ways of rewriting the code of read() and write() in the driver. Please help..
my Makefile is correct... (I am using ubuntu with a kernel version of 2.6.33...)
My code is as below:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
static dev_t first;
static struct cdev c_dev;
static struct class *cl;
static char* k_buf = NULL;
static int my_open(struct inode *i,struct file *f)
{
printk(KERN_INFO "In driver open()\n");
return 0;
}
static int my_close(struct inode *i,struct file *f)
{
printk(KERN_INFO "In driver close()\n");
return 0;
}
static ssize_t my_read(struct file *f,char __user *buf,size_t len,loff_t *off)
{
printk(KERN_INFO "In driver read()\n");
if(k_buf == NULL)
{
printk(KERN_INFO "You cannot read before writing!\n");
return -1;
}
while(*k_buf != 'EOF')
{
if(copy_to_user(buf,k_buf,1))
return -EFAULT;
off++;
return 1;
}
return 0;
}
static ssize_t my_write(struct file *f,const char __user *buf,size_t len,loff_t *off)
{
printk(KERN_INFO "In driver write()\n");
k_buf = (char*) kmalloc(sizeof(len),GFP_KERNEL);
if(copy_from_user(k_buf,buf,len))
return -EFAULT;
off += len;
return (len);
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
.read = my_read,
.write = my_write
};
static int __init rw_init(void) /*Constructor*/
{
printk(KERN_INFO "hello: rw_ch_driver registered\n");
if(alloc_chrdev_region(&first,0,1,"krishna") < 0)
{
return -1;
}
if ((cl = class_create(THIS_MODULE,"chardev")) == NULL)
{
unregister_chrdev_region(first,1);
return -1;
}
if (device_create(cl,NULL,first,NULL,"rw_char_driver") == NULL)
{
class_destroy(cl);
unregister_chrdev_region(first,1);
return -1;
}
cdev_init(&c_dev,&fops);
if(cdev_add(&c_dev,first,1) == -1)
{
device_destroy(cl,first);
class_destroy(cl);
unregister_chrdev_region(first,1);
return -1;
}
return 0;
}
static void __exit rw_exit(void)/*destructor*/
{
cdev_del(&c_dev);
device_destroy(cl,first);
class_destroy(cl);
unregister_chrdev_region(first,1);
printk(KERN_INFO "bye rw_chardriver unregistered");
}
module_init(rw_init);
module_exit(rw_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("krishna");
MODULE_DESCRIPTION("read write character driver");
Take a careful look at your while loop in my_read().
Most important note first: you don't need this loop. You've put a return statement in it, so it is never going to execute more than once, because the whole function is going to exit when the return is reached. It looks like you're trying to make the function return a single byte at a time repeatedly, but you should just call copy_to_user once, and pass it the number of bytes you want to give back to the user instead. If you only send one character at a time that's fine. It will be up to the user to make the read call again to get the next character.
The nice thing about copy_to_user, is that its return code will tell you if it failed because of bad array bounds, so there's no need to check for EOF on every character. In fact, you are not going to get 'EOF' as a character when you are reading from your buffer because it doesn't exist. Your buffer will store characters and usually a null terminator, '\0', but there is no 'EOF' character in C. EOF is a state you need to identify yourself and report to whoever called open. For the "cat" command, this is done by returning 0 from read. That being said, you should still check your array bounds so we don't end up with another Heartbleed. This SO answer has a good suggestion for how to do bounds checking to make sure you don't send more bytes than your buffer has.
Also, give [this post(https://meta.stackexchange.com/questions/981/syntax-highlighting-language-hints) a read. If you don't have your language in your question tags, it is helpful to other readers to tag your. I've edited your question to clean it up, so you can click "edit" now to see how I did it.

kernel driver reading ok from user space, but writing back is always 0

So I'm working my way through kernel driver programming, and currently I'm trying to build a simple data transfer between application and kernel driver.
I am using simple character device as a link between these two, and I have succeeded to transfer data to driver, but I can't get meaningful data back to user space.
Kernel driver looks like this:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("GPL");
//Declarations
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
//Default functions
module_init(memory_init);
module_exit(memory_exit);
/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char* tx_buffer;
char* rx_buffer;
int BUFFER_SIZE=64;
int actual_rx_size=0;
int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "move_data", &memory_fops);
if (result < 0) {
printk(
"<1>move_data: cannot obtain major number %d\n", memory_major);
return result;
}
/* Allocating memory for the buffers */
//Allocate buffers
tx_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
rx_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
//Check allocation was ok
if (!tx_buffer || !rx_buffer) {
result = -ENOMEM;
goto fail;
}
//Reset the buffers
memset(tx_buffer,0, BUFFER_SIZE);
memset(rx_buffer,0, BUFFER_SIZE);
printk("<1>Inserting memory module\n");
return 0;
fail:
memory_exit();
return result;
}
void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "memory");
/* Freeing buffers */
if (tx_buffer) {
kfree(tx_buffer); //Note kfree
}
if (rx_buffer) {
kfree(rx_buffer); //Note kfree
}
printk("<1>Removing memory module\n");
}
//Read function
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
printk("user requesting data, our buffer has (%d) \n", actual_rx_size);
/* Transfering data to user space */
int retval = copy_to_user(buf,rx_buffer,actual_rx_size);
printk("copy_to_user returned (%d)", retval);
return retval;
}
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
//zero the input buffer
memset(tx_buffer,0,BUFFER_SIZE);
memset(rx_buffer,0,BUFFER_SIZE);
printk("New message from userspace - count:%d\n",count);
int retval = copy_from_user(tx_buffer,buf,count);
printk("copy_from_user returned (%d) we read [%s]\n",retval , tx_buffer);
printk("initialize rx buffer..\n");
memcpy(rx_buffer,tx_buffer, count);
printk("content of rx buffer [%s]\n", rx_buffer);
actual_rx_size = count;
return count; //inform that we read all (fixme?)
}
//Always successfull
int memory_open(struct inode *inode, struct file *filp) { return 0; }
int memory_release(struct inode *inode, struct file *filp) { return 0; }
And the userspace application is simple as well:
#include <unistd.h> //open, close | always first, defines compliance
#include <fcntl.h> //O_RDONLY
#include <stdio.h>
#include <stdlib.h> //printf
#include <string.h>
int main(int args, char *argv[])
{
int BUFFER_SIZE = 20;
char internal_buf[BUFFER_SIZE];
int to_read = 0;
memset(internal_buf,0,BUFFER_SIZE);
if (args < 3) {
printf("2 Input arguments needed\nTo read 10 bytes: \"%s read 10\" \
\nTo write string \"hello\": \"%s write hello\"\nExiting..\n", argv[0], argv[0]);
return 1;
}
//Check the operation
if (strcmp(argv[1],"write") == 0) {
printf("input lenght:%d", strlen(argv[2]));
//Make sure our write fits to the internal buffer
if(strlen(argv[2]) >= BUFFER_SIZE) {
printf("too long input string, max buffer[%d]\nExiting..", BUFFER_SIZE);
return 2;
}
printf("write op\n");
memcpy(internal_buf,argv[2], strlen(argv[2]));
printf("Writing [%s]\n", internal_buf);
FILE * filepointer;
filepointer = fopen("/dev/move_data", "w");
fwrite(internal_buf, sizeof(char) , strlen(argv[2]), filepointer);
fclose(filepointer);
} else if (strcmp(argv[1],"read") == 0) {
printf("read op\n");
to_read = atoi(argv[2]);
FILE * filepointer;
filepointer = fopen("/dev/move_data", "r");
int retval = fread(internal_buf, sizeof(char) , to_read, filepointer);
fclose(filepointer);
printf("Read %d bytes from driver string[%s]\n", retval, internal_buf);
} else {
printf("first argument has to be 'read' or 'write'\nExiting..\n");
return 1;
}
return 0;
}
When I execute my application, this is what happens:
./rw write "testing testing"
kernel side:
[ 2696.607586] New message from userspace - count:15
[ 2696.607591] copy_from_user returned (0) we read [testing testing]
[ 2696.607593] initialize rx buffer..
[ 2696.607594] content of rx buffer [testing testing]
So all look correct. But when I try to read:
./rw read 15
read op
Read 0 bytes from driver string[]
Kernel
[ 617.096521] user requesting data, our buffer has (15)
[ 575.797668] copy_to_user returned (0)
[ 617.096528] copy_to_user returned (0)
I guess it's quite simple what I'm doing wrong, since if I don't return 0, I can get some data back, but for example if I read with cat, it will continue looping endlessly.
I would like to understand what mistakes I have made in my thinking.
Is there a way that kernel driver would just spit out it's buffer, and then return 0, so that I wouldn't have to build some protocol there in between to take care of how much data has been read etc.
Thanks for your suggestions!
Edit: corrected the printk statement in memory_write function, and added memory_read function trace
Your read function always returns 0 because you are returning retval, and not the count of bytes read. As long as the copy_to_user() call always succeeds, retval will always be 0. Instead, as long as copy_to_user() succeeds, you should return the number of bytes actually written to user space. This documentation states that copy_to_user() returns the total number of bytes that it was unable to copy.
As an aside, you are ignoring the value of count. It is very possible that the user is requesting less data than you have available in your buffer. You should never ignore count.
Now you have the problem where your function never returns a 0. Returning a 0 is important because is tells the user application that there is no more data available for reading and the user application should close the device file.
You need to keep track in your driver how many bytes have been read vs. how many bytes have been written. This may be implemented using your actual_rx_size.
Try this:
//Read function
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) {
ssize_t bytes;
if (actual_rx_size < count)
bytes = actual_rx_size;
else
bytes = count;
printk("user requesting data, our buffer has (%d) \n", actual_rx_size);
/* Check to see if there is data to transfer */
if (bytes == 0)
return 0;
/* Transfering data to user space */
int retval = copy_to_user(buf,rx_buffer,bytes);
if (retval) {
printk("copy_to_user() could not copy %d bytes.\n", retval);
return -EFAULT;
} else {
printk("copy_to_user() succeeded!\n");
actual_rx_size -= bytes;
return bytes;
}
}

Why doesn't this call to `poll` block correctly on a sysfs device attribute file?

I have a simple sysfs device attribute which shows up under my sysfs directory, and on a call to read returns the value of a kernelspace variable. I want to call poll on this attribute to allow my userspace thread to block until the value shown by the attribute changes.
My problem is that poll doesn't seem to block on my attribute -- it keeps returning POLLPRI even though the value shown by the attribute does not change. In fact, I have no calls at all to sysfs_notify in the kernel module, yet the userspace call poll still does not block.
Perhaps I should be checking for a return value of something other than POLLPRI -- but according to the documentation in the Linux kernel, sysfs_poll should return POLLERR|POLLPRI:
/* ... When the content changes (assuming the
* manager for the kobject supports notification), poll will
* return POLLERR|POLLPRI ...
*/
Is there something I'm forgetting to do with poll?
The device attribute is located at: /sys/class/vilhelm/foo/blah.
I load a kernel module called foo which registers a device, and creates a class and this device attribute.
The userspace application called bar spawns a thread that calls poll on the device attribute, checking for POLLPRI.
If poll returns a positive number, POLLPRI has been returned.
Use fopen and fscan to read the value from the device attribute file.
If the value is 42, print FROM THREAD!!!.
The problem is that the message is printed nonstop when I'm expecting the call to poll to block indefinitely. The problem must lie with poll (the other calls successfully acquire the correct value of 42 from the device attribute).
userspace app - bar.c:
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <unistd.h>
static void handle_val(unsigned val, FILE *fp);
void * start_val_service(void *arg);
int main(void){
pthread_t val_serv;
pthread_create(&val_serv, NULL, &start_val_service, NULL);
pthread_exit(NULL);
return 0;
}
static void handle_val(unsigned val, FILE *fp){
switch(val){
case 42:
{
printf("FROM THREAD!!!\n");
break;
}
default:
break;
}
}
void * start_val_service(void *arg){
struct pollfd fds;
fds.fd = open("/sys/class/vilhelm/foo/blah", O_RDONLY);
fds.events = POLLPRI;
do{
int ret = poll(&fds, 1, -1);
if(ret > 0){
FILE *fp = fopen("/sys/class/vilhelm/foo/blah", "r");
unsigned val;
fscanf(fp, "%u", &val);
handle_val(val, fp);
fclose(fp);
}
}while(1);
close(fds.fd);
pthread_exit(NULL);
}
kernel module - foo.c:
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kernel.h>
static dev_t foo_dev;
static struct class *vilhelm;
static unsigned myvar = 42;
static ssize_t unsigned_dev_attr_show(struct device *dev, struct device_attribute *attr, char *buf);
struct unsigned_device_attribute{
struct device_attribute dev_attr;
unsigned *ptr;
};
static struct unsigned_device_attribute unsigned_dev_attr_blah = {
.dev_attr = __ATTR(blah, S_IRUGO, unsigned_dev_attr_show, NULL)
};
static int __init foo_init(void){
int retval = 0;
printk(KERN_INFO "HELLO FROM MODULE 1");
if(alloc_chrdev_region(&foo_dev, 0, 1, "vilhelm") < 0){
printk(KERN_ERR "foo: unable to register device");
retval = -1;
goto out_alloc_chrdev_region;
}
vilhelm = class_create(THIS_MODULE, "vilhelm");
if(IS_ERR(vilhelm)){
printk(KERN_ERR "foo: unable to create device class");
retval = PTR_ERR(vilhelm);
goto out_class_create;
}
struct device *foo_device = device_create(vilhelm, NULL, foo_dev, NULL, "foo");
if(IS_ERR(foo_device)){
printk(KERN_ERR "foo: unable to create device file");
retval = PTR_ERR(foo_device);
goto out_device_create;
}
unsigned_dev_attr_blah.ptr = &myvar;
retval = device_create_file(foo_device, &unsigned_dev_attr_blah.dev_attr);
if(retval){
printk(KERN_ERR "foo: unable to create device attribute files");
goto out_create_foo_dev_attr_files;
}
return 0;
out_create_foo_dev_attr_files:
device_destroy(vilhelm, foo_dev);
out_device_create:
class_destroy(vilhelm);
out_class_create:
unregister_chrdev_region(foo_dev, 1);
out_alloc_chrdev_region:
return retval;
}
static void __exit foo_exit(void){
printk(KERN_INFO "BYE FROM MODULE 1");
device_destroy(vilhelm, foo_dev);
class_destroy(vilhelm);
unregister_chrdev_region(foo_dev, 1);
}
static ssize_t unsigned_dev_attr_show(struct device *dev, struct device_attribute *attr, char *buf){
struct unsigned_device_attribute *tmp = container_of(attr, struct unsigned_device_attribute, dev_attr);
unsigned value = *(tmp->ptr);
return scnprintf(buf, PAGE_SIZE, "%u\n", value);
}
module_init(foo_init);
module_exit(foo_exit);
MODULE_LICENSE("GPL");
See also
Using the Linux sysfs_notify call
To quote some more from the comment you quoted:
Once poll/select indicates that the value has changed, you
need to close and re-open the file, or seek to 0 and read again.
But you do nothing with fds.fd.
Also, do a dummy read() before calling poll();
any newly opened file is considered changed.

How do I use ioctl() to manipulate my kernel module?

So I'm trying to write a kernel module that uses the linux/timer.h file. I got it to work inside just the module, and now I am trying to get it to work from a user program.
Here is my kernel module:
//Necessary Includes For Device Drivers.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/ioctl.h>
#define DEVICE_NAME "mytimer"
#define DEVICE_FILE_NAME "mytimer"
#define MAJOR_NUM 61
#define MINOR_NUM 0
MODULE_LICENSE("Dual BSD/GPL");
static struct timer_list my_timer;
struct file_operations FileOps =
{
//No File Operations for this timer.
};
//Function to perform when timer expires.
void TimerExpire(int data)
{
printk("Timer Data: %d\n", data);
}
//Function to set up timers.
void TimerSetup(void)
{
setup_timer(&my_timer, TimerExpire, 5678);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000));
}
//Module Init and Exit Functions.
int init_module(void)
{
int initResult = register_chrdev(MAJOR_NUM, "mytimer", &FileOps);
if (initResult < 0)
{
printk("Cannot obtain major number %d\n", MAJOR_NUM);
return initResult;
}
printk("Loading MyTimer Kernel Module...\n");
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(MAJOR_NUM, "mytimer");
printk("Unloading MyTimer Kernel Module...\n");
}
More specifically, I want my user program to call the TimerSetup() function. I know that I'll need to use ioctl() but I'm not sure how to specify in my MODULE FILE that TimerSetup() should be callable via ioctl().
Also, my second question: I was able to insmod my module and also mknod into /dev/mytimer with the correct major number. But when I tried to open() it so that I can get the file descriptor from it, it kept returning -1, which I'm assuming is wrong. I made sure the permissions were fine (in fact, I made it 777 just to be sure)... It still doesn't work... Is there something I'm missing?
Here is the user program just in case:
#include <stdio.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/mytimer", "r");
printf("fd: %d\n", fd);
return 0;
}
The example code you need can be found in drivers/watchdog/softdog.c (from Linux 2.6.33 at the time this was written), which illustrates proper file operations as well as how to permit userland to fill a structure with ioctl().
It's actually a great, working tutorial for anyone who needs to write trivial character device drivers.
I dissected softdog's ioctl interface when answering my own question, which may be helpful to you.
Here's the gist of it (though far from exhaustive) ...
In softdog_ioctl() you see a simple initialization of struct watchdog_info that advertises functionality, version and device information:
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = "Software Watchdog",
};
We then look at a simple case where the user just wants to obtain these capabilities:
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
... which of course, will fill the corresponding userspace watchdog_info with the initialized values above. If copy_to_user() fails, -EFAULT is returned which causes the corresponding userspace ioctl() call to return -1 with a meaningful errno being set.
Note, the magic requests are actually defined in linux/watchdog.h , so that the kernel and userspace share them:
#define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
#define WDIOC_GETSTATUS _IOR(WATCHDOG_IOCTL_BASE, 1, int)
#define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
#define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int)
#define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
#define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int)
#define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
#define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
#define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
WDIOC obviously signifying "Watchdog ioctl"
You can easily take that a step further, having your driver do something and place the result of that something in the structure and copy it to userspace. For instance, if struct watchdog_info also had a member __u32 result_code. Note, __u32 is just the kernel's version of uint32_t.
With ioctl(), the user passes the address of an object, be it a structure, integer, whatever to the kernel expecting the kernel to write its reply in an identical object and copy the results to the address that was provided.
The second thing you are going to need to do is make sure your device knows what to do when someone opens, reads from it, writes to it, or uses a hook like ioctl(), which you can easily see by studying softdog.
Of interest is:
static const struct file_operations softdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = softdog_write,
.unlocked_ioctl = softdog_ioctl,
.open = softdog_open,
.release = softdog_release,
};
Where you see the unlocked_ioctl handler going to ... you guessed it, softdog_ioctl().
I think you might be juxtaposing a layer of complexity that really doesn't exist when dealing with ioctl(), it really is that simple. For that same reason, most kernel developers frown on new ioctl interfaces being added unless they are absolutely necessary. Its just too easy to lose track of the type that ioctl() is going to fill vs the magic you use to do it, which is the primary reason that copy_to_user() fails often resulting in the kernel rotting with hordes of userspace processes stuck in disk sleep.
For a timer, I agree, ioctl() is the shortest path to sanity.
You are missing a .open function pointer in your file_operations structure to specify the function to be called when a process attempts to open the device file. You will need to specify a .ioctl function pointer for your ioctl function as well.
Try reading through The Linux Kernel Module Programming Guide, specifically chapters 4 (Character Device Files) and 7 (Talking to Device Files).
Chapter 4 introduces the file_operations structure, which holds pointers to functions defined by the module/driver that perform various operations such as open or ioctl.
Chapter 7 provides information on communicating with a module/drive via ioctls.
Linux Device Drivers, Third Edition is another good resource.
Minimal runnable example
Tested in a fully reproducible QEMU + Buildroot environment, so might help others get their ioctl working. GitHub upstream:
kernel module |
shared header |
userland.
The most annoying part was understanding that some low ids are hijacked: ioctl is not called if cmd = 2 , you have to use _IOx macros.
Kernel module:
#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include "ioctl.h"
MODULE_LICENSE("GPL");
static struct dentry *dir;
static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
void __user *arg_user;
union {
int i;
lkmc_ioctl_struct s;
} arg_kernel;
arg_user = (void __user *)argp;
pr_info("cmd = %x\n", cmd);
switch (cmd) {
case LKMC_IOCTL_INC:
if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) {
return -EFAULT;
}
pr_info("0 arg = %d\n", arg_kernel.i);
arg_kernel.i += 1;
if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) {
return -EFAULT;
}
break;
case LKMC_IOCTL_INC_DEC:
if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) {
return -EFAULT;
}
pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j);
arg_kernel.s.i += 1;
arg_kernel.s.j -= 1;
if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) {
return -EFAULT;
}
break;
default:
return -EINVAL;
break;
}
return 0;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = unlocked_ioctl
};
static int myinit(void)
{
dir = debugfs_create_dir("lkmc_ioctl", 0);
/* ioctl permissions are not automatically restricted by rwx as for read / write,
* but we could of course implement that ourselves:
* https://stackoverflow.com/questions/29891803/user-permission-check-on-ioctl-command */
debugfs_create_file("f", 0, dir, NULL, &fops);
return 0;
}
static void myexit(void)
{
debugfs_remove_recursive(dir);
}
module_init(myinit)
module_exit(myexit)
Shared header between the kernel module and userland:
ioctl.h
#ifndef IOCTL_H
#define IOCTL_H
#include <linux/ioctl.h>
typedef struct {
int i;
int j;
} lkmc_ioctl_struct;
#define LKMC_IOCTL_MAGIC 0x33
#define LKMC_IOCTL_INC _IOWR(LKMC_IOCTL_MAGIC, 0, int)
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)
#endif
Userland:
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "../ioctl.h"
int main(int argc, char **argv)
{
int fd, arg_int, ret;
lkmc_ioctl_struct arg_struct;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file>");
return EXIT_FAILURE;
}
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
/* 0 */
{
arg_int = 1;
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d\n", arg_int);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
puts("");
/* 1 */
{
arg_struct.i = 1;
arg_struct.j = 1;
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d %d\n", arg_struct.i, arg_struct.j);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
close(fd);
return EXIT_SUCCESS;
}

Resources