ioctl - invalid argument - c

I have
#define IOCTL_ALLOC_MSG _IO(MAJOR_NUM, 0)
#define IOCTL_DEALLOC_MSG _IO(MAJOR_NUM, 1)
in a header file.
and in the driver file I wrote:
struct file_operations memory_fops = {
unlocked_ioctl: device_ioctl,
open: memory_open,
release: memory_release
};
int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(MAJOR_NUM, "memory", &memory_fops);
if (result < 0) {
printk("<1>memory: cannot obtain major number %d\n", MAJOR_NUM);
return result;
}
allocfunc();
printk("<1>Inserting memory module\n");
return 0;
}
int device_ioctl(struct inode *inode, /* see include/linux/fs.h */
struct file *file, /* ditto */
unsigned int ioctl_num, /* number and param for ioctl */
unsigned long ioctl_param)
{
/*
* Switch according to the ioctl called
*/
printk ( "<l> inside ioctl \n" );
switch (ioctl_num) {
case IOCTL_ALLOC_MSG:
allocfunc();
break;
case IOCTL_DEALLOC_MSG:
deallocfunc();
break;
}
return 0;
}
I created the character file like
mknod /dev/memory c 60 0
the app call fails
int main(int argc, char *argv[]) {
FILE * memfile;
/* Opening the device parlelport */
memfile=fopen("memory","r+");
if ( memfile <0) {
printf ( " cant open file \n");
return -1;
}
/* We remove the buffer from the file i/o */
int ret_val;
if ( argc > 1 ) {
if ( strcmp (argv[1], "mem" ) ==0 ) {
ret_val = ioctl(memfile, IOCTL_ALLOC_MSG);
if (ret_val < 0) {
printf("ioctl failed. Return code: %d, meaning: %s\n", ret_val, strerror(errno));
return -1;
}
}
when i run the app i get "ioctl failed. Return code: -1, meaning: Invalid argument" in : strerror(errno)
printk:
Inserting memory module
fyi, I experimented with "/dev/memory" "memory" different names and major number combinations - but in vain.

You are passing a FILE* to the ioctl() function, while it expects a file descriptor, that is an int.
It should at the very least generate a big warning saying that you are converting a pointer to integer without a cast, doesn't it?
There are two obvious solutions:
Use the fileno() function to get the file descriptor from the FILE*. It should be something like ioctl(fileno(memfile), IOCTL_ALLOC_MSG).
Use open() instead of fopen(). This one is the preferred solution if you are writing low level code, as you avoid the additional abstraction layer that FILE* imposes (all the buffering stuff and so).

I'm going to postulate that changing fopen("memory") to fopen("/dev/memory1") will fix the initial problem with your code.
#SunEric also points out in a comment on your question that you have a call to allocFunc() in your driver's initialization function (memory_init()), and yet that seems to be what you want your IOCTL_ALLOC_MSG to do. That may well be the next problem you need to straighten out.

Related

Why can I not mmap /proc/self/maps?

To be specific: why can I do this:
FILE *fp = fopen("/proc/self/maps", "r");
char buf[513]; buf[512] = NULL;
while(fgets(buf, 512, fp) > NULL) printf("%s", buf);
but not this:
int fd = open("/proc/self/maps", O_RDONLY);
struct stat s;
fstat(fd, &s); // st_size = 0 -> why?
char *file = mmap(0, s.st_size /*or any fixed size*/, PROT_READ, MAP_PRIVATE, fd, 0); // gives EINVAL for st_size (because 0) and ENODEV for any fixed block
write(1, file, st_size);
I know that /proc files are not really files, but it seems to have some defined size and content for the FILE* version. Is it secretly generating it on-the-fly for read or something? What am I missing here?
EDIT:
as I can clearly read() from them, is there any way to get the possible available bytes? or am I stuck to read until EOF?
They are created on the fly as you read them. Maybe this would help, it is a tutorial showing how a proc file can be implemented:
https://devarea.com/linux-kernel-development-creating-a-proc-file-and-interfacing-with-user-space/
tl;dr: you give it a name and read and write handlers, that's it. Proc files are meant to be very simple to implement from the kernel dev's point of view. They do not behave like full-featured files though.
As for the bonus question, there doesn't seem to be a way to indicate the size of the file, only EOF on reading.
proc "files" are not really files, they are just streams that can be read/written from, but they contain no pyhsical data in memory you can map to.
https://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html
As already explained by others, /proc and /sys are pseudo-filesystems, consisting of data provided by the kernel, that does not really exist until it is read – the kernel generates the data then and there. Since the size varies, and really is unknown until the file is opened for reading, it is not provided to userspace at all.
It is not "unfortunate", however. The same situation occurs very often, for example with character devices (under /dev), pipes, FIFOs (named pipes), and sockets.
We can trivially write a helper function to read pseudofiles completely, using dynamic memory management. For example:
// SPDX-License-Identifier: CC0-1.0
//
#define _POSIX_C_SOURCE 200809L
#define _ATFILE_SOURCE
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
/* For example main() */
#include <stdio.h>
/* Return a directory handle for a specific relative directory.
For absolute paths and paths relative to current directory, use dirfd==AT_FDCWD.
*/
int at_dir(const int dirfd, const char *dirpath)
{
if (dirfd == -1 || !dirpath || !*dirpath) {
errno = EINVAL;
return -1;
}
return openat(dirfd, dirpath, O_DIRECTORY | O_PATH | O_CLOEXEC);
}
/* Read the (pseudofile) contents to a dynamically allocated buffer.
For absolute paths and paths relative to current durectory, use dirfd==AT_FDCWD.
You can safely initialize *dataptr=NULL,*sizeptr=0 for dynamic allocation,
or reuse the buffer from a previous call or e.g. getline().
Returns 0 with errno set if an error occurs. If the file is empty, errno==0.
In all cases, remember to free (*dataptr) after it is no longer needed.
*/
size_t read_pseudofile_at(const int dirfd, const char *path, char **dataptr, size_t *sizeptr)
{
char *data;
size_t size, have = 0;
ssize_t n;
int desc;
if (!path || !*path || !dataptr || !sizeptr) {
errno = EINVAL;
return 0;
}
/* Existing dynamic buffer, or a new buffer? */
size = *sizeptr;
if (!size)
*dataptr = NULL;
data = *dataptr;
/* Open pseudofile. */
desc = openat(dirfd, path, O_RDONLY | O_CLOEXEC | O_NOCTTY);
if (desc == -1) {
/* errno set by openat(). */
return 0;
}
while (1) {
/* Need to resize buffer? */
if (have >= size) {
/* For pseudofiles, linear size growth makes most sense. */
size = (have | 4095) + 4097 - 32;
data = realloc(data, size);
if (!data) {
close(desc);
errno = ENOMEM;
return 0;
}
*dataptr = data;
*sizeptr = size;
}
n = read(desc, data + have, size - have);
if (n > 0) {
have += n;
} else
if (n == 0) {
break;
} else
if (n == -1) {
const int saved_errno = errno;
close(desc);
errno = saved_errno;
return 0;
} else {
close(desc);
errno = EIO;
return 0;
}
}
if (close(desc) == -1) {
/* errno set by close(). */
return 0;
}
/* Append zeroes - we know size > have at this point. */
if (have + 32 > size)
memset(data + have, 0, 32);
else
memset(data + have, 0, size - have);
errno = 0;
return have;
}
int main(void)
{
char *data = NULL;
size_t size = 0;
size_t len;
int selfdir;
selfdir = at_dir(AT_FDCWD, "/proc/self/");
if (selfdir == -1) {
fprintf(stderr, "/proc/self/ is not available: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
len = read_pseudofile_at(selfdir, "status", &data, &size);
if (errno) {
fprintf(stderr, "/proc/self/status: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("/proc/self/status: %zu bytes\n%s\n", len, data);
len = read_pseudofile_at(selfdir, "maps", &data, &size);
if (errno) {
fprintf(stderr, "/proc/self/maps: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("/proc/self/maps: %zu bytes\n%s\n", len, data);
close(selfdir);
free(data); data = NULL; size = 0;
return EXIT_SUCCESS;
}
The above example program opens a directory descriptor ("atfile handle") to /proc/self. (This way you do not need to concatenate strings to construct paths.)
It then reads the contents of /proc/self/status. If successful, it displays its size (in bytes) and its contents.
Next, it reads the contents of /proc/self/maps, reusing the previous buffer. If successful, it displays its size and contents as well.
Finally, the directory descriptor is closed as it is no longer needed, and the dynamically allocated buffer released.
Note that it is perfectly safe to do free(NULL), and also to discard the dynamic buffer (free(data); data=NULL; size=0;) between the read_pseudofile_at() calls.
Because pseudofiles are typically small, the read_pseudofile_at() uses a linear dynamic buffer growth policy. If there is no previous buffer, it starts with 8160 bytes, and grows it by 4096 bytes afterwards until sufficiently large. Feel free to replace it with whatever growth policy you prefer, this one is just an example, but works quite well in practice without wasting much memory.

Problem with writing from kernel to user space - linux device driver

I'm trying to write a simple Raspberry Pi GPIO driver, with four switches connected to four of the GPIO pins, that reads each switch state. The problem is, I'm not sure how to write from kernel to user space, I'm not getting anything when I insert my device kernel module and try to read the device file with cat command.
The device_read function is as follows:
static ssize_t gpio_driver_read(struct file *filp, char *buf, size_t len, loff_t *f_pos)
{
/* Size of valid data in gpio_driver - data to send in user space. */
int data_size = 0;
/* Counter for 'for' loop. */
int i;
/* Print to kernel space. */
printk(KERN_INFO "Reading active Switch state...\n");
for (i = 0; i < 4; i = i+1)
{
printk(KERN_INFO "Loop number %d...\n", i);
/* TODO: fill gpio_driver_buffer here. */
if (i == 0 && mySwitches[0])
sprintf(gpio_driver_buffer, "gpio_driver: gpio12 value: %d\n", GetGpioPinValue(GPIO_12));
else if (i == 1 && mySwitches[1])
sprintf(gpio_driver_buffer, "gpio_driver: gpio16 value: %d\n", GetGpioPinValue(GPIO_16));
else if (i == 2 && mySwitches[2])
sprintf(gpio_driver_buffer, "gpio_driver: gpio20 value: %d\n", GetGpioPinValue(GPIO_20));
else if (i == 3 && mySwitches[3])
sprintf(gpio_driver_buffer, "gpio_driver: gpio21 value: %d\n", GetGpioPinValue(GPIO_21));
printk(KERN_INFO "%s\n", gpio_driver_buffer);
/* Get size of valid data. */
data_size = strlen(gpio_driver_buffer);
printk(KERN_INFO "%d\n", data_size);
/* Send data to user space. */
if (copy_to_user(buf, gpio_driver_buffer, data_size) != 0)
{
return -EFAULT;
}
}
return 0;
}
gpio_driver_buffer is an array of some default size (I put it to 80).
mySwitches is an array of 4 elements, each one with value 0 or 1 (I'm passing that as an argument when inserting the kernel module, 1 meaning I want to watch the state of the switch and 0 meaning I'm not watching the switch).
GetGpioPinValue is a function that returns switch state.
The problem is, when I try to read the device file with cat command, I'm not getting anything. However, as you can see, I kind of debugged the program with printk commands and everything is written correctly in kernel space. Where could the problem be?
It doesn't look like you are ever writing to the actual file. Since you don't mention how you are generating the file, I'm assuming you are writing to an arbitrary file, not one created by the driver for /proc or something.
Review the post here: Read/write files within a Linux kernel module
You can try this:
int file_write(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)
{
mm_segment_t oldfs;
int ret;
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_write(file, data, size, &offset);
set_fs(oldfs);
return ret;
}
Then call it instead of 'copy_to_user':
/* Send data to user space. */
if (file_write(filep, 0, gpio_driver_buffer, data_size) != 0)
{
return -EFAULT;
}
Have a look at the sample code here.

Creation of file under /proc and using it

I'm trying to understand some example code my lecturer gave me.
It is a method of transferring data from user space into kernel space via a /proc file. This is the only code he gave me and I feel like I'm missing the user space program and I don't think he's explained what's going on very well.
He's trying to demonstrate locking files via semaphores, and also transferring the data I believe. The things I'm struggling to understand are:
what is the "reference count" (He mentions it in the comments for procfs_open and procfs_close)
Why would he use a proc file? It appears to do nothing.
What do module_put and try_module_get do? I can't find any remotely good explanations online.
How would I trigger the kernelWrite function from userspace? So that I know how I can actually transfer the data, not just receive it.
Here is the code:
#define BUFFERLENGTH 256
#define INCREASE_COUNTER 'I'
#define SHOW_COUNTER 'S'
#define PROC_ENTRY_FILENAME "kernelWrite"
DECLARE_RWSEM(counter_sem); /* semaphore to protect counter access */
static struct proc_dir_entry *Our_Proc_File;
int counter1 = 0;
int counter2 = 0;
/* displays the kernel table - for simplicity via printk */
void show_table (void) {
int tmp1;
int tmp2;
down_read (&counter_sem); /* lock for reading */
tmp1 = counter1;
tmp2 = counter2;
up_read (&counter_sem); /* unlock reading */
printk (KERN_INFO "kernelWrite:The counters are %d, %d\n", tmp1, tmp2);
}
void increase_counter (void) {
down_write (&counter_sem); /* lock for writing */
counter1++;
counter2++;
up_write (&counter_sem);
}
/* This function reads in data from the user into the kernel */
ssize_t kernelWrite (struct file *file, const char __user *buffer, size_t count, loff_t *offset) {
char command;
printk (KERN_INFO "kernelWrite entered\n");
if (get_user (command, buffer)) {
return -EFAULT;
}
switch (command) {
case INCREASE_COUNTER:
increase_counter ();
break;
case SHOW_COUNTER:
show_table ();
break;
default:
printk (KERN_INFO "kernelWrite: Illegal command \n");
}
return count;
}
/*
* The file is opened - we don't really care about
* that, but it does mean we need to increment the
* module's reference count.
*/
int procfs_open(struct inode *inode, struct file *file)
{
printk (KERN_INFO "kernelWrite opened\n");
try_module_get(THIS_MODULE);
return 0;
}
/*
* The file is closed - again, interesting only because
* of the reference count.
*/
int procfs_close(struct inode *inode, struct file *file)
{
printk (KERN_INFO "kernelWrite closed\n");
module_put(THIS_MODULE);
return 0; /* success */
}
const struct file_operations File_Ops_4_Our_Proc_File = {
.owner = THIS_MODULE,
.write = kernelWrite,
.open = procfs_open,
.release = procfs_close,
};
int init_module(void)
{
/* create the /proc file */
Our_Proc_File = proc_create_data (PROC_ENTRY_FILENAME, 0644, NULL, &File_Ops_4_Our_Proc_File, NULL);
/* check if the /proc file was created successfuly */
if (Our_Proc_File == NULL){
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
PROC_ENTRY_FILENAME);
return -ENOMEM;
}
printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_FILENAME);
return 0; /* success */
}
void cleanup_module(void)
{
remove_proc_entry(PROC_ENTRY_FILENAME, NULL);
printk(KERN_INFO "/proc/%s removed\n", PROC_ENTRY_FILENAME);
printk(KERN_INFO "kernelWrite:Proc module unloaded.\n");
}
Several questions, several answers:
1 Module reference count and try_module_get and module_put:
Each kernel module has usage count, in particular if it is referenced by any other module or used any other way. In this case, when doing opening file it will prevent module from being removed, and after closing the file, it will remove reference. Why it should not be used is explained here
2 Proc file:
Uses File_Ops_4_Our_Proc_File structure. You need to perform action in user space to trigger appropriate action on proc file (namely open, close and write).
3 Triggering actions.
For example (from bash):
echo 'I' > /proc/kernelWrite
Which writes character 'I' to proc file, triggering File_Ops_4_Our_Proc_File.write, effectively calling kernelWrite.

Return value from file_operations.write is not respected

I am writing a simple misc device driver for the linux kernel.
In my file_operations.write I do few checks and compare the passed value with a pre defined value, if the value are equal I return the string length, If not I return -EINVAL
The problem is that even that I print the return value before leaving the write, and it is printed in the log as -22, in my client program that I test with I keep getting the count of bytes passed to the write system call. !
Below is a sample from my write function:
ssize_t misc_write(struct file *filp, const char __user *buff,
size_t count, loff_t *offp)
{
ssize_t retval;
pr_crit("count: %zu\n", count);
pr_crit("strlen(MY_UNIQUE_ID) + 1: %zu\n", strlen(MY_UNIQUE_ID) + 1);
printk(KERN_INFO "Inside write \n");
if (count != (strlen(MY_UNIQUE_ID) + 1)) {
retval = - EINVAL;
pr_crit("retval: %i\n", retval);
goto out;
}
if (strncmp(MY_UNIQUE_ID, buff, count))
retval = -EINVAL;
else
retval = count;
out:
pr_crit("retval: %i\n", retval);
return retval;
}
Below is my test client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[] = "0daf007211a9";
char filename[] = "/dev/misctest";
int string_size, write_size;
FILE *handler = fopen(filename, "r+");
if (handler == 0)
{
printf("error openning file\n");
return -1;
}
write_size = fwrite(&buffer, sizeof(char), 2, handler);
if (write_size < 0)
printf("Error");
printf("write_size: %i\n", write_size);
return 0;
}
And this is what is printed in the kernel logs:
[793868.964583] count: 2
[793868.964593] strlen(MY_UNIQUE_ID) + 1: 13
[793868.964596] Inside write
[793868.964600] retval: -22
[793868.964602] retval: -22
When testing kernel stuff, always use as low level user space api as possible. If you were using write() (the system call) everything would be fine (you will get your error code out). But you decided to go with the more complicated fwrite() function which does something different (http://linux.die.net/man/3/fwrite):
On success, fread() and fwrite() return the number of items read or
written. This number equals the number of bytes transferred only when
size is 1. If an error occurs, or the end of the file is reached, the
return value is a short item count (or zero).
fread() does not distinguish between end-of-file and error, and callers
must use feof(3) and ferror(3) to determine which occurred.
In fact, fwrite() could not possibly return a negative value even if it wanted too (check out its signature).

Bad File Descriptor on a serial port

I'm implementing a simple protocol to do file transfer between 2 PC's over serial port and I'm getting a weird error.
On the main I call a function "llopen":
int
llopen(int port, int type) {
int fd = 0;
char* PORT;
PORT = malloc( sizeof(char) * (strlen(COM) + 1) );
sprintf(PORT,"%s%d",COM,port);
fd = initialization(PORT); // Open(...): returns a file descriptor!
switch(type) {
case SENDER:
return connectSender(fd);
break;
case RECEIVER:
return connectReceiver(fd);
break;
}
return fd; // The fd value here is 5
}
After that, I call a function llwrite(int fd, ...) to write a string to the file descriptor, but I'm getting an error: "Bad file descriptor" on llwrite(int fd, ...). If I call again the initialization(port) function, before that, it works and it writes the N bytes on the file descriptor, but if I don't it gives to me the "Bad file descriptor" error again.
Here it is the llwrite(int fd, ...) function:
int
llwrite(int fileDescriptor, unsigned char* buffer, unsigned int length) {
// The fd value here is 5
return writeBuffer(fileDescriptor,buffer,length);
}
Even before the return statement if I call, for instance, the tcflush(...) function I'm getting the "Bad file descriptor" error.
Any clue? Thanks in advance!
EDIT:
The problem is solved.
llopen(...) was wrong. I was returning the number of bytes wrote on the ConnectReceiver(...) / ConnectSender(...) and not the file descriptor
Now it's right:
int
llopen(int port, int type) {
int fd = 0;
char* PORT;
PORT = malloc( sizeof(char) * (strlen(COM) + 1) );
sprintf(PORT,"%s%d",COM,port);
fd = initialization(PORT); // Open(...): returns a file descriptor!
switch(type) {
case SENDER:
if( connectSender(fd) > 0 ) return fd;
case RECEIVER:
if( connectReceiver(fd) > 0 ) return fd;
}
return -1;
}
There's not really enough information here, but it's worth a shot noting that you do
return connectSender(fd);
break;
The break there is dead code, since the return stops execution of the function. Perhaps you didn't mean to return?
If that's not the case try using strace to get more details about what's going on. If you're not on linux other OSes should have similar tools, such as dtruss or ktrace.

Resources