Reading a configfs file - file

I am writing an user space process that will read data from the configfs entry continuously. I have defined callback function for read in kernel.
When I invoke read in a loop, only for the first time callback is called and for the next iterations control is not hitting the callback.
Kernel callback for read is simple function that will return a character.
static ssize_t show(struct config_item *item, char *page)
{
static char a = 'a';
printk("reading data\n");
page[0] = a++;
return 1;
}
User space process will read the data and display it on the screen.
int main()
{
int fd = open("/sys/kernel/config/sample/showme", O_RDONLY);
int ret;
int i = 5;
char receive[8];
if (fd < 0) {
perror("Failed to open the device...");
return errno;
}
while(i--) {
ret = read(fd, receive, 1);
if (ret < 0) {
perror("Failed to read the message\n");
return errno;
}
printf("Message is %x with size %d\n", receive[0], ret);
}
close(fd);
}
output:
Message is 61 with size 1
Message is 61 with size 0
Message is 61 with size 0
Message is 61 with size 0
Message is 61 with size 0
Note: The flow goes well if I close and open the file for all reads.
How to fix the above problem? I want the data to be reflected on all read.

A file under configfs filesystem is interpreted as an attribute, which have specific finite content at any moment.
E.g., a file may have content:
"123" at moment 1ns
"abc" at moment 2ns
"" (empty) at moment 3ns
and so on.
Moreover, configfs filesystem ensures, that after opening the file, any read() performed by the user will see portion of data consistent with other read()s. Assuming the example above, user won't read first symbol "1" (as at moment 1ns), 2nd symbol "b" (as at moment 2ns) and then found 3d symbol to be absent (as at moment 3ns).
So, after opening the file, .show() method is called once, and is expected to return whole content of the file. This content (or an appropriate portion of it) is returned upon futher read requests from the user.
Consistency guarantee is cleared at closing the file; so when you open it again, .show() will be called once more, and user's read requests will return updated content of the file.
I am writing an user space process that will read data from the configfs entry continuously.
With this semantic abstraction of finite file's content is lost, so you cannot implement that for configfs files.
However, you may implement this semantic with any "general" filesystem, which allows directly to set file_operations callbacks. You may create a file, e.g., under debugfs (/sys/kernel/debug/):
ssize_t my_read (struct file * filp, char __user * buf, size_t size, loff_t * offp)
{
static char a = 'a';
printk("reading data\n");
a++;
copy_to_user(buf, &a, 1);
return 1;
}
struct file_operations my_ops = {
.owner = THIS_MODULE,
.read = &my_read
};
int module_init(void)
{
debugfs_create_file("showme", S_IRUGO, NULL, NULL, &my_ops);
...
}

Related

How can I Execute/Call a user-space defined function from Linux kernel space module?

I am developing a Linux module which I want to use to run my C program from kernel mode.
My problem here, in function read() of the module, I need to use a function named eval_keycode(), which is defined in my user space program.
When I try to compile my module, this error occurs :
error: implicit declaration of function ‘eval_keycode’
which is confirming my problem described above.
This is the read() function of my module :
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
struct file *f = pfile->private_data;
enum { MAX_BUF_SIZE = 4096 };
size_t buf_size = 0;
char *buf = NULL;
ssize_t total = 0;
ssize_t rc = 0;
struct input_event *ev;
int yalv;
/* Allocate temporary buffer. */
if (length) {
buf_size = min_t(size_t, MAX_BUF_SIZE, length);
ev = kmalloc(buf_size, GFP_KERNEL);
if (ev == NULL) {
return -ENOMEM;
}
}
/* Read file to buffer in chunks. */
do {
size_t amount = min_t(size_t, length, buf_size);
rc = kernel_read(f, ev, amount, offset);
if (rc > 0) {
/* Have read some data from file. */
if (copy_to_user(buffer, ev, rc) != 0) {
/* Bad user memory! */
rc = -EFAULT;
} else {
/* Update totals. */
total += rc;
buffer += rc;
*offset += rc;
length -= rc;
for (yalv = 0; yalv < (int) (rc / sizeof(struct input_event)); yalv++) {
if (ev[yalv].type == EV_KEY) {
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
if (rc < amount) {
/* Didn't read the full amount, so terminate early. */
rc = 0;
}
}
}
}
while (rc > 0 && length > 0);
/* Free temporary buffer. */
kfree(buf);
if (total > 0) {
return total;
}
return rc;
}
This is my user space eval_keycode() defined function :
void eval_keycode(int code)
{
static int red_state = 0;
static int green_state = 0;
switch (code) {
case 260:
printf("BTN left pressed\n");
/* figure out red state */
red_state = red_state ? 0 : 1;
change_led_state(LED_PATH "/" red "/brightness", red_state);
break;
case BTN_RIGHT:
printf("BTN right pressed\n");
/* figure out green state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
How can call the eval_keycode function from user space in order to solve this problem ?
Thank you.
You can, but it is a really bad idea. You need to establish a pointer to your user mode function, arrange for the process containing that function to be running (in the kernel) when you invoke it. That is a lot of work, and is fundamentally malware due to the security holes it creates. Additionally, in the mad dash to lock the door to the now empty barn in the wake of spectre et al, new layers of hackery are being deployed in newer CPUs to make this even harder.
A different approach:
In your original query, you are running this driver as a "tee"; that is, you take the input you receive from the device, give a copy to the caller, and call eval_keycode with each input. Eval_keycode doesn't modify the data, and the kernel module discards it afterwards. So Eval_keycode doesn't really need to be a function; or rather, there could be a user function:
void ProcessEvents(int fd) {
struct input_event ev;
while (read(fd, &ev, sizeof ev) == sizeof ev) {
eval_keycode(&ev);
}
}
if you could arrange for all the events to be fed into that fd. With this setup, your problem becomes more plumbing than kernel renovation. The user creates a pipe/socket/fifo/... and passes the write end to your kernel module (yay more ioctl()s). Your kernel module can then carefully use kernel_write() ( or vfs_write if you are stuck in the past ) to make these events available to the user handler. It wants to be careful about where its blocking points are.
You could extend this to work as a transform; that is where your driver transforms the events via a user mode handler; but at that point, you might really consider FUSE a better solution.
There is no traditional (in the way a library works) way to "call" a user space "function".
Your user space code should be running in its' own process (or another user space process), in which you would implement communications (through shared memory, interprocess calls [IPC], device files, interrupts..) where you handle the exchange of data, and act on the data (e.g. calling your eval_keycode function).
You basically want an upcall. You can find some explanation about that here, but it doesn't seem like Linux has an official upcall API.
However, as others have already mentioned, this isn't very good design. Upcalls are useful to servers implemented in the kernel.
If your exer_read() is only called for your own code (on your files for which you're implementing the driver), then perhaps inotify would be a better design.
If your exer_read() can be called for any file (e.g. you want any file write on the machine to change the LED state), then you want your userspace process containing eval_keycode() to poll some character device, and you want your module to write the code to this character device instead of calling eval_keycode().
If, however, change_led_state() is synchronous, and you actually need the read to block until it returns, then you are advised to reconsider your design... but that's a valid use case for upcalls.

Is it possible to allow to use linux kernel module only for one process ?

I have linux kernel module, which get some info from user space application via device file and return some other data.
int *g_GlobalVariable;
static ssize_t dev_write(struct file* file, const char __user* buffer, size_t count, loff_t* pos)
{
int i;
int some_size = 10000;
char dev_buffer[64];
copy_from_user(dev_buffer, buffer, count);
g_GlobalVariable = kmalloc(kmalloc(some_size * sizeof(int), GFP_KERNEL);
for(i = 0; i < some_size; i++)
{
g_GlobalVariable[i] = 45; //any info
}
}
when user space application reads from device file, driver executes function dev_read.
static ssize_t dev_read(struct file* filep, char* buffer, size_t len, loff_t* offset)
{
//do something with g_GlobalVariable
}
I was thinking, that it is possible situation, that two or more processes use this driver and bad things can happen, for example:
1) first process pass data via device file and function dev_write generated and filled array g_GlobalVariable
2) first process read from device file, dev_read invoked and it works with g_GlobalVariable
3) second process writes into the same device file and g_GlobalVariable contains after that other information.
4) first process in dev_read get the wrong data, or read memory, which already doesn't exist.
How can I fix this situation ?

Unable to write the complete script onto a device on the serial port

The script file has over 6000 bytes which is copied into a buffer.The contents of the buffer are then written to the device connected to the serial port.However the write function only returns 4608 bytes whereas the buffer contains 6117 bytes.I'm unable to understand why this happens.
{
FILE *ptr;
long numbytes;
int i;
ptr=fopen("compass_script(1).4th","r");//Opening the script file
if(ptr==NULL)
return 1;
fseek(ptr,0,SEEK_END);
numbytes = ftell(ptr);//Number of bytes in the script
printf("number of bytes in the calibration script %ld\n",numbytes);
//Number of bytes in the script is 6117.
fseek(ptr,0,SEEK_SET);
char writebuffer[numbytes];//Creating a buffer to copy the file
if(writebuffer == NULL)
return 1;
int s=fread(writebuffer,sizeof(char),numbytes,ptr);
//Transferring contents into the buffer
perror("fread");
fclose(ptr);
fd = open("/dev/ttyUSB3",O_RDWR | O_NOCTTY | O_NONBLOCK);
//Opening serial port
speed_t baud=B115200;
struct termios serialset;//Setting a baud rate for communication
tcgetattr(fd,&serialset);
cfsetispeed(&serialset,baud);
cfsetospeed(&serialset,baud);
tcsetattr(fd,TCSANOW,&serialset);
long bytesw=0;
tcflush(fd,TCIFLUSH);
printf("\nnumbytes %ld",numbytes);
bytesw=write(fd,writebuffer,numbytes);
//Writing the script into the device connected to the serial port
printf("bytes written%ld\n",bytesw);//Only 4608 bytes are written
close (fd);
return 0;
}
Well, that's the specification. When you write to a file, your process normally is blocked until the whole data is written. And this means your process will run again only when all the data has been written to the disk buffers. This is not true for devices, as the device driver is the responsible of determining how much data is to be written in one pass. This means that, depending on the device driver, you'll get all data driven, only part of it, or even none at all. That simply depends on the device, and how the driver implements its control.
On the floor, device drivers normally have a limited amount of memory to fill buffers and are capable of a limited amount of data to be accepted. There are two policies here, the driver can block the process until more buffer space is available to process it, or it can return with a partial write only.
It's your program resposibility to accept a partial read and continue writing the rest of the buffer, or to pass back the problem to the client module and return only a partial write again. This approach is the most flexible one, and is the one implemented everywhere. Now you have a reason for your partial write, but the ball is on your roof, you have to decide what to do next.
Also, be careful, as you use long for the ftell() function call return value and int for the fwrite() function call... Although your amount of data is not huge and it's not probable that this values cannot be converted to long and int respectively, the return type of both calls is size_t and ssize_t resp. (like the speed_t type you use for the baudrate values) long can be 32bit and size_t a 64bit type.
The best thing you can do is to ensure the whole buffer is written by some code snippet like the next one:
char *p = buffer;
while (numbytes > 0) {
ssize_t n = write(fd, p, numbytes);
if (n < 0) {
perror("write");
/* driver signals some error */
return 1;
}
/* writing 0 bytes is weird, but possible, consider putting
* some code here to cope for that possibility. */
/* n >= 0 */
/* update pointer and numbytes */
p += n;
numbytes -= n;
}
/* if we get here, we have written all numbytes */

Write atomically to a file using Write() with snprintf()

I want to be able to write atomically to a file, I am trying to use the write() function since it seems to grant atomic writes in most linux/unix systems.
Since I have variable string lengths and multiple printf's, I was told to use snprintf() and pass it as an argument to the write function in order to be able to do this properly, upon reading the documentation of this function I did a test implementation as below:
int file = open("file.txt", O_CREAT | O_WRONLY);
if(file < 0)
perror("Error:");
char buf[200] = "";
int numbytes = snprintf(buf, sizeof(buf), "Example string %s" stringvariable);
write(file, buf, numbytes);
From my tests it seems to have worked but my question is if this is the most correct way to implement it since I am creating a rather large buffer (something I am 100% sure will fit all my printfs) to store it before passing to write.
No, write() is not atomic, not even when it writes all of the data supplied in a single call.
Use advisory record locking (fcntl(fd, F_SETLKW, &lock)) in all readers and writers to achieve atomic file updates.
fcntl()-based record locks work over NFS on both Linux and BSDs; flock()-based file locks may not, depending on system and kernel version. (If NFS locking is disabled like it is on some web hosting services, no locking will be reliable.) Just initialize the struct flock with .l_whence = SEEK_SET, .l_start = 0, .l_len = 0 to refer to the entire file.
Use asprintf() to print to a dynamically allocated buffer:
char *buffer = NULL;
int length;
length = asprintf(&buffer, ...);
if (length == -1) {
/* Out of memory */
}
/* ... Have buffer and length ... */
free(buffer);
After adding the locking, do wrap your write() in a loop:
{
const char *p = (const char *)buffer;
const char *const q = (const char *)buffer + length;
ssize_t n;
while (p < q) {
n = write(fd, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1) {
/* Write error / kernel bug! */
} else
if (errno != EINTR) {
/* Error! Details in errno */
}
}
}
Although there are some local filesystems that guarantee write() does not return a short count unless you run out of storage space, not all do; especially not the networked ones. Using a loop like above lets your program work even on such filesystems. It's not too much code to add for reliable and robust operation, in my opinion.
In Linux, you can take a write lease on a file to exclude any other process opening that file for a while.
Essentially, you cannot block a file open, but you can delay it for up to /proc/sys/fs/lease-break-time seconds, typically 45 seconds. The lease is granted only when no other process has the file open, and if any other process tries to open the file, the lease owner gets a signal. (If the lease owner does not release the lease, for example by closing the file, the kernel will automagically break the lease after the lease-break-time is up.)
Unfortunately, these only work in Linux, and only on local files, so they are of limited use.
If readers do not keep the file open, but open, read, and close it every time they read it, you can write a full replacement file (must be on the same filesystem; I recommend using a lock-subdirectory for this), and hard-link it over the old file.
All readers will see either the old file or the new file, but those that keep their file open, will never see any changes.

linux virtual file as device driver

I write a linux char device driver to simulate a file. The data is stored in an array and I want to implement a "read-file"-handler...
static ssize_t data_read(struct file *f, char __user *buf, size_t count, loff_t *f_pos){
char *msg_pointer;
int bytes_read = 0;
if(vault.storage==NULL)
return -EFAULT;
msg_pointer = vault.storage + *f_pos;
while (count && (*f_pos < vault.size) ) {
put_user(*(msg_pointer++), buf++);
count--;
bytes_read++;
++*f_pos;
}
return bytes_read;
}
vault.storage is a pointer to a kmalloc-creation. If I test the code by copying with dd it works as expected, but when I want to open the file with C
if((fp_data = open("/dev/vault0", O_RDWR)) < 0){
perror("could not open file.\n");
}
err = write(fp_data, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 36);
if (err < 0){
perror("failed to write to sv \n");
}
read(fp_data, buffer, 36);
read(fp_data, buffer, 36);
the first read-command returns 4.. the second 0 - how is this possible?
write performed on a file is not guaranteed to write all the bytes requested atomically ... that is only reserved for a pipe or FIFO when the requested write-amount is less than PIPE_BUF in size. For instance, write can be interrupted by a signal after writing some bytes, and there will be other instances where write will not output the full number of requested bytes before returning. Therefore you should be testing the number of bytes written before reading back any information into a buffer to make sure you are attempting to read-back the same number of bytes written.
Put a printk in the data_read call and print the count and print what is returned to the user(check the value of bytes_read). The bytes_read is returned to the read() call in the use space. Make sure you are returning correct value. And you can also print the fpos and check what is happening.
Here I assume that your drivers read and write functions are called properly, I mean major and minor numbers of your device file belongs to your driver

Resources