Linux Device Driver, kernel thread can't open file? - c

I'm writing a Linux Driver with Linux Kernel Modules when, user can write and when user calls close, driver has to flush content into a file in another directory with same name of the device file.
I have this problem: when a process calls close, the driver can open a file and flush all its content correctly; when the process is killed (for example, from the terminal with a kill), device driver fails to execute filp_open becuse fs->CURRENT is set to NULL. So, I was trying to start a kernel thread to do this work.
When I try opening a file in the same directory, for example filp_open("myfile"...), it works correctly. But if I have to open a file in another directory, so filp_open("dirA/myfile"), filp_open returns -2. But this not going to happen when I call filp_open from the main thread.
This is my code:
static int thread_fn(void *unused){
struct thread_data* td = (struct thread_data *) unused;
if(td == NULL)
printk(KERN_INFO "td is null\n");
struct file* filp=filp_open("/dirA/myfile",O_RDWR,0666);
if(filp == NULL || (IS_ERR(filp)))
printk(KERN_INFO "filp is null!\n");
else
printk(KERN_INFO "filp is not null!\n");
size_t filp_size = filp->f_inode->i_size;
printk(KERN_INFO "size on release: %ld\n",filp_size);
if(filp_size > td->size){
printk(KERN_INFO "truncating file\n");
truncate_setsize(filp->f_inode, td->size);
}
inode_lock(filp->f_inode);
//file_write(filp,/*file->f_pos*/0,td->data,td->size);
inode_unlock(filp->f_inode);
printk(KERN_INFO "Thread Stopping\n");
do_exit(0);
return 0;
}
This is my device_release function:
static int device_release(struct inode *inode, struct file *file)
{
if(my_data->buffer == NULL)
return -ENOMEM;
struct thread_data* td=alloc_mem(sizeof(struct thread_data));
td->filename=my_data->filename;
td->data=my_data->buffer;
td->size=my_data->size;
thread_st = kthread_run(thread_fn, (void *)td,"Thread!");
if (thread_st)
printk(KERN_INFO "Thread Created successfully\n");
else
printk(KERN_ERR "Thread creation failed\n");
return 0;
}
What's the problem? I can't understand, it could be an OS problem? I have also tried with set_fs/get_fs but it didn't work.

I have an update: if I put flag O_CREAT, filp_open doesn't return error, but file isn't created; so, kernel thread cannot operate on file?

Related

Linux C ext2fs_write_inode_full failing to write

after successfully reading the file inode with this:
retval = ext2fs_read_inode_full(current_fs, inode, inode_buf, EXT2_INODE_SIZE(current_fs->super));
if (retval) {
fprintf(stderr, "Failed to read inode\n");
free(fs);
free(inode_buf);
return retval;
}
(At this point I have verified the inode contains the correct data of the file in question)
I immediately attempt to write it back with this :
retval = ext2fs_write_inode_full(current_fs, inode, inode_buf, EXT2_INODE_SIZE(current_fs->super));
if (retval) {
fprintf(stderr, "Failed to write inode %d\n", retval);
}
(Of course it's my intention to change some date values in the inode before writing back)
But ext2fs_write_inode_full returns an error value 2133571349.
The program executes with root privileged!
The issue turned out to be the way crtime was opening the FS with ext2fs_open.
I needed to pass the EXT2_FLAG_RW flag otherwise the open is by default read only.

ioctl error when open char dev file

i am writing a driver code, to read some register values from x86., when i ran my user space application i got the below error.
ioctl:Inappropriate ioctl for device
here is the code sniff..
fd = open_drvfile();
if(ioctl(fd, IOCTL_MSR_CMDS, (long long)msr_start) == -1 ) {
perror("ioctl:");
exit (0);
}
and open_drvfile() just open(create and open) the char file as below
fd = open("/dev/" DEV_NAME, O_RDWR|O_CREAT);
if (fd == -1) {
perror("Failed to open /dev/" DEV_NAME);
}
return fd;
can some one point where i made mistake on this?
A char device implies that it shall be created with mknod(), and not with O_CREAT under open() flags (which will create a regular file, not a char device).
(see question comments).

IOCTL: invalid argument for HDIO_GET_IDENTITY

I wrote a program to get the details of hard disk drive using HDIO_ ioctl calls.
For writing program, I'm referring Documentation/ioctl/hdio.txt in kernel source(2.6.32).
Here is my main part of code:
unsigned char driveid[512];
fd = open("/dev/sda", O_RDONLY); // validated fd.
retval = ioctl(fd, HDIO_GET_IDENTITY, &driveid);
if(retval < 0) {
perror("ioctl(HDIO_GET_IDENTITY)");
exit(3);
}
When I run(as root) the above code, I got below error:
ioctl(HDIO_GET_IDENTITY): Invalid argument
What is the wrong in the program?
Why I'm getting error?
Additional Info: OS: CentOS-6.5, kernel version: 2.6.32, IA:x86_64 (running on VMware).
the HDIO_GET_IDENTITY ioctl() doesn`t take a raw character buffer as its 3rd argument.
it uses a struct defined in linux/hdreg.h.
struct hd_driveid driveid;
fd = open("/dev/sda", O_RDONLY); // validated fd.
retval = ioctl(fd, HDIO_GET_IDENTITY, &driveid);
if(retval < 0) {
perror("ioctl(HDIO_GET_IDENTITY)");
exit(3);
}
this way it should work. Be aware that it only works for IDE/SATA drives, SCSI is not supported.
has
if you are wondering on how to get the information after the command ioctl() has returned succesfully, I suggest going through
http://lxr.free-electrons.com/source/include/linux/hdreg.h?v=2.6.36

Opening a file from userspace from a Linux kernel module

I've been following a tutorial for opening files from userspace from a Linux kernel module at http://www.howtoforge.com/reading-files-from-the-linux-kernel-space-module-driver-fedora-14
The code is the following:
#include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // Needed for KERN_INFO
#include <linux/fs.h> // Needed by filp
#include <asm/uaccess.h> // Needed by segment descriptors
int init_module(void)
{
// Create variables
struct file *f;
char buf[128];
mm_segment_t fs;
int i;
// Init the buffer with 0
for(i=0;i<128;i++)
buf[i] = 0;
// To see in /var/log/messages that the module is operating
printk(KERN_INFO "My module is loaded\n");
// I am using Fedora and for the test I have chosen following file
// Obviously it is much smaller than the 128 bytes, but hell with it =)
f = filp_open("/etc/fedora-release", O_RDONLY, 0);
if(f == NULL)
printk(KERN_ALERT "filp_open error!!.\n");
else{
// Get current segment descriptor
fs = get_fs();
// Set segment descriptor associated to kernel space
set_fs(get_ds());
// Read the file
f->f_op->read(f, buf, 128, &f->f_pos);
// Restore segment descriptor
set_fs(fs);
// See what we read from file
printk(KERN_INFO "buf:%s\n",buf);
}
filp_close(f,NULL);
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "My module is unloaded\n");
}
The code is copy-pasted from the link above. On my machine, running Fedora 19 with 3.11.10-200 kernel, it seems that filp_open isn't run, providing the buf variable with null values.
What could be wrong? I am still learning the ropes of Linux kernel module development.
First thing you should do is to check if any errors are returned from filp_open (in fact, checking for NULL is probably an outright mistake when modern kernels are concerned). The proper sequence should be:
f = filp_open("/etc/fedora-release", O_RDONLY, 0);
if (IS_ERR(f)) {
// inspect the value of PTR_ERR(f), get the necessary clues
// negative values represent various errors
// as defined in asm-generic/errno-base.h
}
Only then you can move on to diagnosing the read.
977 struct file *filp_open(const char *filename, int flags, umode_t mode)
978 {
979 struct filename *name = getname_kernel(filename);
980 struct file *file = ERR_CAST(name);
981
982 if (!IS_ERR(name)) {
983 file = file_open_name(name, flags, mode);
984 putname(name);
985 }
986 return file;
987 }
Probably the error is in how you put the parameters, the flags parameter is in mode parameter position and vice versa, mode in falgs position.
source: http://lxr.free-electrons.com/source/fs/open.c#L977

Errno : 13 on using fopen on proc entry

I am trying to write a /proc file created by a loadable kernel module. I am using fopen() to open the file for write but am getting errno : 13 (permission denied).
FILE *fp;
fp = fopen("/proc/file1","w");
if(fp == NULL){
printf("Errno : %d",errno); // prints 13
}
The LKM contains the following code:
static struct proc_dir_entry *proc_entry;
static ssize_t proc_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
{
// code writes from buffer to local variable
return len;
}
static ssize_t proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
// code for reading file
return 0;
}
int proc_open(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
return 0;
}
int proc_close(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
return 0;
}
Any suggestions on how to overcome this?
Thanks.
The most probable answer is that the procfs node that is created does not have the correct permissions for the user.
When run as root, it bypasses most of the permission checking for the node, so you do not receive an error (there are exceptions; this is the general case).
in the kernel loadable module, where it creates the procfs node (somewhere in the .c file):
create_proc_entry(...)
You need to make sure that the second parameter, the mode is set to something that permits opening for writing by users other than root in order to support your desired open option; e.g. 0666 makes the file globally openable as R/W by anyone.
Generally, nodes in procfs are created with the flags 0444 (i.e. R/O only for all users). Some are created in mode 0644 (R/W by root, R/O for all other users), some are created with permissions 0400 (R/O for root, all others stay away).

Resources