I wrote a kernel module which creates a /proc file. I also wrote an user space code which writes into the file and I fetch that written data to my module using "copy_from_user" method and print in the kernel logs.
The data is written successfully on the logs but when I open the proc file in an editor then its blank.
Can anyone explain me why this is so?
The user space code is
#include<fcntl.h>
main()
{
int fd=open("/proc/MY_PROC_FILE", O_RDWR);
write(fd, "linux is awesome", 16);
return 0;
}
The module is
int open_callback(struct inode *p, struct file *q)
{
printk(KERN_ALERT "open callback\n");
return 0;
}
ssize_t write_callback(struct file *p, const char __user *buffer, size_t len, loff_t *s)
{
printk(KERN_ALERT "write callback\n");
char msg[256];
copy_from_user(msg, buffer, len);
printk("%s\n", msg);
return 0;
}
static struct proc_dir_entry *my_proc_entry;
static struct file_operations fs={
.open=open_callback,
.read=read_callback,
.write=write_callback,
.release=release_callback
};
static int start(void)
{
printk(KERN_ALERT "proc module registered\n");
my_proc_entry=proc_create(file_name, 0, NULL, &fs);
if(my_proc_entry==NULL)
{
printk(KERN_ALERT "os error\n");
return -ENOMEM;
}
return 0;
}
static void stop(void)
{
remove_proc_entry(file_name, NULL);
printk(KERN_ALERT "proc module unregistered\n");
}
module_init(start);
module_exit(stop);
MODULE_LICENSE("GPL");
Thanks in advance for any help
You did not implemented read_callback()
when you gona read that proc file then that read_callback() will be called. Here you need to write code to write back(Using copy_to_user()) what was written earlier in write_callback() callback.
First you need to store what was written by user in write_callback() in some global memory for kernel space then on only you can write that back in read_callback()
This is best example of what you want to do. http://www.makelinux.net/books/lkmpg/x810
Related
I'm trying to create a simple character device LKM but I've been stuck for days trying to get my read and write to work correctly. Currently when I do something like:
echo hi > /dev/simple_character_device
I am able to see I'm writing the correct amount of bytes.
But when I attempt to cat out the contents of that device it will continuously loop hi until reaching a bad address. Currently I'm trying to keep track of how many bytes I've written in a global counter. But that doesn't seem right. Any help on implementing the read and write would be appreciated.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>
MODULE_LICENSE("GPL");
#define BUFFER 1024
char * buffer_data;
// Count open and closed
size_t current_count;
int my_open(struct inode *, struct file *);
int my_release(struct inode *, struct file *);
ssize_t my_read(struct file *, char __user *, size_t count, loff_t *);
ssize_t my_write(struct file *, const char __user *, size_t count, loff_t *offp);
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write
};
int reg_init(void)
{
// Allocate memory to store information
buffer_data = kmalloc(BUFFER, GFP_KERNEL); // Use Kernel Flag
register_chrdev(240, "simple_character_device", &fops);
printk(KERN_ALERT "Init Allocating Memory");
return 0;
}
void reg_exit(void)
{
// Free and unregister device and data
kfree(buffer_data);
unregister_chrdev(240, "simple_character_device");
printk(KERN_ALERT "Deregister Simple Character Device");
}
int my_open(struct inode *inode, struct file *file){
printk(KERN_ALERT "Open File Device.\n");
return 0;
}
int my_release(struct inode *inode, struct file *file){
printk(KERN_ALERT "Close File Device.\n");
return 0;
}
ssize_t my_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){
// Check if we are reading within the Buffer Size
if(BUFFER - *offp < 0){
printk(KERN_ALERT "Out of buffer range.\n");
return -EFAULT;
}
// Check if we fail to copy to user
if (copy_to_user(buff, buffer_data, current_count) != 0){
printk(KERN_ALERT "Failed to send character to user\n");
return -EFAULT;
}
(*offp) += current_count;
printk(KERN_ALERT "Read %zu bytes.\n", current_count);
return current_count;
}
ssize_t my_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){
// We need to get data FROM the user space
// Make sure we are reading within the buffer
if (*offp >= BUFFER || BUFFER - count < *offp){
printk(KERN_ALERT "ATTEMPTING TO WRITE TO OUSIDE OF BUFFER!\n");
return EFAULT;
}
// Get the amount of bytes from the user
copy_from_user(buffer_data + *offp, buff, count);
*offp += count;
printk(KERN_ALERT "Wrote %zu to the device.\n", count);
current_count = count;
return current_count;
}
module_init(reg_init);
module_exit(reg_exit);
In my_read() you must not allow reading the buffer after current_count (after the point where initialized data ends) . If the requested count goes farther you must first trim the passed count. If the resulting count is <= 0, or if the offset is after current_count you must return 0 to indicate end of file.
Also you must return the trimmed count (which was really copied to the user).
I expect that you test with echo and cat. But if you test with your own code, by reading and writing in sequence, don't forget to reset the offset using lseek() between reading and writing.
As far as I can tell your code looks like a good start but the counts and file position management require some cleanup.
Obviuosly, it's a unsuprising newbie's question after a lot of troubles with kernel programming. I try to launch a program that gets driver file in /dev folder available for some reading and writing (indeed, I realize it's rather unsafe idea, but I need strongly going ahead with all that experience). Let's look at a module source code:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
int init_module(void); // driver file initialization as opening it
void cleanup_module(void); // exec files removal ahead of shutting driver file
static int device_open(struct inode *, struct file *); // driver file opening
static int device_release(struct inode *, struct file *); // return of system resource control
static ssize_t device_read(struct file *, char *, size_t, loff_t *); // reading from driver file
static ssize_t device_write(struct file *, const char *, size_t, loff_t *); // writing into driver file
#define SUCCESS 1
#define DEVICE_NAME "sample device"
#define BUF_LEN 80
static int Major; // device's major number
static int Device_Open = 0; // device access counter
static char message[BUF_LEN]; // buffer for both read and write operations
static char *message_ptr;
// list of basic operations executable by driver
static struct file_operations ops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &ops); // major number assignment
// evaluate whether driver file is accessible
if(Major < 0) {
printk(KERN_ALERT "Device registration attempt failed\n");
return Major;
}
return SUCCESS;
}
void cleanup_module(void)
{
unregister_chrdev(Major, DEVICE_NAME); // cancelling driver registration in file system before exit
printk(KERN_ALERT "Driver file of /dev/%s c %d 0 has been destroyed\n", DEVICE_NAME, Major);
return;
}
static int device_open(struct inode * node, struct file * file)
{
printk(KERN_INFO "Trying access /dev/%s c %d 0\n", DEVICE_NAME, Major);
static int counter = 0; // access counter initializing
// file control evaluation
if(Device_Open)
return -EBUSY;
Device_Open++; // increment counter to avert driver's immanent running
sprintf(message, "This sentence displayed %d times\n", counter++);
message_ptr = message;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int device_release(struct inode * node, struct file * file)
{
printk(KERN_INFO "Trying closure of /dev/%s c %d 0\n", DEVICE_NAME, Major);
Device_Open--; // decrement counter to keep driver file removable as well
module_put(THIS_MODULE);
return SUCCESS;
}
static ssize_t device_read(struct file * file, char * ch, size_t num, loff_t * off)
{
int read_bytes = 0; // output size
printk(KERN_INFO "Trying read from /dev/%s c %d 0\n", DEVICE_NAME, Major);
if(*message_ptr == 0)
return 0;
// loop-executed reading from file
while(num && *message_ptr) {
put_user(*(message_ptr++), ch++);
num--;
read_bytes++;
}
printk("%d bytes read, %d bytes to be handled", read_bytes, num);
return read_bytes;
}
// updated stuff
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
char message_from_user[BUF_LEN];
if(copy_from_user(message_from_user, buff, len)) return -EINVAL;
printk(KERN_INFO "length of message:%d message:'%s'", (int)len, message_from_user);
return len;
}
To test reading/writing, I use this code:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <linux/unistd.h>
extern int errno;
int main()
{
int fd; // file descriptor id
size_t cnt = 0; // input / output number of bytes
size_t cnt_2 = 0;
char inputBuffer[30] = "Device file is open"; // write operation buffer
char outputBuffer[50]; // read operation buffer
printf("Continuing with basics of Linux drivers...\n");
// evaluate accessibility of driver file
fd = open("/dev/dev", O_RDWR);
if(fd == -1) {
close(fd);
printf("File opening isn't completed\n");
return 1;
}
printf("Driver file is open now\n");
// writing from file
cnt = write(fd, inputBuffer, sizeof(inputBuffer));
printf("Driver got written %d bytes\n", cnt);
// read into file
cnt = read(fd, outputBuffer, sizeof(outputBuffer));
printf("Driver received %d bytes\n", cnt);
int i = 0;
// display an input message
while(i < cnt) {
printf("%c", outputBuffer[i]);
printf("%s", "\n");
i++;
}
close(fd); // wrap up driver connection and clear memory
printf("Driver file is close\n");
return 0;
}
Altough the module was built in as well as dev file was made by mknod (I run it on Ubuntu 18.04), I'm stuck at write operation due to some miscomprehension of driver calls in user/kernel spaces. Once I start my program, outputs are here as follows:
Continuing with basics of Linux drivers...
Driver file is open now
Driver got written -1 bytes
Followed by last line output, the system becomes inoperable (no response until I make off PC). That's a case I think of like a matter of memory control or, most probably, some driver file properties. However, user rights have been granted to reading / writing / executing, no access restrictions are inferable indeed. Hopefully, it's possible to point out to what's wrongness in the code posted here.
Seeing your code you don't handle the writing part.
static ssize_t device_write(struct file * file, const char * ch, size_t num, loff_t * off)
{
printk(KERN_ALERT "Operation denied\n");
return -EINVAL;
}
Thus there is no way your module can possibly work.
But your crash comes from memory accesses in your reading function (check this with strace). I let you understand your issue. dmesg should help (or in the case your system panics you can make the log persistant to debug it after rebooting your system).
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.
Below is my kernel module,which I tested through C program but now instead of using c application I want to write a shell script which do read and write operation with my kernel module ?
Thanks in advance.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "mydevice"
#define CLASS_NAME "device"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ABC");
MODULE_DESCRIPTION("A simple Linux character driver");
MODULE_VERSION("0.1");
static int majorNumber;
static char message[256] = {0};
static short size_of_message;
static int numberOpens = 0;
static struct class* character_deviceClass = NULL;
static struct device* character_deviceDevice = NULL;
static int dev_open(struct inode *, struct file *);
static int dev_release(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
static ssize_t dev_write(struct file *, const char *, size_t, loff_t *);
static DEFINE_MUTEX(devicedev_mutex);
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
static int __init character_device_init(void){
printk(KERN_INFO "Shell: Initializing the character device LKM\n");
majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
if (majorNumber<0){
printk(KERN_ALERT "character device failed to register a major number\n");
return majorNumber;
}
printk(KERN_INFO "character device: registered correctly with major number %d\n", majorNumber);
character_deviceClass = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(character_deviceClass)){
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(character_deviceClass);
}
printk(KERN_INFO "character device: device class registered correctly\n");
character_deviceDevice = device_create(character_deviceClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
if (IS_ERR(character_deviceDevice)){
class_destroy(character_deviceClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(character_deviceDevice);
}
printk(KERN_INFO "character device: device class created correctly\n");
mutex_init(&devicedev_mutex);
return 0;
}
static void __exit character_device_exit(void){
mutex_destroy(&devicedev_mutex);
device_destroy(character_deviceClass, MKDEV(majorNumber, 0));
class_unregister(character_deviceClass);
class_destroy(character_deviceClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_INFO "character device: Goodbye from the LKM!\n");
}
static int dev_open(struct inode *inodep, struct file *filep){
if(!mutex_trylock(&devicedev_mutex))
{
printk(KERN_ALERT "Character device: Device in use by another process");
return -EBUSY;
}
numberOpens++;
printk(KERN_INFO "character device: Device has been opened %d time(s)\n", numberOpens);
return 0;
}
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
int error_count = 0;
error_count = copy_to_user(buffer, message, size_of_message);
if (error_count==0){
printk(KERN_INFO "character device: Sent %d characters to the user\n", size_of_message);
return (size_of_message=0);
}
else {
printk(KERN_INFO "character device: Failed to send %d characters to the user\n", error_count);
return -EFAULT;
}
}
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
sprintf(message, "%s(%d letters)", buffer, len);
size_of_message = strlen(message);
printk(KERN_INFO "character device: Received %d characters from the user\n", len);
return len;
}
static int dev_release(struct inode *inodep, struct file *filep){
mutex_unlock(&devicedev_mutex);
printk(KERN_INFO "character device: Device successfully closed\n");
return 0;
}
module_init(character_device_init);
module_exit(character_device_exit);
Let's say that you registered with major number 254 and minor number 1 (the actual code given in your question logs the allocated numbers to dmesg, so check there). If you didn't have udev or similar configured to create a /dev/mydevice for you, you could do so yourself:
mknod /dev/mydevice c 254 1 # substitute the real allocated values
At that point, opening it is the same as with anything else:
# file descriptor number 3 is arbitrary, but the same number needs to be reused later
# don't use 0-2, which are reserved for stdin/stdout/stderr
exec 3<>/dev/mydevice
...and reads and writes are similarly conventional:
echo "This is a write" >&3
read varname <&3 # read until newline from device
For a homework assignment, I have written a character device driver. It seems to work OK. I can read and write it. The problem is that when I read the device, it endlessly loops, printing out the contents of the message buffer over and over.
This seems like it should be fairly straight forward. Just use copy_to_user(), but it's proven to be very problematic.
Anyway, here is the code. I think the problem is in the gdev_read() function.
The printk's are there to serve as debugging as well as talking points, since I have to present the project in class.
/*
* Implement a generic character pseudo-device driver
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
/* you need these, or the kernel will be tainted */
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple sample character device driver");
/*
* function prototypes
*/
int init_module(void);
void cleanup_module(void);
static ssize_t gdev_read(struct file *, char *, size_t, loff_t *);
static ssize_t gdev_write(struct file *, const char *, size_t, loff_t *);
static int gdev_open(struct inode *, struct file *);
static int gdev_release(struct inode *, struct file *);
/* macros */
#define TRUE 1
#define FALSE 0
#define MAX_MSG_LEN 64
/*
* global variables
*/
static dev_t dev_num; /* device number, for new device */
static char *mesg; /* buffer for message */
/* file operations structure, so my device knows how to act */
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = gdev_read,
.write = gdev_write,
.open = gdev_open,
.release = gdev_release,
};
/* character device struct. Declaired here, but initialized elsewhere */
struct cdev *gdev;
int init_module(void)
{
int err;
printk(KERN_ALERT "in init_module\n");
if(alloc_chrdev_region(&dev_num, 0, 1, "/dev/gdev")){
printk(KERN_INFO "Could not allocate device numbers\n");
printk(KERN_INFO "Module gdev not loaded\n");
return -1;
}
/* now I need to make the device and register it */
gdev = cdev_alloc();
gdev->owner = THIS_MODULE;
gdev->ops = &fops;
err = cdev_add(gdev, dev_num, 1);
if(err){
printk(KERN_NOTICE "Error %d adding gdev", err);
return err;
}
mesg = (char *)vmalloc(MAX_MSG_LEN);
printk(KERN_INFO "Module gdev successfully loaded.\n");
printk(KERN_INFO "gdev Major Number: %d\n", MAJOR(dev_num));
return 0;
}
void cleanup_module(void)
{
printk(KERN_ALERT "in cleanup_module\n");
unregister_chrdev_region(dev_num, 3);
vfree(mesg);
cdev_del( gdev );
printk(KERN_INFO "Module gdev unregistered\n");
}
static ssize_t gdev_read(struct file *filp, char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN;
printk(KERN_ALERT "in gdev_read\n");
if(copy_to_user(page, mesg, bytes)){
return -EFAULT;
}
return bytes;
}
static ssize_t gdev_write(struct file *filp, const char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN;
printk(KERN_ALERT "in gdev_write\n");
if(copy_from_user(mesg, page, bytes)){
return -EFAULT;
}
return bytes;
}
static int gdev_open(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "in gdev_open\n");
return 0;
}
static int gdev_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "in gdev_release\n");
/* doesn't do anything because it doesn't need too */
return 0;
}
If zero is not returned from read() (in your case gdev_read()), the read function will be called again.
To stop this you use the loff_t *offset parameter. Increment it by how many bytes you have read using (*offset) += bytes; after copy_to_user(). Next time read() is called, offset will be what you have incremented it to. Now just check how many bytes you have previously sent, and only send what you still have remaining. Your function should look like this:
static ssize_t gdev_read(struct file *filp, char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < (MAX_MSG_LEN-(*offset)) ? len : (MAX_MSG_LEN-(*offset));
printk(KERN_ALERT "in gdev_read\n");
if(copy_to_user(page, mesg, bytes)){
return -EFAULT;
}
(*offset) += bytes;
return bytes;
}
You could use 'simple_read_from_buffer' function from 'linux/fs.h':
static ssize_t gdev_read(struct file *filep, char __user *buff, size_t count, loff_t *offp)
{
return simple_read_from_buffer(buff, count, offp, my_buffer, buffer_len);
}
'my_buffer' and 'buffer_len' are defined in your module.