Linux Character device: userspace (cat) does not stop reading - linux-kernel

I made a simple character device, and created a node for communicating with it. When I cat /dev/mychrdev, it userspace invokes my character device's read function over and over again. The relevant code is:
static ssize_t useless_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) {
int ret, read_count;
read_count = sprintf(message, "Major number: %d\n", MAJOR(useless_chr_dev->cdev_num));
ret = copy_to_user(buff, message, read_count);
if (ret == 0) {
printk(KERN_INFO "userspace read success");
return read_count;
} else
return -EFAULT;
}
After I initiate a read from the terminal, dmesg is filled with:
[ 8966.299554] userspace read success
and cat is giving out lots of
Major number: 242
Major number: 242
Major number: 242
Major number: 242
Why isnt it stopping ?

cat is not about calling your read function once. cat will keep calling the read function unless you return a 0 (i.e no more bytes to read).

Related

Return value of call_usermodehelper() is not correct

I am calling a user-space application, /usr/bin/myapp, from a Linux Kernel Module using call_usermodehelper(). The myapp returns 2228 when it exits. I should receive same value i.e 2228 as a return value of call_usermodehelper() in the kernel module. However, I am receiving a different value, that is 46080.
My question is, why I don't receive the value I return from myapp as the return value of call_usermodehelper()? Note, myapp executes successfully when I call it from kernel module using call_usermodehelper(). I don't return 0 as a success code. I return 2228 on exit.
Here is the sample code:
user-space's application code:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%s called successfully\n", argv[0]);
return 2228;
}
Kernel Module's Code:
int call_userspaceapp()
{
int ret = -EPERM;
char *argv[] = {"/usr/bin/myapp", "11", "22", "33", NULL};
char *envp[] = {"HOME=/", NULL};
ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
printk("%s returns value %d", argv[0], ret);
return ret;
}
However, I am receiving a different value, that is 46080.
Exit status has 8 bits and return value is just like waitpid return value. See userspace definition of WEXITSTATUS to access the exit status, which is 46080 >> 8 = 180, which is equal to the returned exit status 2228 % 256 = 180. Here drbd_nl.c I found an example of call_usermodehelper that also accesses the exit status with (ret >> 8) && 0xff, just like WEXITSTATUS.

copy_to_user not copying data?

for a project we are reading and writing data from an embedded FPGA on a SoC system. Writing works (for now just 1 byte, but oh well). The read function correctly accesses the FPGA (and gets the correct value) but for some reason the copy_to_user does not copy anything to the user. Running cat on my device doesn't not return anything. I hope somebody can tell me where I'm doing something wrong.
Additional information: We're targeting a Altrera Cyclone V SoC system with a ARMv7 Processor. We're using a buildroot system with kernel 4.3.0 as recommended by Altera.
Code:
// Read function is called whenever a read in performed on one of the /dev devices
static ssize_t mydevice_read(struct file *file, char *buffer, size_t len, loff_t *offset) {
int success = 0;
u32 read_value32 = 0;
// Get the device struct out of the miscdev struct
struct mydevice_dev *dev = container_of(file->private_data, struct mydevice_dev, miscdev);
// Read data from FPGA
read_value32 = ioread32(dev->regs);
pr_info("Data received from FPGA: %d", read_value32);
success = copy_to_user(buffer, &read_value32, sizeof(read_value32));
pr_info("%d: %d bytes copied to userspace pointer 0x%p, value: %d!\n", success, sizeof(read_value32), buffer, dev->data_value8);
// If copy_to_user failed
if (success != 0) {
pr_info("Failed to copy current value to userspace!\n");
return -EFAULT;
}
return 0;
}
Output (including kernel messages and debug prints):
# insmod mymodule.ko
[ 701.922707] Initializing mymodule module
[ 701.926681] Probing for fpga devices...
[ 701.931382] Probing successful!
[ 701.935429] FPGA successfully initialized!
# echo -n -e \\x81 > /dev/mydevice
# cat /dev/mydevice
[ 721.555795] Data received from FPGA: 129
[ 721.559539] 0: 4 bytes copied to userspace pointer 0xbec67c78, value: 129!
Thanks a bunch!
Are you sure about return 0;? I think this function should return the amount of bytes copied, in your case this should be return sizeof(read_value32);

How to determine if there are bytes available to be read from boost:asio:serial_port

I am trying to use boost to communicate serially between my desktop and an arduino. In arduino space, I can ask the serial port whether or not there are bytes available before trying to perform a read.
I am having trouble finding the equivalent for boost::asio::serial_port.
While Boost.Asio does not provide direct support for this, one can still accomplish this by using serial port's native_handle() with system specific calls. Consult the system's documentation to determine how to query for the available bytes ready to be read, but it is often ioctl(..., FIONREAD, ...) on Linux, and ClearCommError() on Windows.
Here is a complete minimal example that uses system specific calls to get the number of bytes available. The example program will continue to query the serial port until there are greater than 20 bytes available, at which point it will read all but 5 bytes:
#include <iostream>
#include <vector>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
/// #brief Returns the number of bytes available for reading from a serial
/// port without blocking.
std::size_t get_bytes_available(
boost::asio::serial_port& serial_port,
boost::system::error_code& error)
{
error = boost::system::error_code();
int value = 0;
#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
COMSTAT status;
if (0 != ::ClearCommError(serial_port.lowest_layer().native_handle(),
NULL, &status))
{
value = status.cbInQue;
}
// On error, set the error code.
else
{
error = boost::system::error_code(::GetLastError(),
boost::asio::error::get_system_category());
}
#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
if (0 == ::ioctl(serial_port.lowest_layer().native_handle(),
FIONREAD, &value))
{
error = boost::system::error_code(errno,
boost::asio::error::get_system_category());
}
#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
return error ? static_cast<std::size_t>(0)
: static_cast<size_t>(value);
}
/// #brief Returns the number of bytes available for reading from a serial
/// port without blocking. Throws on error.
std::size_t get_bytes_available(boost::asio::serial_port& serial_port)
{
boost::system::error_code error;
std::size_t bytes_available = get_bytes_available(serial_port, error);
if (error)
{
boost::throw_exception((boost::system::system_error(error)));
}
return bytes_available;
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " <device_name>" << std::endl;
return 1;
}
// Create all I/O objects.
boost::asio::io_service io_service;
boost::asio::serial_port serial_port(io_service, argv[1]);
// Continue quering the serial port until at least 20 bytes are available
// to be read.
std::size_t bytes_available = 0;
while (bytes_available < 20)
{
bytes_available = get_bytes_available(serial_port);
std::cout << "available: " << bytes_available << std::endl;
boost::this_thread::sleep_for(::boost::chrono::seconds(3));
}
// Read all but 5 available bytes.
std::vector<char> buffer(bytes_available - 5);
std::size_t bytes_transferred =
read(serial_port, boost::asio::buffer(buffer));
bytes_available = get_bytes_available(serial_port);
// Print results.
std::cout << "Read " << bytes_transferred << " bytes\n";
std::cout.write(&buffer[0], bytes_transferred);
std::cout << "\navailable: " << bytes_available << std::endl;
}
Create virtual serial ports with socat:
$ socat -d -d PTY: PTY
2015/02/01 21:12:31 socat[3056] N PTY is /dev/pts/2
2015/02/01 21:12:31 socat[3056] N PTY is /dev/pts/3
2015/02/01 21:12:31 socat[3056] N starting data transfer loop
with FDs [3,3] and [5,5]
After starting the program in one terminal, I write to /dev/pts/3 in another terminal:
$ echo -n "This is" > /dev/pts/3
$ echo -n " an example" > /dev/pts/3
$ echo -n " with asio." > /dev/pts/3
And the resulting output from the program:
$ ./a.out /dev/pts/2
available: 0
available: 7
available: 18
available: 29
Read 24 bytes
This is an example with
available: 5
I don't know of such a thing in asio, but as comments above have already stated, you don't really need it. I have an example of how to use boost asio serial at:
https://github.com/cdesjardins/ComBomb/blob/master/TargetConnection/TgtSerialConnection.cpp
It uses async_read_some to fill a buffer with serial data, the buffer data is then queued up for other parts of the program to process.

Using an old device file for char device driver

I have two questions as I'm trying device drivers as a beginner.
I created one module , loaded it, it dynamically took major number 251 say. Number of minor devices is kept 1 only i.e minor number 0. For testing , I tried echo and cat on the device file (created using mknod) and it works as expected. Now if I unload the module but don't remove /dev entry and again load the module with same major number and try writing/reading to same device file which was used previously, kernel crashes. I know we shouldn't do this but just want to understand what happens in this scenario which causes this crash. I think something that VFS does.
When I do cat on device file, the read keeps on happening indefinitely. why? To stop that needed to use offset manipulation. This looks to be because buffer length is coming as 32768 as default to read?
EDIT: further in this I added one ioctl function as below, then I'm getting error regarding the storage class of init and cleanup function, which work well if no ioctl is defined. Not getting the link between ioctl and the init/cleanup functions' storage class. Updated code is posted. Errors are below:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:95:12: error: invalid storage class for function ‘flow_init’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_init’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:98:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_ioctl’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:112:13: error: invalid storage class for function ‘flow_terminate’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: error: invalid storage class for function ‘__inittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: invalid storage class for function ‘__exittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: expected declaration or statement at end of input
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: At top level:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:73:13: warning: ‘flow_ioctl’ defined but not used [-Wunused-function]
Below is the code:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#define SUCCESS 0
#define BUF_LEN 80
#define FLOWTEST_MAGIC 'f'
#define FLOW_QUERY _IOR(FLOWTEST_MAGIC,1,int)
MODULE_LICENSE("GPL");
int minor_num=0,i;
int num_devices=1;
int fopen=0,counter=0,ioctl_test;
static struct cdev ms_flow_cd;
static char c;
///// Open , close and rest of the things
static int flow_open(struct inode *f_inode, struct file *f_file)
{
printk(KERN_ALERT "flowtest device: OPEN\n");
return SUCCESS;
}
static ssize_t flow_read(struct file *f_file, char __user *buf, size_t
len, loff_t *off)
{
printk(KERN_INFO "flowtest Driver: READ()\nlength len=%d, Offset = %d\n",len,*off);
/* Check to avoid the infinitely printing on screen. Return 1 on first read, and 0 on subsequent read */
if(*off==1)
return 0;
printk(KERN_INFO "Copying...\n");
copy_to_user(buf,&c,1);
printk(KERN_INFO "Copied : %s\n",buf);
*off = *off+1;
return 1; // Return 1 on first read
}
static ssize_t flow_write(struct file *f_file, const char __user *buf,
size_t len, loff_t *off)
{
printk(KERN_INFO "flowtest Driver: WRITE()\n");
if (copy_from_user(&c,buf+len-2,1) != 0)
return -EFAULT;
else
{
printk(KERN_INFO "Length len = %d\n\nLast character written is - %c\n",len,*(buf+len-2));
return len;
}
}
static int flow_close(struct inode *i, struct file *f)
{
printk(KERN_INFO "ms_tty Device: CLOSE()\n");
return 0;
}
///* ioctl commands *///
static long flow_ioctl (struct file *filp,unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case FLOW_QUERY:
ioctl_test=51;
return ioctl_test;
default:
return -ENOTTY;
}
///////////////////File operations structure below/////////////////////////
struct file_operations flow_fops = {
.owner = THIS_MODULE,
.llseek = NULL,
.read = flow_read,
.write = flow_write,
.unlocked_ioctl = flow_ioctl,
.open = flow_open,
.release = flow_close
};
static int flow_init(void)
{
printk(KERN_ALERT "Here with flowTest module ... loading...\n");
int result=0;
dev_t dev=0;
result = alloc_chrdev_region(&dev, minor_num,
num_devices,"mod_flowtest"); // allocate major number dynamically.
i=MAJOR(dev);
printk(KERN_ALERT "Major allocated = %d",i);
cdev_init(&ms_flow_cd,&flow_fops);
cdev_add(&ms_flow_cd,dev,1);
return 0;
}
static void flow_terminate(void)
{
dev_t devno=MKDEV(i,0); // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
printk(KERN_ALERT "Going out... exiting...\n");
unregister_chrdev_region(devno,num_devices); //remove entry from the /proc/devices
}
module_init(flow_init);
module_exit(flow_terminate);
1- You're missing cdev_del() in your cleanup function. Which means the device stays registered, but the functions to handle it are unloaded, thus the crash. Also, cdev_add probably fails on the next load, but you don't know because you're not checking return values.
2- It looks ok... you modify offset, return the correct number of bytes, and then return 0 if offset is 1, which indicates EOF. But you should really check for *off >= 1.
EDIT-
The length passed into your read handler function comes all the way from user-land read(). If the user opens the device file and calls read(fd, buf, 32768);, that just means the user wants to read up to 32768 bytes of data. That length gets passed all the way to your read handler. If you don't have 32768 bytes of data to supply, you supply what you have, and return the length. Now, the user code isn't sure if that's the end of the file or not, so it tries for another 32768 read. You really have no data now, so you return 0, which tells the user code that it has hit EOF, so it stops.
In summary, what you're seeing as some sort of default value at the read handler is just the block size that the utility cat uses to read anything. If you want to see a different number show up at your read function, try using dd instead, since it lets you specify the block size.
dd if=/dev/flowtest of=/dev/null bs=512 count=1
In addition, this should read one block and stop, since you're specifying count=1. If you omit count=1, it will look more like cat, and try to read until EOF.
For 2, make sure you start your module as a char device when using mknod.
mknod /dev/you_device c major_number minor_number

Regarding how the parameters to the read function is passed in simple char driver

I am newbei to driver programming i am started writing the simple char driver . Then i created special file for my char driver mknod /dev/simple-driver c 250 0 .when it type cat /dev/simple-driver. it shows the string "Hello world from Kernel mode!". i know that function
static const char g_s_Hello_World_string[] = "Hello world tamil_vanan!\n\0";
static const ssize_t g_s_Hello_World_size = sizeof(g_s_Hello_World_string);
static ssize_t device_file_read(
struct file *file_ptr
, char __user *user_buffer
, size_t count
, loff_t *possition)
{
printk( KERN_NOTICE "Simple-driver: Device file is read at offset =
%i, read bytes count = %u", (int)*possition , (unsigned int)count );
if( *possition >= g_s_Hello_World_size )
return 0;
if( *possition + count > g_s_Hello_World_size )
count = g_s_Hello_World_size - *possition;
if( copy_to_user(user_buffer, g_s_Hello_World_string + *possition, count) != 0 )
return -EFAULT;
*possition += count;
return count;
}
is get called . This is mapped to (*read) in file_opreation structure of my driver .My question is how this function is get called , how the parameters like struct file,char,count, offset are passed bcoz is i simply typed cat command ..Please elabroate how this happening
In Linux all are considered as files. The type of file, whether it is a driver file or normal file depends upon the mount point where it is mounted.
For Eg: If we consider your case : cat /dev/simple-driver traverses back to the mount point of device files.
From the device file name simple-driver it retrieves Major and Minor number.
From those number(especially from minor number) it associates the driver file for your character driver.
From the driver it uses struct file ops structure to find the read function, which is nothing but your read function:
static ssize_t device_file_read(struct file *file_ptr, char __user *user_buffer, size_t count, loff_t *possition)
User_buffer will always take sizeof(size_t count).It is better to keep a check of buffer(In some cases it throws warning)
String is copied to User_buffer(copy_to_user is used to check kernel flags during copy operation).
postion is 0 for first copy and it increments in the order of count:position+=count.
Once read function returns the buffer to cat. and cat flushes the buffer contents on std_out which is nothing but your console.
cat will use some posix version of read call from glibc. Glibc will put the arguments on the stack or in registers (this depends on your hardware architecture) and will switch to kernel mode. In the kernel the values will be copied to the kernel stack. And in the end your read function will be called.

Resources