Synchronizing a usermode application to a kernel driver - c

We have a driver that schedules work using a timer (using add_timer). Whenever the work results in a change, an application should be notified of this change.
Currently this is done by providing a sysfs entry from the driver, that blocks a read operation until there is a change in the data.
(Please see the relevant code from the driver and the application in the code block below.)
I have inspected the source of most functions related to this in the linux kernel (4.14.98), and I did not notice any obvious problems in dev_attr_show, sysfs_kf_seq_show,__vfs_read and vfs_read.
However in seq_read the mutex file->private_data->lock is held for the duration of the read:
https://elixir.bootlin.com/linux/v4.14.98/source/fs/seq_file.c#L165
Will this pose a problem?
Are there any other (potential?) problems that I should be aware of?
Please note that:
The data will change at least once per second, usually way faster
The application should respond as soon as possible to a change in the data
This runs in a controlled (embedded) environment
// driver.c
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int xxx_block_c = 0;
// driver calls this to notify the application that something changed (from a timer, `timer_list`)
void xxx_Persist(void)
{
xxx_block_c = 1;
wake_up_interruptible(&wq);
}
// Sysfs entry that blocks until there is a change in the data.
static ssize_t xxx_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
wait_event_interruptible(wq, xxx_block_c != 0);
xxx_block_c = 0;
/* Remainder of the implementation */
}
//application.cpp
std::ifstream xxx;
xxx.open("xxx", std::ios::binary | std::ios::in);
while (true)
{
xxx.clear();
xxx.seekg(0, std::ios_base::beg);
xxx.read(data, size);
/* Do something with data */
}

Related

Managing UART buffer Thingy91

I have a Thingy91 Nordic device, and I am integrating it with a sensor that works at 1200 baud rate. It basically sends strings that i need to store in a buffer and parse for usage. However I am facing a peculiar issue wherein I am getting the correct string the 1st time I recieve data, but after that I recieve garbage values.
Below is the part of the code:
uint8_t message_buf[100];
void uart_cb(struct device *x) {
uart_irq_update(x);
if (uart_irq_rx_ready(x)) {
uart_fifo_read(x, message_buf, sizeof(message_buf));
printk("%s", message_buf);
}
}
void main(){
struct device *uart = device_get_binding(UART_PORT);
......
uart_irq_callback_set(uart, uart_cb);
......
}
We think that it might be a problem in managing the message_buf while getting the new string, and wanted to know the correct procedure of managing the buffer. Also,what could be the root cause that I get correct data on the first call and get garbage values later on.
Regards,
Adeel.
Looking at the API document:
static int uart_fifo_read(structdevice *dev, u8_t *rx_data, const int size)
Read data from FIFO.
This function is expected to be called from UART interrupt handler (ISR), if uart_irq_rx_ready() returns true. Result of calling this function not from an ISR is undefined (hardware-dependent). It’s unspecified whether “RX ready” condition as returned by uart_irq_rx_ready() is level- or edge- triggered. That means that once uart_irq_rx_ready() is detected, uart_fifo_read() must be called until it reads all available data in the FIFO (i.e. until it returns less data than was requested).
Returns: Number of bytes read.
Parameters:
dev: UART device structure.
rx_data: Data container.
size: Container size.
It clearly specifies that the API must be called until the return value is lesser than requested number of bytes (size).
Your code:
if (uart_irq_rx_ready(x)) {
uart_fifo_read(x, message_buf, sizeof(message_buf));
printk("%s", message_buf);
}
It calls uart_fifo_read() once and then exits the callback uart_cb, which deviates from what is recommended.
You should read from FIFO until it is empty:
int readBytes = 0;
if (uart_irq_rx_ready(x))
{
do{
readBytes += uart_fifo_read(x, &message_buf[readBytes], (sizeof(message_buf)-readBytes));
while(readBytes < sizeof(message_buf));
printk("Received %d bytes: ", readBytes);
// printk("%s", message_buf); // Certainly the code will crash if it isn't a string that fits in message_buf!
}

Linux kernel driver : polling on hardware register

I'm writing a Linux driver that aims to delegate some work to hardware accelerators. My driver writes some registers and memories to tell the hardware to do its job. Once the hardware is done, it will indicate so by setting a status register to 1. I do realize this is not how it should be done and that IRQ should be used instead and I'm planning to do so. But for now, I'm willing to do some polling on that register. And here I am, asking you smart people what's the best way to do so.
My hardware registers are mapped into kernel space using ioremap() and here is the code I'm struggling with :
int mailbox_request(const uint32_t *request, size_t request_size, struct mailbox_reply *reply)
{
size_t i;
int retval = 0;
if(down_interruptible(&sem))
return -ERESTARTSYS;
for(i = 0; i < request_size; i++)
iowrite32(mailbox + FIFO_OFFSET, request[i]);
iowrite32(mailbox + CONTROL_OFFSET, 1);
// WHAT SHOULD I DO HERE TO WAIT FOR THE RESULT ?
// while(ioread32(mailbox + STATUS_OFFSET) != 1); // better not do that...
reply->data = ioread32(mailbox + RESULT_OFFSET);
out:
up(&sem);
return retval;
}
My first idea was to use a workqueue and a waitqueue as follow :
static DECLARE_WORK(workqueue, mailbox_polling_result);
static DECLARE_WAIT_QUEUE_HEAD(wq);
static void mailbox_polling_result(struct work_struct *work)
{
while(ioread32(mailbox + STATUS_OFFSET) != 1)
msleep_interruptible(100);
wake_up_interruptible(&wq);
}
int mailbox_request(const uint32_t *request, size_t request_size, struct mailbox_reply *reply)
{
[...]
schedule_work(&workqueue);
wait_event_interruptible(wq, ioread32(mailbox + STATUS_OFFSET) == 1);
[...]
}
I'm not sure this is relevant, but just in case : the mailbox_request function won't necessarily be called from a process context. It might very well be called by the kernel itself. I read somewhere that workqueues are executed in a process context, that's why I'm telling you about that, to be sure this is not an issue.
Then I was wondering if the {work,wait}queue way of doing was not a bit overkill for what I'm trying to achieve ? I read somewhere about the schedule() function and I have to admit this a bit obscure to me. Would you consider that to be ok :
int mailbox_request(const uint32_t *request, size_t request_size, struct mailbox_reply *reply)
{
[...]
while(ioread32(mailbox + STATUS_OFFSET) != 1) {
schedule(); // or maybe some interruptible_sleep ?
}
[...]
}
The idea being to prevent the kernel from being stuck if it has better things to do. If you think of better ways to do that, I'd be glad to read about it !

Linux block device module is hanging when unloading with rmmod (del_gendisk)

I'm writing a little example for block device drivers in Linux. This example is not complete and I take progress step by step. I registered a block device with blkdev_register and allocated the gendisk structure with alloc_disk. All works fine, when inserting the module. It shows up in /proc/devices. But if I want to unload it with rmmod, it hangs.
I figured out, that in the module unload function, the call to del_gendisk caused the hanging. I know that the gendisk structure has an embedded kobject, which takes care of reference counting. This mechanism hinders you to unload the module, while it's being used. But since I don't call add_disk, there should be no reference's to that structure.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#define BLKDEVNAME "blkdev_test"
#define MINORS 16
struct block_device_operations bdops = {
.owner = THIS_MODULE
};
struct blkdev {
int major;
struct gendisk *disk;
struct request_queue *queue;
} dev;
static int __init blkdev_init(void)
{
dev.major = register_blkdev( 0, BLKDEVNAME );
if( dev.major < 0 )
return -EIO;
dev.disk = alloc_disk(MINORS);
if( dev.disk == NULL )
goto DISK_ERR;
dev.disk->major = dev.major;
dev.disk->first_minor = 0;
snprintf(dev.disk->disk_name, DISK_NAME_LEN, "bd0" );
dev.disk->fops = &bdops;
// dev.disk->queue = dev.queue;
// add_disk( dev.disk );
return 0;
DISK_ERR:
unregister_blkdev( dev.major, BLKDEVNAME );
return -EIO;
}
static void __exit blkdev_exit(void)
{
del_gendisk(dev.disk);
unregister_blkdev( dev.major, BLKDEVNAME );
}
module_init(blkdev_init);
module_exit(blkdev_exit);
MODULE_LICENSE("GPL");
If I issue the command sudo rmmod mod.ko then the command gets killed by the system.
Quoting :
Manipulating gendisks Once you have your gendisk structure set up, you
have to add it to the list of active disks; that is done with:
void add_disk(struct gendisk *disk);
After this call, your device is active. There are a few things worth
keeping in mind about add_disk():
add_disk() can create I/O to the device (to read partition tables and such). You should not call add_disk() until your driver is
sufficiently initialized to handle requests.
If you are calling add_disk() in your driver initialization routine, you should not fail the initialization process after the
first call.
The call to add_disk() increments the disk's reference count; if the disk structure is ever to be released, the driver is responsible
for decrementing that count (with put_disk()).
Should you need to remove a disk from the system, that is accomplished
with:
void del_gendisk(struct gendisk *disk);
This function cleans up all of the information associated with the
given disk, and generally removes it from the system. After a call to
del_gendisk(), no more operations will be sent to the given device.
Your driver's reference to the gendisk object remains, though; you
must explicitly release it with:
void put_disk(struct gendisk *disk);
That call will cause the gendisk structure to be freed, as long as no
other part of the kernel retains a reference to it.

How to modify kernel timer_list timeout

I am implementing a timeout for some parameters in my kernel module.
So I am using struct timer_list and Associated API's to implement a 12 sec timer.
So as mentioned in the IBM developer Works guide for kernel timers I use:
struct timer_list my_timer;
init_timer_on_stack(&my_timer);
void tick_timer()
{
my_timer.expires = jiffies + delay * HZ; //delay is global variable int = 12.
my_timer.data=0;
my_timer.function = my_timer_func;
add_timer(&my_timer);
}
So each time my timer expires I do my work in my_timer_func and call tick_timer again to reset the timer.
Next, I would like to implement the delay as a sysctl entry.
But the change should immediately call the tick_timer function and reset the timer with new delay. SO how can I detect this change and remove any current timer or reset it.
Should there be any kernel thread to detect the change in delay
Kernel has no mechanism for detect changes in variables. Instead, you should perform corresponded actions before/after your code changes your variable.
When you add sysctl entry, you also set handler for it(ctl_table->proc_handler). This handler defines actions, which are executed when read/write method for entry is called. Standard proc_do* functions only set/get value of variable, so you should define your handler. Something like this:
int my_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
// Call standard helper..
int res = proc_dointvec(table, write, buffer, lenp, ppos);
if(write && !res) {
// Additional actions on successfull write.
}
return res;
}
Modification of the timer's timeout can be performed using mod_timer function.

alternative to container_of()

I am a newbie trying to code a serial driver(PCI based ) and I don't want to use the container_of() for lack of downward compatibility.The kernel version I may compile the module
would be < 2.6.x so I want to make it compatible with most of the old and new versions.
i want to access the structure member(s) of a serial card driver.the structure is a custom one containing the atomic variable for example - use_count and the related operation on it-- atomic_inc(&serial_card->use_count).I dont want to access them by using the container_of() function which will give me the containing structure
Is there any alternate to container_of() function.If I am not wrong the text LINux device drivers by Allesandro Roubini describes a way on page no 174 | Chapter 6: Advanced Char Driver Operations.
But I am still fixed about how to assign something like struct scull_dev *dev = &scull_s_device.
if the structure itself contains a variable of type struct pc_device *dev,the above statement populates a similar variable and that is assigned to dev,
in my case i have declared a structure and related function as below
struct serial_card
{
unsigned int id; // to identify the each card
//atomic_t use_count; // variable used to check whether the device is already opened or not
wait_queue_head_t rx_queue[64]; // queue in which the process are stored
unsigned int data_ready[64]; // queue in which the process is ready
unsigned int rx_chan; // used by interrupt handler
unsigned int base, len; // holds physical base address , holds the total area ( for each card )
unsigned int *base; // holds virtual address
/*struct cdev cdev; // kernel uses this structure to represent the EACH char device
not using the new method to represent char devices in kernel instead using the old method of register_chrdev();*/
struct pci_dev *device; // pci_dev structure for EACH device.
//struct semaphore sem; //Semaphore needed to handle the co-ordination of processes,use incase need arises
};
static struct serial_card *serial_cards; // pointer to array of structures [ depending on number of cards ],NO_OF_CARDS #defined in header file
static int serialcard_open(struct inode *inode,struct file *filep)
{
//getting the structure details of type struct serialcard,using the pointer inode->i_cdev and field type cdev
//struct serial_card *serial_cards = container_of(inode->i_cdev, struct serial_card, cdev);
// read the current value of use_count
static int Device_Open = 0;
if ( Device_Open ) //Device_Open is static varibale used here for checking the no of times a device is opened
{
printk("cPCIserial: Open attempt rejected\n");
return -EBUSY;
}
Device_Open++;
// using the card so increment use_count
//atomic_inc(&serial_cards->use_count);
//filep->private_data = serial_cards;
return 0;
}
the complete description on page 174 - 175 is as follows
Single-Open Devices
The brute-force way to provide access control is to permit a device to be opened by
only one process at a time (single openness). This technique is best avoided because it
inhibits user ingenuity. A user might want to run different processes on the same
device, one reading status information while the other is writing data. In some cases,
users can get a lot done by running a few simple programs through a shell script, as
long as they can access the device concurrently. In other words, implementing a singleopen
behavior amounts to creating policy, which may get in the way of what your
users want to do. Allowing only a single process to open a device has undesirable properties, but it is also the easiest access control to implement for a device driver, so it’s shown here.
The source code is extracted from a device called scullsingle.
The scullsingle device maintains an atomic_t variable called scull_s_available; that
variable is initialized to a value of one, indicating that the device is indeed available.
The open call decrements and tests scull_s_available and refuses access if somebody
else already has the device open:
static atomic_t scull_s_available = ATOMIC_INIT(1);
static int scull_s_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev = &scull_s_device; /* device information */
if (! atomic_dec_and_test (&scull_s_available)) {
atomic_inc(&scull_s_available);
return -EBUSY; /* already open */
}
/* then, everything else is copied from the bare scull device */
if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
scull_trim(dev);
filp->private_data = dev;
return 0; /* success */
}
The release call, on the other hand, marks the device as no longer busy:
static int scull_s_release(struct inode *inode, struct file *filp)
{
atomic_inc(&scull_s_available); /* release the device */
return 0;
}
Normally, we recommend that you put the open flag scull_s_available within the
device structure (Scull_Dev here) because, conceptually, it belongs to the device. The
scull driver, however, uses standalone variables to hold the flag so it can use the same
device structure and methods as the bare scull device and minimize code duplication.
Please let me know any alternative for this
thanks and regards
perhaps I am missing the point, but "cotainer_of" is not a function, but a macro. If you have porting concerns, you can safely define it by yourserlf if the system headers don't implement it. Here a basic implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif
Or here's the implementation - more accurate - from recent linux headers:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
In that code the containerof is used to store and retrieve the correct dev structure easily. The correct structure can be retrieved inside the read and write functions also without accessing to the private_data.
I do not know why you do not want to use private->data and containerof, but you can always retrieve your minor number from the struct file pointer.
int minor=MINOR(filp->f_dentry_d_inode->i__rdev);
then accessing to your multiple devices vector using something like
struct scull_dev* dev = &scull_devices[minor]:
and using it.
You will need to use filp->privatedata to store "per-open" information that you also use in read/write. You will need to decide what to store to ensure that the right information is available.
Probably you want two structures. One "device structure" and one "open structure". The open structure can get dynamically allocated in "open" and stored at private_data. In release, it gets freed. It should have the members such that you can use them in read/write to get access to the data you need.
The device structure is going to be per "card". In your driver init, you probably want to loop on the number of cards and create a new device structure (serial_card) for each. You can make them a static array, or dynamically allocate, it doesn't matter. I would store the minor number in the structure as well. The minor number is chosen by you, so start with 1 and go through #cards. You can reserve "0" for a system level interface, if you want, or just start at 0 for the cards.
In open, you will get the minor number that the user opened. Go through your serial_card list looking for a match. If you don't find it, error out of open. Otherwise, you have your info and can use it to allocate a "open structure", populate it, and store it in filp->private_data.
#Giuseppe Guerrini Some compiler just cannot recognize the linux implementation of container_of.
The basic define is fine, but I wonder if there is any safety or compatibility risk at this implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif

Resources