Attempting to lock a spinlock in the down function results in freezing - c

I am attempting to implement my own version of a semaphore into a linux vm and am running into a crash when I attempt to lock a spinlock inside the down function. Using GDB I found that the down is called immediately after the create function so the problem is definitely there.
Here is the create function:
asmlinkage long sys_create(int value, char name[32], char key[32]){
struct sem *new_sem = (struct sem*) kmalloc(sizeof(struct sem), GFP_ATOMIC);
struct sem_node *new_sem_node = (struct sem_node*) kmalloc(sizeof(struct sem_node), GFP_ATOMIC);
struct sem_node *curr_sem = sem_list_head;
new_sem_node->sem = new_sem;
spin_lock(&sem_lock);
new_sem->sem_id = IDcntr++;
spin_lock_init(&(new_sem->lock));
strncpy(new_sem->key, key, 32);
strncpy(new_sem->name, name, 32);
if(curr_sem == NULL)
{
sem_list_head = new_sem_node;
}
else
{
while(curr_sem->next != NULL)
{
curr_sem = curr_sem->next;
}
curr_sem->next = new_sem_node;
}
spin_unlock(&sem_lock);
return new_sem->sem_id;
}
Functions spin_lock, spin_unlock, and spin_lock_init are working as intended. The down function calls:
spin_lock(&(sem_list_head->sem->lock));
right at the beginning and freezes. To be more specific, in the gdb terminal, I try and get to the next line and it stops and in the actual machine it's completely stopped. No other functions are called between the create and down function. Below is the header file that defines the sem_node, process_node, and sem objects used in the create and down functions:
int IDcntr = 1;
DEFINE_SPINLOCK(sem_lock);
struct sem_node
{
struct sem* sem;
struct sem_node* next;
};
struct process_node
{
struct process_node* next;
struct task_struct* task;
};
struct sem
{
int value;
long sem_id;
spinlock_t lock;
char key[32];
char name[32];
struct process_node* head;
struct process_node* tail;
};
struct sem_node* sem_list_head = NULL;
Through independent testing the function DEFINE_SPINLOCK and object spinlock_t are working as intended. After thorough debugging the problem is in the create function. I freely admit that I am still learning how semaphores work so chances are I didn't set variables correctly or define things correctly. Any help in pointing me the right way would be greatly appreciated.

Related

How to pass data to kthread_run

I'm try to make simple kernel module with multithreading.
So I'm using linux/kthread.h, kernel v. 5.2.11
Problem: I can't passing the char array into thread: Segmentation fault.
That's what I'm doing:
typedef struct {
int num;
char origin[MAXSTR]; //part of input for current thread
struct completion wait_for_thread; //completion struct
} kthread_arg;
Then:
struct task_struct *task;
static kthread_arg kta_first_thread;
kta_first_thread.num = 1;
strncpy(kta_first_thread.origin, dat1, MAXSTR );
//Here I have normal char array 'origin'
init_completion(&kta_first_thread.wait_for_thread);
task = kthread_run(&thread_function, (void*)&kta_first_thread, "one");
And after that I have the error. Moreover, if you remove the array from struct, then everything works.
I'm sure doing something wrong?
The args passed to kernel_run must be kmalloced, your args is in stack. I have met the same problem, your code should like this:
struct your_struct* test=NULL;
struct task_struct* t=NULL;
test=(struct your_struct*)kmalloc(sizeof(struct your_struct),GFP_KERNEL);
t=kthread_run(your_function,(void*)test,name);

C - Reuse struct as argument for multiple PThreads

I have a while loop, and for each iteration of the loop, I am creating and populating a struct, and creating a thread while passing in that struct as an argument to the threaded function.
This is causing some issues - My while loop updates the data in the struct before my threaded function has a chance to make local copies of the struct data.
Does anyone know a good way to go about reusing a struct for multiple threads? I thought about using some kind of flag to make the main thread wait until the threaded function grabs its own copy, but this seems like it would introduce unnecessary waiting.
Here is an example of what I am trying to accomplish:
struct parameters {
int val1;
int val2;
int val3;
};
int main() {
...
while (readLine(file)) {
...
struct parameters *myParameters = malloc(sizeof(struct parameters));
myParameters.val1 = line.val1;
myParameters.val2 = line.val2;
myParameters.val3 = line.val3;
pthread_t myThread;
pthread_create(&myThread, NULL, &print, myParameters);
free(myParameters);
}
}
void *print(void *param) {
struct parameters *localParameters = param;
int threadVal1 = localParameters->val1;
int threadVal2 = localParameters->val2;
int threadVal3 = localParameters->val3;
}

Static allocation of struct members within another static struct?

I am trying to implement a low-level thread lock without the use of dynamic memory allocation; this code will basically be used on a completely bare-bones kernel.
However, I am running into the problem of receiving a seg fault when I am trying to dereference a member inside this global static struct. My code is as such
My wrapper struct
/** LOCKING STRUCT & FUNCTIONS **/
struct lock {
int free;
struct thread_list* wait_list;
struct thread* current_holder;
};
The nested struct(intended as a linked list sort of deal)
struct thread_list {
struct thread *head;
};
And the member inside this list
struct thread {
void *top; // top of the stack for this thread
void *sp; // current stack pointer for this thread (context)
void (*start_func)(void *);
void *arg;
int state;
int exit_value;
struct thread *join_thread;
struct thread *next_thread;
int id;
};
The method I'm trying to implement is as such
void lock_init (struct lock *lk) {
lk->free = 1; //Set lock as free
struct thread_list waiting = lk->wait_list; //Get waitlist, works fine
waiting->head = NULL; //Set waitlist's head to null, SEGFAULTS HERE
}
I am not super proficient at C, but I can't seem to figure out the correct methodology/syntax to make my code work like this.
struct thread_list waiting = lk->wait_list; //Get waitlist, works fine
waiting->head = NULL; //Set waitlist's head to null, SEGFAULTS HERE
waiting is not a struct pointer but a struct variable . To access member using it you need to use . operator -
waiting.head = NULL;
Or to use -> operator declare it as a struct pointer .

Problems with netdev_alloc and netdev_priv in kernel network driver

I've got a custom piece of FPGA logic which I've implemented a functioning char driver for, and I'm trying to get it to work as a network driver as well now. I'm following along as best I can using the LDD book, snull code, and loopback.c, dummy.c, and other drivers from the kernel as examples.
The code I've got below (obviously ripped out of the larger file) is the networking driver code I have so far; I can successfully insmod, and "ifconfig optical0" shows that my MTU & flags are correct so I know at least it's being registered.
Now I'm trying to implement the struct net_device's private field (void* priv) to store stats and other things in, and it's resulting in segfaults. Here's the code so far:
struct serdes_device {
struct serdes_regs __iomem *regs;
struct serdes_dma *tx_dma,
*rx_dma;
struct device *dev;
struct net_device *netdev;
struct resource serdes_res;
struct cdev cdev;
int major, minor;
int tx_kbps;
int rx_kbps;
};
struct optical_priv {
struct serdes_device *serdes_dev;
struct net_device_stats stats;
};
static const struct net_device_ops optical_netdev_ops = {
.ndo_get_stats = optical_stats,
.ndo_start_xmit = optical_xmit,
/* and so on, not including the ops functions for brevity */
};
void optical_setup(struct net_device *dev)
{
dev->netdev_ops = &optical_netdev_ops;
dev->destructor = free_netdev;
dev->tx_queue_len = 1;
dev->type = ARPHRD_NONE;
dev->hard_header_len = SERDES_FRAME_HEADER_LENGTH;
dev->mtu = SERDES_FRAME_TOTAL_LENGTH;
dev->addr_len = 0;
dev->flags &= ~IFF_BROADCAST;
/* more flags & features cut */
}
static int optical_init(struct net_device *netdev)
{
int err;
struct optical_priv *priv;
netdev = alloc_netdev(sizeof(struct optical_priv), "optical%d", optical_setup);
if (!netdev)
return -ENOMEM;
err = register_netdev(netdev);
if (err < 0)
goto err;
priv = netdev_priv(netdev);
printk(KERN_WARNING "priv is at address 0x%p\n", priv);
return 0;
err:
free_netdev(netdev);
return err;
}
static int serdes_of_probe(struct platform_device *op)
{
struct serdes_device *serdes_dev;
struct optical_priv *priv;
int err = 0;
serdes_dev = kzalloc(sizeof(struct serdes_device), GFP_KERNEL);
/* A bunch of unrelated openfirmware & cdev code removed. */
err = optical_init(serdes_dev->netdev);
if (err < 0)
dev_err(serdes_dev->dev, "Error %d initing optical link\n", err);
priv = netdev_priv(serdes_dev->netdev);
if (!priv)
dev_err(serdes_dev->dev, "priv is null... \n");
dev_info(serdes_dev->dev, "priv is at 0x%p\n", priv);
dev_info(&op->dev, "Done probing.\n");
return 0;
out_free_serdes:
kfree(serdes_dev);
out_return:
return err;
}
So as I understand it, I'm allocating space for and initializing my serdes device (which I know works as a char driver). Then I call optical_init which allocs, registers, and configures serdes_dev->netdev. alloc_netdev is supposed to allocate room for the (void *)priv field as well which is why sizeof(struct optical_priv) is passed in.
The output after insmod of the two print statements in there look like this:
priv is at address 0xdd2de500
priv is at 0x00000500
Done probing.
and obviously trying to access priv in any way after that causes a segfault. I think my confusion is about why netdev_priv() returns the two different values when called from the two different functions-- shouldn't it be allocated and correct anytime after alloc_netdev?
e: I think I'm also confusing myself by looking for examples in too many drivers, from too many eras, steeped in the history of hardware and kernel APIs past... if anyone has a good basic driver recommendation for me to start with, I'm more than happy reading code to learn.
I think that the problem is here:
err = optical_init(serdes_dev->netdev);
You are passing an invalid pointer to a netdev structure. Then in optical_init() you change the local value of the pointer with:
netdev = alloc_netdev(sizeof(struct optical_priv), "optical%d", optical_setup);
Now you have a valid pointer to a struct net_device. But this pointer value does not apply to the serdes_dev->netdev variable but only locally in optical_init(). In consequence of this, also the pointer to priv is invalid. Here a little example that show the issue:
#include <stdio.h>
#include <stdlib.h>
struct test {
int first;
int *second;
};
void allocate_memory(int *ptr)
{
ptr = malloc(10);
printf("while allocating %p\n", ptr);
}
int main(void) {
struct test *p1;
p1= malloc(sizeof(struct test));
printf("before %p\n", p1->second);
allocate_memory(p1->second);
printf("after %p\n", p1->second);
free(p1);
free(p2);
return EXIT_SUCCESS;
}
The output is:
before (nil)
while allocating 0x23ee030
after (nil)

C Casting between different struct-pointers during "simulated inheritance"

Hey I'm currently porting a C++ program into C and I simplified I'm using the following code when I'm simulating inheritence from C++ classes using structs in C.
typedef struct GenTask GenTask;
typedef struct Task Task;
typedef struct UserTask UserTask;
struct GenTask{
char name[MAXCHAR];
boolean isUserTask;
int k;
void (*print)(Task*);
};
GenTask* newGenTask(const char* n){
GenTask* inhTask = (GenTask*)malloc(sizeof(GenTask));
strncpy(inhTask->name, n, MAXCHAR);
inhTask->k = 1;
return inhTask;
}
struct Task{
GenTask* inhTask;
};
void printTask(Task* task){
printf("\nThis is Task: %s",task->inhTask->name);
}
Task* newTask(const char* n){
Task* task = (Task*)malloc(sizeof(Task));
task->inhTask = newGenTask(n);
task->inhTask->isUserTask = false;
task->inhTask->print = printTask;
return task;
}
void deleteTask(Task* task){
free(task->inhTask);
free(task);
}
struct UserTask{
GenTask* inhTask;
int m;
};
void printUserTask(Task* task){
UserTask* ut = (UserTask*)task;
printf("\nThis is UserTask nbr: %d",ut->m);
}
UserTask* newUserTask(const char* n){
UserTask *ut = (UserTask*)malloc(sizeof(UserTask));
ut->inhTask = newGenTask(n);
ut->inhTask->isUserTask = true;
ut->inhTask->print = printUserTask;
ut->m=100;
return ut;
}
void deleteUserTask(UserTask* utask){
free(utask->inhTask);
free(utask);
}
I've tried running the code and it works as expected (or rather as I wish for it to work;)). My question though, is if there is any risk that the extra "UserTask-memory" is exposed after type casting like below.
Task* task = (Task*)newUserTask("A UserTask");
There seems to be no problem when I cast back into a UserTask pointer.
UserTask* utask = (UserTask*)task;
I assume that when I free the memory for "A UserTask", I suffies to free utask and using deleteUserTask(utask)? If I instead free task using deleteTask(task), I guess the UserTask specific memory won't get freed.
I my all new to both C++ and C, been using Java before and the dynamic memory allocation is still a bit scary... Thanks for any help!
/Patrik
I think the 'normal' way to do this in C is to include the parent struct inline not as a pointer, i.e.:
struct Task{
GenTask inhTask;
};
That way a pointer to a task struct can be up cast to a Task*. And of course the 'parent' is freed automatically along with the child instance.

Resources