EDITED Previously I said it became null at device_write but it's actually device_read.
I am trying to write a simple program which read and writes to the character device. The problem I have is "top" pointer of my stack becomes null at the starting of device_read somehow even though "push" is working properly.
This is my stack declaration.
static struct Node {
char* data;
struct Node *next;
};
This is my full charDeviceDriver.c code
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <charDeviceDriver.h>
#include<linux/slab.h>
MODULE_LICENSE("GPL");
/*
* This function is called whenever a process tries to do an ioctl on our
* device file. We get two extra parameters (additional to the inode and file
* structures, which all device functions get): the number of the ioctl called
* and the parameter given to the ioctl function.
*
* If the ioctl is write or read/write (meaning output is returned to the
* calling process), the ioctl call returns the output of this function.
*
*/
DEFINE_MUTEX (devLock);
static int counter = 0;
int size = 0;
struct Node* top;
/*
* This function is called when the module is loaded
*/
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
top = NULL;
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "the driver, create a dev file with\n");
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
printk(KERN_INFO "the device file.\n");
printk(KERN_INFO "Remove the device file and module when done.\n");
return SUCCESS;
}
/*
* This function is called when the module is unloaded
*/
void cleanup_module(void)
{
unregister_chrdev(Major, DEVICE_NAME);
}
/*
* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
static int device_open(struct inode *inode, struct file *file)
{
mutex_lock (&devLock);
if (Device_Open) {
mutex_unlock (&devLock);
return -EBUSY;
}
Device_Open++;
mutex_unlock (&devLock);
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
/* Called when a process closes the device file. */
static int device_release(struct inode *inode, struct file *file)
{
empty();
mutex_lock (&devLock);
Device_Open--; /* We're now ready for our next caller */
mutex_unlock (&devLock);
/*
* Decrement the usage count, or else once you opened the file, you'll
* never get get rid of the module.
*/
module_put(THIS_MODULE);
return 0;
}
/*
* Called when a process, which already opened the dev file, attempts to
* read from it.
*/
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
char *buffer, /* buffer to fill with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
printk(KERN_INFO "INSIDE DEVICE READ\n");
char* msgTemp = (char*)kmalloc(sizeof(char)*length,GFP_USER);
if(!top) {
printk(KERN_INFO "TOP BEOMES NULL AT DEVICE_READ \n" );
}
if(size == 0) {
printk(KERN_INFO "INSIDE DEVICE READ IF EMPTY LIST");
return -EAGAIN;
}
else {
printk(KERN_INFO "INSIDE DEVICE READ IF LIST NOT EMPTY");
msgTemp = pop();
printk(KERN_INFO "MESSAGE POPPED IS %s", msgTemp);
if (copy_to_user(buffer,msgTemp,length) == 0) {
return length;
}
}
return 0;
}
/* Called when a process writes to dev file: echo "hi"> /dev/hello */
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
char* msgTemp = (char*)kmalloc(sizeof(char)*len,GFP_USER);
printk(KERN_ALERT "THIS IS THE STARTING OF DEVICE WRITE.\n");
if(len > 6144) {
printk(KERN_ALERT "FIRST IF CONDITION.\n");
return -EINVAL;
}
else if (totalSize() + len > 4 * 1024 * 1024) {
printk(KERN_ALERT "SECOND IF CONDITION.\n");
return -EAGAIN;
}
else if (copy_from_user(msgTemp,buff,len) == 0) {
printk(KERN_ALERT "THIRD IF CONDITION.\n");
printk(KERN_ALERT "WRITTEN MESSAGE IS %s",msgTemp);
push(msgTemp);
return len;
}
printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
return EAGAIN;
}
void push(char* dataS)
{
// char* tempCheck;
struct Node* newNode = (struct Node*) kmalloc(sizeof(struct Node),GFP_USER);
newNode->data = dataS;
newNode->next = top;
top = newNode;
size++;
printk(KERN_ALERT "THE SIZE IS AFTER PUSHING IS %d.\n",size);
printk(KERN_ALERT "THE MESSAGE PUSHED IS %s\n",dataS);
}
char* pop()
{
printk(KERN_INFO "INSIDE POP METHOD\n");
char* dataS;
struct Node* topNode;
// Check stack underflow
if (size <= 0 || !top)
{
printk(KERN_INFO "INSIDE POP IF METHOD ABOUT UNDERFLOW\n");
//printf("Stack is empty.\n");
// Throw empty stack error/exception
// Since C does not have concept of exception
// Hence return minimum integer value as error value
// Later in code check if return value is INT_MIN, then
// stack is empty
return NULL;
}
topNode = top;
dataS = top->data;
top = top->next;
kfree(topNode);
size--;
printk(KERN_INFO "THE ELEMENT THAT GOT POPPED IS %s",dataS);
return dataS;
}
size_t totalSize()
{
struct Node* temp;
size_t total;
int i;
temp = top;
for(i = 0;i<size;i++){
total += sizeof(*temp->data)/sizeof(char);
temp = temp -> next;
}
return total;
}
void empty()
{
struct Node* cur = top;
struct Node* next;
while (cur != NULL) {
next = cur->next;
kfree(cur);
cur = next;
}
top = NULL;
}
These are my log messages.
