character module blues: bad memory address on close and read - linux-kernel

I'm making a simple fifo style character module. I'm struggling to get it to behave. Here's what's happening:
I'm getting
close failed in file object destructor:
IOError: [Errno 14] Bad address
When i try to close a file object that I'm using to talk to my character device. I also get a bad address when I try to read from it. I'm pretty new to kernel programming so I'm not too sure what these symptoms imply. Here is some relevant code. Any assistance would be greatly appreciated:
int pop(char *source, char* dest, int count)
{
// take count values from source, store in dest
memcpy(dest,source,count);
memset(source,0x00,count);
return 0;
}
ssize_t ent_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
int retval;
char *temp;
int copy_count;
printk(KERN_ALERT "entropy_feed: module reading...\n");
if (level>=count)
{
copy_count=count;
}
else
{
copy_count=level;
}
printk(KERN_ALERT "entropy_feed: allocating temp memory buffer");
temp = kcalloc(copy_count,1,GFP_KERNEL);
if (down_interruptible(&sem))
{
retval= -ERESTARTSYS;
goto u_out;
}
printk(KERN_ALERT "entropy_feed: semaphore locked");
printk(KERN_ALERT "entropy_feed: popping");
pop(buffer+level-copy_count, temp, copy_count);
printk(KERN_ALERT "entropy_feed: popped");
level-=copy_count;
if (copy_to_user(buf,temp,copy_count))
{
retval= -EFAULT;
goto out;
}
out:
up(&sem);
printk(KERN_ALERT "entropy_feed: semaphore unlocked");
u_out:
kfree(temp);
printk(KERN_ALERT "entropy_feed: exiting read function")
return retval;
}
ssize_t ent_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
int retval;
char *temp;
int copy_count;
printk(KERN_ALERT "entropy_feed module writing...\n");
copy_count=level-max_lvl;
if (count<copy_count)
copy_count=count;
if (down_interruptible(&sem))
{
retval= -ERESTARTSYS;
goto u_out;
}
printk(KERN_ALERT "entropy_feed: semaphore locked");
temp = kcalloc(count,1,GFP_KERNEL);
if (copy_from_user(temp,buf,count))
{
retval= -EFAULT;
goto out;
}
printk(KERN_ALERT "entropy_feed: popping");
pop(temp, buffer+level, copy_count);
printk(KERN_ALERT "entropy_feed: popped");
level+=copy_count;
out:
up(&sem);
printk(KERN_ALERT "entropy_feed: semaphore unlocked");
u_out:
kfree(temp);
printk(KERN_ALERT "entropy_feed: exiting write function");
return retval;
}
struct file_operations ent_fops = {
.owner = THIS_MODULE,
.read = ent_read,
.write = ent_write,
};

Error number 14 is EFAULT.
Looking at your ent_read() function, I don't see anywhere that you set retval to the number of bytes written if the function succeeds, so you are just returning whatever uninitialized value is in retval in the non-failure case. Try adding
retval = copy_count;
right before the
out:
line, so that you get the correct return value in the successful read case.
As far as the error from close, does your actual file_operations structure have a flush method? If so what are you returning from that? Otherwise I can't see why close() would return EFAULT for you.

Related

Unable to print the message sent from user space C application to linux kernel module

I have developed a simple linux kernel module :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
return length;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_ALERT "Inside the %s function\n", __FUNCTION__);
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
I insert this module to the kernel using insmod command without any problem.
I want to use this module to print a message sent to it by user space program that I have developed too :
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
int main()
{
int ret, fd;
char stringToSend[] = "Hello World !";
fd = open("/dev/char_device", O_RDWR); // Open the device with read/write access
if (fd < 0)
{
perror("Failed to open the device...");
return errno;
}
ret = write(fd, stringToSend, strlen(stringToSend)); // Send the string to the LKM
if (ret < 0)
{
perror("Failed to write the message to the device.");
return errno;
}
return 0;
}
When I execute the program and examin the kernel logs using tail -f /var/log/messages command I can see : user.alert kernel: Inside the exer_read function But I cant see the message " Hello World !"
I don't know what I am missing here especially I still beginner in developing modules and using it. Help me please!
For people who still can't find a solution for that, I have an answer.
This is the module :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gaston");
MODULE_DESCRIPTION("A simple Linux char driver");
MODULE_VERSION("0.1");
#define MAX 256
static char message[MAX] =""; ///< Memory for the string that is passed from userspace
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device has been opened\n");
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
if (length > MAX)
return -EINVAL;
if (copy_from_user(message, buffer, length) != 0)
return -EFAULT;
printk(KERN_INFO "Received %s characters from the user\n", message);
return 0;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device successfully closed\n");
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_INFO "Initializing the LKM\n");
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
Ans this is the application :
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#define BUFFER_LENGTH 256
int main()
{
int ret, fd;
char stringToSend[BUFFER_LENGTH];
fd = open("/dev/char_device", O_RDWR); // Open the device with read/write access
if (fd < 0)
{
perror("Failed to open the device...");
return errno;
}
printf("Type in a short string to send to the kernel module:\n");
scanf("%s", stringToSend); // Read in a string (with spaces)
printf("Writing message to the device [%s].\n", stringToSend);
ret = write(fd, stringToSend, strlen(stringToSend)); // Send the string to the LKM
if (ret < 0)
{
perror("Failed to write the message to the device.");
return errno;
}
return 0;
}
You will see that this will work fine.

There is no entry for device under /dev even after class_create and device_create

I am making one simple char driver and I learnt that there are 2 ways I can get Major number for my driver to pair with - alloc_chrdev_region(and register_chrdev_region) and register_chrdev. I initially started with register_chrdev and it gave me my major number and also created entry in /dev (class and device create used).
But when I change for register_chrdev to alloc_chrdev_region to acquire major number (using chrdev_init and chrdev_add), leaving rest of the entry function same, I don't see an entry in /dev, though when I make it manually with mknode, and run the test application to use the driver, it works fine.
Below is the code of entry point that does not produce the /dev entry
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<linux/kernel.h>
#include<linux/slab.h>
#include<linux/uaccess.h>
#include<linux/stat.h>
#include<linux/cdev.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#define DEVICE_NAME "myCharDevice"
#define MODULE_NAME "myCharDriver"
#define CLASS_NAME "myCharClass"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YASH BHATT");
MODULE_VERSION(".01");
static char *bufferMemory;
static int bufferPointer;
static int bufferSize = 15;
static dev_t myChrDevid;
static struct cdev *myChrDevCdev;
static struct class *pmyCharClass;
static struct device *pmyCharDevice;
int majorNumber = 0;
static int charDriverOpen(struct inode *inodep, struct file *filep);
static int charDriverClose(struct inode *inodep, struct file *filep);
static ssize_t charDriverWrite(struct file *filep, const char *buffer, size_t len, loff_t *offset);
static ssize_t charDriverRead(struct file *filep, char *buffer, size_t len, loff_t *offset);
static int charDriverEntry(void);
static void charDriverExit(void);
static ssize_t attrShowData(struct device*, struct device_attribute*, char*);
static ssize_t attrStoreData(struct device*, struct device_attribute*, const char*, size_t);
static ssize_t attrShowBuffer(struct device*, struct device_attribute*, char*);
static ssize_t attrStoreBuffer(struct device*, struct device_attribute*, const char*, size_t);
/* The following function is called when the file placed on the sysfs is accessed for read*/
static ssize_t attrShowData(struct device* pDev, struct device_attribute* attr, char* buffer)
{
printk(KERN_INFO "MESG: The data has been accessed through the entry in sysfs\n");
if (bufferPointer == 0)
{
printk(KERN_WARNING "Thre is no data to read from buffer!\n");
return -1;
}
strncpy(buffer, bufferMemory, bufferPointer);
/* Note : Here we can directly use strncpy because we are already in kernel space and do not need to translate address*/
return bufferPointer;
}
static ssize_t attrStoreData(struct device* pDev, struct device_attribute* attr, const char* buffer, size_t length)
{
printk(KERN_INFO "Writing to attribute\n");
bufferPointer = length;
strncpy(bufferMemory, buffer, length);
return length;
}
static ssize_t attrShowBuffer(struct device* pDev, struct device_attribute* attr, char* buffer)
{
int counter;
int temp = bufferSize;
char bufferSizeArray[4] = {0};
counter = 3;
//printk(KERN_INFO "Buffer = %d\n",bufferSize % 10);
do
{
bufferSizeArray[counter] = '0' + (bufferSize % 10);
//printk(KERN_INFO "Character at %d is : %c\n",counter,bufferSizeArray[counter]);
bufferSize /= 10;
counter--;
}
while(counter != -1);
strncpy(buffer, bufferSizeArray, 4);
bufferSize = temp;
/* Note : Here we can directly use strncpy because we are already in kernel space and do not need to translate address*/
return 4;
}
static ssize_t attrStoreBuffer(struct device* pDev, struct device_attribute* attr, const char* buffer, size_t length)
{
int counter;
bufferPointer = length;
//printk(KERN_INFO "Length : %d With first char %c\n",length,buffer[0]);
bufferSize = 0;
for (counter = 0; counter < length-1 ; counter++)
{
bufferSize = (bufferSize * 10) + (buffer[counter] - '0') ;
}
//printk(KERN_INFO "Buffer size new : %d\n",bufferSize);
return length;
}
/* These macros converts the function in to instances dev_attr_<_name>*/
/* Defination of the macro is as follows : DEVICE_ATTR(_name, _mode, _show, _store) */
/* Note the actual implementation of the macro makes an entry in the struct device_attribute. This macro does that for us */
static DEVICE_ATTR(ShowData, S_IRWXU, attrShowData, attrStoreData); // S_IRUSR gives read access to the user
static DEVICE_ATTR(Buffer, S_IRWXU, attrShowBuffer, attrStoreBuffer); // S_IRUSR gives read access to the user
static struct file_operations fops =
{
.open = charDriverOpen,
.release = charDriverClose,
.read = charDriverRead,
.write = charDriverWrite,
};
static int __init charDriverEntry()
{
int returnValue;
//majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
returnValue = alloc_chrdev_region(&myChrDevid, 0, 1, DEVICE_NAME);
/* This function takes 4 arguments - dev_t address, start of minor number, range/count of minor number, Name; Note - unlike register_chrdev fops have not
yet been tied to the major number */
if (returnValue < 0)
{
printk(KERN_ALERT "ERROR : can not aquire major number! error %d",returnValue);
return -1;
}
printk(KERN_INFO "Aquired Major Number! : %d\n", MAJOR(myChrDevid));
//cdev_init(&myChrDevCdev,&fops);
myChrDevCdev = cdev_alloc();
if (IS_ERR(myChrDevCdev))
{
printk(KERN_ALERT "Failed to allocate space for CharDev struct\n");
unregister_chrdev_region(myChrDevid, 1);
return -1;
}
cdev_init(myChrDevCdev,&fops);
myChrDevCdev->owner = THIS_MODULE;
//myChrDevCdev->ops = &fops;/* this function inits the c_dev structure with memset 0 and then does basic konject setup and then adds fops to cdev struct*/
/* this function adds the cdev to the kernel structure so that it becomes available for the users to use it */
// Now we will create class for this device
pmyCharClass = class_create(THIS_MODULE,CLASS_NAME);
if (IS_ERR(pmyCharClass))
{
printk(KERN_ALERT "Failed to Register Class\n");
cdev_del(myChrDevCdev);
kfree(myChrDevCdev);
unregister_chrdev_region(myChrDevid, 1);
return -1;
}
printk(KERN_INFO "Class created!\n");
pmyCharDevice = device_create(pmyCharClass, NULL, MKDEV(majorNumber,0),NULL,DEVICE_NAME);
if (IS_ERR(pmyCharDevice))
{
printk(KERN_ALERT "Failed to Register Class\n");
class_unregister(pmyCharClass);
class_destroy(pmyCharClass);
cdev_del(myChrDevCdev);
kfree(myChrDevCdev);
unregister_chrdev_region(myChrDevid, 1);
return -1;
}
printk(KERN_INFO "Device created!\n");
returnValue = cdev_add(myChrDevCdev, myChrDevid, 1);
if (returnValue < 0)
{
printk(KERN_ALERT "Failed to add chdev \n");
return -1;
}
/* We now have created the class and we have aquired major numer. But we have not yet tied out created fileops with anything.
We will do that now */
//returnValue = cdev_init(cdev)
printk(KERN_INFO "Now We will create the attribute entry in sysfs\n");
/* the function used is device_create_file(struct device *, struct device_attribute*) */
device_create_file(pmyCharDevice, &dev_attr_ShowData); // The second argumnet is the structure created by the DEVICE_ATTR macro
device_create_file(pmyCharDevice, &dev_attr_Buffer);
return 0;
}
static void __exit charDriverExit()
{
device_remove_file(pmyCharDevice, &dev_attr_Buffer);
device_remove_file(pmyCharDevice, &dev_attr_ShowData);
device_destroy(pmyCharClass, MKDEV(majorNumber,0));
class_unregister(pmyCharClass);
class_destroy(pmyCharClass);
//unregister_chrdev(majorNumber,DEVICE_NAME);
cdev_del(myChrDevCdev);
unregister_chrdev_region(myChrDevid, 1);
kfree(myChrDevCdev);
printk(KERN_INFO "Unmounting module done !\n");
}
static int charDriverOpen(struct inode *inodep, struct file *filep)
{
if ((filep->f_flags & O_ACCMODE) != O_RDWR)
{
printk(KERN_ALERT "WARNING : This driver can only be opened in both read and write mode\n");
return -1;
}
printk(KERN_INFO "INFO : CHARATER DRIVER OPENED\n");
bufferMemory = kmalloc(bufferSize,GFP_KERNEL);
bufferPointer = 0;
return 0;
}
static int charDriverClose(struct inode *inodep, struct file *filep)
{
kfree(bufferMemory);
printk(KERN_INFO "INFO : CHARACTER DRIVER CLOSED\n");
return 0;
}
static ssize_t charDriverWrite(struct file *filep, const char *buffer, size_t len, loff_t *offset)
{
// Here we will only allow to write one byte of data
if (len > bufferSize)
{
printk(KERN_WARNING "Attempted to write data larger than 15 byte!\n");
return 0;
}
//bufferMemory[bufferPointer] = *buffer;
copy_from_user(bufferMemory, buffer, len);
bufferPointer += len;
return len;
}
static ssize_t charDriverRead(struct file *filep, char *buffer, size_t len, loff_t *offset)
{
if(len > bufferSize || len > bufferPointer)
{
printk(KERN_WARNING "Attempting to read more than buffer size ! Deny\n");
return 0;
}
copy_to_user(buffer, bufferMemory, len);
// buffer[0] = bufferMemory[0];
bufferPointer -= len;
return len;
}
module_init(charDriverEntry);
module_exit(charDriverExit);
module_param(bufferSize, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bufferSize, "Buffer Memory Size [15]");
Now if I replace the while alloc_chrdev_region, cdev_init and cdev_add with just register_chrdev(), The entry in /dev pops up. I am unable to figure out what more does register_chrdev() do that the former combination does not.
Thank you
Edit : Found the issue.
it was due to using MKDEV(majorNumber, 0); Without actually storing major number in the majorNumber variable using MAJOR();
Not deleting the question as someone can find it useful

how to alloc user space memory in kernel space?

I hook a syscall(open) on Linux, and want to print this opened filename.
then I call syscall(getcwd) to get the absolute path.
this is source code:
void *memndup_from_user(const void __user *src, long len)
{
void *kbuf = NULL;
if(src == NULL) {
return kbuf;
}
kbuf = kmalloc(len + 1, GFP_KERNEL);
if(kbuf != NULL) {
if (copy_from_user(kbuf, src, len)) {
printk(KERN_ALERT "%s\n", "copy_from_user failed.");
kfree(kbuf);
kbuf = NULL;
}
else {
((char *)kbuf)[len] = '\0';
}
} else {
printk(KERN_ALERT "%s\n", "kmalloc failed.");
}
return kbuf;
}
void *memdup_from_user(const void __user *src)
{
long len = 0;
if(src == NULL) {
return NULL;
}
len = strlen_user(src);
return memndup_from_user(src, len);
}
asmlinkage long fake_getcwd(char __user *buf, unsigned long size)
{
return real_getcwd(buf, size);
}
asmlinkage long
fake_open(const char __user *filename, int flags, umode_t mode)
{
if(flags & O_CREAT) {
char *k_filename = (char *)memdup_from_user(filename);
char *u_path = (char *)kmalloc(PAGE_SIZE, GFP_USER);
if(k_filename != NULL) {
printk(KERN_ALERT "ano_fake_open pid:%ld create : %s\n", ano_fake_getpid(), k_filename);
kfree(k_filename);
}
if(u_path != NULL) {
long retv;
retv = fake_getcwd(u_path, PAGE_SIZE);
if(retv > 0) {
printk(KERN_ALERT "getcwd ret val: %ld, path: %s\n", retv, u_path);
} else {
printk(KERN_ALERT "getcwd ret val: %ld, error...\n", retv);
}
kfree(u_path);
}
}
return real_open(filename, flags, mode);
}
the sys_getcwd requires an user space memory, and I call kmalloc with GFP_USER.
but sys_getcwd always return -EFAULT(Bad Address)...
this is dmesg logs:
[344897.726061] fake_open pid:70393 create : sssssssssssssssss
[344897.726065] getcwd ret val: -14, error...
[344897.727431] fake_open pid:695 create : /var/lib/rsyslog/imjournal.state.tmp
[344897.727440] getcwd ret val: -14, error...
so I find the implement in sys_getcwd, he does
# define __user __attribute__((noderef, address_space(1)))
# define __kernel __attribute__((address_space(0)))
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
{
char *page = __getname();
get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
...
// char *cwd = page + xxx; (xxx < PAGE_SIZE)
// len = PAGE_SIZE + page - cwd;
...
if (len <= size) {
error = len;
if (copy_to_user(buf, cwd, len))
error = -EFAULT;
}
}
obviously, getcwd alloc memory with flag GFP_KERNEL, then copy to my buffer( __user *buf ) from (GFP_KERNEL) !!!
isn't __user MACRO be GFP_USER ?
the flag GFP_USER brief is https://elixir.bootlin.com/linux/v4.4/source/include/linux/gfp.h#L208:
/* GFP_USER is for userspace allocations that also need to be directly
* accessibly by the kernel or hardware. It is typically used by hardware
* for buffers that are mapped to userspace (e.g. graphics) that hardware
* still must DMA to. cpuset limits are enforced for these allocations.
*/
what's wrong ?
This is wrong on at least two accounts:
syscall hijacking (let alone for something like open) is just a bad idea. the only sensible method to catch all possible open path is through using LSM hooks. it also happens to deal with the actual file being opened avoiding the race: you read the path in your routine, wrapped opens reads it again. but by that time malicious userspace could have changed it and you ended up looking at the wrong file.
it should be clear getcwd has to have a method of resolving a name in order to put it into the userspace buffer. you should dig in into the call and see what can be changed to put it in a kernel buffer.
Why are you doing this to begin with?

polling sysfs and kernel module

I have read many posts about this same topic, but I am unable to find out what is exactly wrong with my sysfs implementation in my kernel module. I am trying to make a userspace program block on a poll untill the value changes in a sysfs file. Most people seem to not get blocking, I seem to not be able to get out of my blocking. Here is the relevent code:
kernel module:
static int sysfs_test = 88;
static ssize_t test_interrupts_show(struct device* dev, struct device_attribute* attr, const char* buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", sysfs_test);
}
static ssize_t test_interrupts_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
kstrtol(buf, 10, &sysfs_test);
return count;
}
static DEVICE_ATTR(interrupts, S_IWUSR | S_IRUGO, test_interrupts_show, test_interrupts_store);
static int __init test_init(void)
{
int result;
if(dev_major)
{
dev = MKDEV(dev_major, dev_minor);
result = register_chrdev_region(dev, NUM_DEVICES, name);
} else {
result = alloc_chrdev_region(&dev, dev_minor, NUM_DEVICES, name);
dev_major = MAJOR(dev);
dev_minor = MINOR(dev);
}
if(result < 0) {
printk(KERN_WARNING "%s: can't get major %d\n", name, dev_major);
return -1;
}
printk(KERN_NOTICE "%s: Major = %d, Minor = %d\n", name, dev_major, dev_minor);
// Register as character device
test_cdev = cdev_alloc();
cdev_init(cajun_cdev, &test_fops); // Initialize cdev structure
test_cdev->owner = THIS_MODULE; // Add owner
result = cdev_add(test_cdev, dev,1); // Tell kernel about our device
if(result)
{
printk(KERN_NOTICE "Error %d adding cdev\n", result);
goto OUT2;
}
// This stuff relates to sysfs:
ctest_class = class_create(THIS_MODULE, NAME);
if(IS_ERR(test_class))
{
printk(KERN_ALERT "Failed to register device class\n");
goto OUT2;
}
test_device = device_create(test_class, NULL, dev, NULL, NAME);
if(IS_ERR(test_device))
{
printk(KERN_ALERT "Failed to create device\n");
goto OUT3;
}
result = device_create_file(test_device, &dev_attr_interrupts);
if (result < 0)
{
printk(KERN_ALERT "failed\n");
}
OUT3:
class_unregister(test_class);
class_destroy(test_class);
OUT2:
cdev_del(test_cdev);
OUT1:
unregister_chrdev_region(dev, NUM_DEVICES);
return -1;
}
Relevent userspace code:
char interrupts_path[] = "/sys/class/test_module/test_module/interrupts";
int main()
{
struct pollfd fds;
fds.fd = open(interrupts_path, O_RDWR | O_SYNC);
char dummy_buff[1];
read(fds.fd, dummy_buff, 1);
lseek(fds.fd, 0, SEEK_SET);
fds.events = POLLPRI;
printf("Polling for interrupt\n");
poll(&fds,1,-1);
printf("Interrupt occured\n");
return 0;
}
I run my userspace code in the background (./test &) and then I echo a new value into the sysfs file for interrupts. I am hopping for my userspace program to unblock and return when the value changes. What am I doing wrong here?
edit:
struct file_operations test_fops = {
.owner = THIS_MODULE,
.llseek = test_llseek,
.read = test_read,
.write = test_write,
.unlocked_ioctl = test_ioctl,
.open = test_open,
.release = test_release
};

interacting user space during system call

I'm trying to write block device driver that implements read/write operations.
The tricky thing is that the information is not in the hardware, but in a user space process. Therefore, during the read/write system call I would like to interact the user space (i.e. sendign signal to the user space).
However, my user space process catching the signal only after the read/write system call returned. adding wait in the system call implementation seems to be ignored somehow.
I used this code at the read system call:
ssize_t sleepy_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
struct siginfo info;
struct task_struct *t;
int ret;
#define SIG_TEST 44
memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIG_TEST;
info.si_code = SI_QUEUE;
info.si_int = 1234;
rcu_read_lock();
t = pid_task(find_pid_ns(current->pid, &init_pid_ns), PIDTYPE_PID);
if(t == NULL){
printk(KERN_ERR "no such pid\n");
rcu_read_unlock();
return -ENODEV;
}
rcu_read_unlock();
ret = send_sig_info(SIG_TEST, &info, t); //send the signal
if (ret < 0) {
printk("error sending signal\n");
return ret;
}
wait_event_interruptible(wq, flag != 0);
msleep(10000);
return (0);
}
and this code at user space:
#define SIG_TEST 44
int g_devFile = -1;
void receiveData(int n, siginfo_t *info, void *unused)
{
printf("received value %i\n", info->si_int);
}
int main(void)
{
struct sigaction sig;
sig.sa_sigaction = receiveData;
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig, NULL);
g_devFile = open(devname, O_RDWR);
if ( g_devFile < 0 ) {
fprintf(stderr,"Error opening device[%s] file err[%s]\n",devname,strerror(errno));
return -1;
} else {
fprintf (stderr, "device opened. ptr=%p\n", (void*)g_devFile);
}
i = read(g_devFile, &buff, 11);
}
Currently I'm catching my signal (in user space) only after the 10 seconds sleep expieres (the wait seems to be ignored).
Any idea will be appriceated. Thanks.

Resources