Segmentation fault while using my char drivers - c

I'm trying to write a char driver, named my_module. for every device I want to act in the following way:
if I open the device's file for the first time , I'm Allocating memory
for a struct, which "private_data" field in the device's file will later point to.
If I open the device's file afterwards, I will keep using the same struct that "private_data" points to
the problem: when I open the file for the second time , I have a Segmentation fault. If I reallocate the memory for the struct each time I use "open", there is no error.
what have I done wrong?
/* my_module.c: Example char device module.
*
*/
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include<linux/slab.h> /* included for the purpose of using kmalloc and kfree */
#include "my_module.h"
#define CAN_READ 1
#define CANT_READ -1
#define CAN_WRITE 1
#define CANT_WRITE -1
#define MY_DEVICE "my_device"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anonymous");
#define BUF_LEN 4096
/* globals */
int my_major = 0; /* will hold the major # of my device driver */
int can_read = CANT_READ;
int can_write = CANT_WRITE;
char * buffp = NULL;
struct file_operations my_fops = {
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write,
.ioctl = my_ioctl,
.owner = THIS_MODULE
};
typedef struct driver_t {
int can_read;
int can_write;
int curr_index_write_d;
int curr_index_read_d;
char * d_ptr;
} Driver;
Driver * driverCreate( char * buffer, int can_read_arg, int can_write_arg ) {
Driver * driver = (Driver*)kmalloc(sizeof(*driver),GFP_KERNEL);
if(!driver){
return NULL;
}
driver->curr_index_write_d=0;
driver->curr_index_read_d=0;
driver->d_ptr=buffer;
driver->can_read=can_read_arg;
driver->can_write=can_write_arg;
return driver;
}
int init_module(void)
{
//printk(KERN_WARNING "start of module! ");
my_major = register_chrdev(my_major, MY_DEVICE, &my_fops);
if (my_major < 0)
{
//printk(KERN_WARNING "can't get dynamic major\n");
return my_major;
}
//
// do_init();
//
return 0;
}
void cleanup_module(void)
{
//printk(KERN_WARNING "end of module! ");
unregister_chrdev(my_major, MY_DEVICE);
//
// do clean_up();
//
return;
}
int my_open(struct inode *inode, struct file *filp)
{
if(MOD_IN_USE>1) {
return 0;
}
if (filp->f_mode & FMODE_READ)
{
can_read = CAN_READ;
}
if (filp->f_mode & FMODE_WRITE)
{
can_write = CAN_WRITE;
}
char * ptr = kmalloc(BUF_LEN, GFP_KERNEL);
if (!ptr) {
return my_major;
}
Driver * driver = driverCreate(ptr,can_read,can_write);
if (!driver) {
return my_major;
}
filp->private_data = driver;
MOD_INC_USE_COUNT;
return 0;
}
int my_release(struct inode *inode, struct file *filp)
{
/*
if(MOD_IN_USE>1) {
printk(KERN_WARNING "\nclose: MOD IN USE: %d\n", (int)MOD_IN_USE);
MOD_DEC_USE_COUNT;
return 0;
}
printk(KERN_WARNING "\nclose:(suupose to be 1) MOD IN USE: %d\n", (int)MOD_IN_USE);
Driver * d_ptr = (Driver*)(filp->private_data);
char * ptr = d_ptr->d_ptr;
if (filp->f_mode & FMODE_READ)
{
d_ptr->can_read = CANT_READ;
can_read = CANT_READ;
//
// handle read closing
//
}
if (filp->f_mode & FMODE_WRITE)
{
d_ptr->can_write = CANT_WRITE;
can_write = CANT_WRITE;
//
// handle write closing
//
}
if(ptr != NULL) {
kfree(ptr);
kfree(filp->private_data);
filp->private_data=NULL;
printk( KERN_WARNING "Memory is now free ");
}
else {
printk( KERN_WARNING "No memory to free ");
}
*/
return 0;
}
ssize_t my_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
Driver * d_ptr = (Driver*)(filp->private_data);
char * ptr = d_ptr->d_ptr;
int curr_index_write = d_ptr->curr_index_write_d;
int curr_index_read = d_ptr->curr_index_read_d;
if(d_ptr->can_read == CANT_READ) {
return 0;
}
if( curr_index_write - curr_index_read == 0 ) {
return 0;
}
int length = (count >= (curr_index_write - curr_index_read) ?
(curr_index_write - curr_index_read) : count );
copy_to_user((char*)buf,(ptr+curr_index_read),length);
d_ptr->curr_index_read_d = curr_index_write;
return length;
//
// Do read operation.
// Return number of bytes read.
}
ssize_t my_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
Driver * d_ptr = (Driver*)(filp->private_data);
int curr_index_write = d_ptr->curr_index_write_d;
char * ptr = d_ptr->d_ptr;
if(can_write == CANT_WRITE) {
return 0;
}
if( BUF_LEN < curr_index_write + count ) {
return -ENOMEM;
}
copy_from_user((ptr+curr_index_write),(char*)buf,count);
d_ptr->curr_index_write_d = curr_index_write + count;
return count;
//
// Do write operation.
// Return number of bytes written.
}
int my_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
if(filp->private_data==NULL) {
return 0;
}
Driver * d_ptr = (Driver*)(filp->private_data);
switch(cmd)
{
case MY_RESET:
d_ptr->curr_index_write_d = 0;
d_ptr->curr_index_read_d = 0;
//
// handle OP 1.
//
break;
case MY_RESTART:
d_ptr->curr_index_read_d = 0;
//
// handle OP 1.
//
break;
default:
return -ENOTTY;
}
return 0;
}

Instead of this line
driver->d_ptr=buffer;
Try
driver->d_ptr=strdup(buffer);
Remember that d_ptr is a pointer to char. It needs memory allocation first and copy to it. strdup() does the job.

Related

C: Multi producer, multi consumer bounded queue

I try (better tried) to implement a circular buffer with the following interface:
ring_buffer *ring_buffer_create(int capacity, int element_size);
void ring_buffer_destroy(ring_buffer *buffer)
const void *ring_buffer_read_acquire(ring_buffer *buffer, ring_buffer_loc *loc);
void ring_buffer_read_finish(ring_buffer *buffer, ring_buffer_loc loc);
void *ring_buffer_write_acquire(ring_buffer *buffer, ring_buffer_loc *loc);
void ring_buffer_write_finish(ring_buffer *buffer, ring_buffer_loc loc);
It should be possible to read / write multiple elements concurrently (and even in parallel). E.g.:
ring_buffer *buffer = ring_buffer_create(10, sizeof(int));
/* Write a single element */
ring_buffer_loc loc0;
int *i0 = ring_buffer_write_acquire(buffer, &loc);
*i0 = 42; // this could be a big data structure and way more expensive
ring_buffer_write_finish(buffer, loc0);
/* Write "concurrently" */
ring_buffer_loc loc1, loc2;
int *i1 = ring_buffer_write_acquire(buffer, &loc);
int *i2 = ring_buffer_write_acquire(buffer, &loc);
*i1 = 1729;
*i2 = 314;
ring_buffer_write_finish(buffer, loc1);
ring_buffer_write_finish(buffer, loc2);
All "acquire"-functions should be blocking until the operation is possible.
So far, so good. I thought this is simple and so I started with a clean implementation which is based on mutex. But soon I could see that this was far too slow for my use-case (100'000 writes and reads per second), so I switched over to spin-locks etc.
My implementation became quite messy and at some point (now), I started to think about why not something "simple" like this with the desired interface already exists? Probably, it is anyway not a great idea to re-implement something like this.
Maybe someone knows an implementation which has such an interface and which is blocking if the operation is not possible? I was looking quite long in the internet, but I could not find a good match for my problem. Maybe my desired interface is just "bad" or "wrong"?
Nevertheless, I add my current code. It basically assigns each "cell" (=value) a state which can be NONE (not set; the cell is basically empty), WRITING (someone acquired the cell to write data), READING (someone acquired the cell to read) and SET (the cell has a value which could be read). Each cell has a spin-lock which is used to update the cell state.
It then works like this:
When someone acquires a read and the current cell has the state "SET", then the value can be read (new state is READING) and the read index is increased. In all other cases a conditional variable is used to wait until an element is available. When an element read is finished, the cell state is changed to NONE and if any writers are waiting, a conditional variable signal is sent.
The same is true if a cell write is acquires. The only difference is that the cell needs the state "NONE" to be used and possible readers are signaled if there are any.
For some reasons the code sometimes locks and so I had to add a "dirty" timeout to my conditional variable. I would already be super happy if this could be solved, because the "timeout" basically makes the code polling (which is relatively ugly) and at the same time many context switches are done. Maybe someone sees the bug? The "new" code also has the disadvantage that it sometimes is really slow which is like a killer for my application. I attached the "old" and the "new" code (the changed lines are marked).
Thank you for helping me:)!
#include <stdio.h>
#include <stdlib.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
typedef int ring_buffer_loc;
enum t_ring_buffer_cell_state
{
NONE = 0,
WRITING = 1,
READING = 2,
SET = 3
};
typedef struct {
char *buffer; // data
atomic_int_fast8_t *states; // state per cell
pthread_spinlock_t *locks; // lock per cell
int capacity;
int element_size;
pthread_spinlock_t read_i_lock;
int read_i;
pthread_spinlock_t write_i_lock;
int write_i;
pthread_spinlock_t waiting_readers_lock;
int waiting_readers;
pthread_spinlock_t waiting_writers_lock;
int waiting_writers;
pthread_mutex_t value_written_lock;
pthread_mutex_t value_read_lock;
pthread_cond_t value_written;
pthread_cond_t value_read;
} ring_buffer;
ring_buffer *ring_buffer_create(int capacity, int element_size)
{
ring_buffer *res = calloc(1, sizeof(ring_buffer));
res->buffer = calloc(capacity, element_size);
res->states = calloc(capacity, sizeof(*res->states));
res->locks = malloc(capacity * sizeof(*res->locks));
for (int i = 0; i < capacity; ++i) {
pthread_spin_init(&res->locks[i], PTHREAD_PROCESS_PRIVATE);
}
pthread_spin_init(&res->write_i_lock, PTHREAD_PROCESS_PRIVATE);
pthread_spin_init(&res->read_i_lock, PTHREAD_PROCESS_PRIVATE);
pthread_spin_init(&res->waiting_readers_lock, PTHREAD_PROCESS_PRIVATE);
pthread_spin_init(&res->waiting_writers_lock, PTHREAD_PROCESS_PRIVATE);
res->capacity = capacity;
res->element_size = element_size;
return res;
}
void ring_buffer_destroy(ring_buffer *buffer)
{
free(buffer->buffer);
free(buffer->states);
free(buffer);
}
static inline void ring_buffer_inc_index(ring_buffer *buffer, int *index)
{
*index = (*index + 1) % buffer->capacity;
}
void timespec_now_plus_ms(struct timespec *result, long ms_to_add)
{
const int one_second_us = 1000 * 1000 * 1000;
timespec_get(result, TIME_UTC);
const long nsec = result->tv_nsec + ms_to_add * 1000 * 1000;
result->tv_sec += nsec / one_second_us;
result->tv_nsec += nsec % one_second_us;
}
const void *ring_buffer_read_acquire(ring_buffer *buffer, ring_buffer_loc *loc)
{
bool is_waiting = false;
start:
pthread_spin_lock(&buffer->read_i_lock);
const int read_i = buffer->read_i;
pthread_spinlock_t *cell_lock = &buffer->locks[read_i];
pthread_spin_lock(cell_lock);
const int state = buffer->states[read_i];
if (state == NONE || state == WRITING || state == READING) {
if (!is_waiting) {
is_waiting = true;
pthread_spin_lock(&buffer->waiting_readers_lock);
++buffer->waiting_readers;
pthread_mutex_lock(&buffer->value_written_lock);
pthread_spin_unlock(&buffer->waiting_readers_lock);
} else {
pthread_mutex_lock(&buffer->value_written_lock);
}
pthread_spin_unlock(cell_lock);
pthread_spin_unlock(&buffer->read_i_lock);
// "new" code:
// struct timespec ts;
// do {
// timespec_now_plus_ms(&ts, 50);
// } while (pthread_cond_timedwait(&buffer->value_written, &buffer->value_written_lock, &ts) == ETIMEDOUT && buffer->states[read_i] == state);
// pthread_mutex_unlock(&buffer->value_written_lock);
// "old" code (which hangs quite often):
pthread_cond_wait(&buffer->value_written, &buffer->value_written_lock);
pthread_mutex_unlock(&buffer->value_written_lock);
goto start;
} else if (state == SET) {
if (is_waiting) {
pthread_spin_lock(&buffer->waiting_readers_lock);
--buffer->waiting_readers;
assert(buffer->waiting_readers >= 0);
pthread_spin_unlock(&buffer->waiting_readers_lock);
}
buffer->states[read_i] = READING;
ring_buffer_inc_index(buffer, &buffer->read_i);
pthread_spin_unlock(&buffer->read_i_lock);
pthread_spin_unlock(cell_lock);
*loc = read_i;
return &buffer->buffer[read_i * buffer->element_size];
} else {
printf("unknown state!\n");
exit(1);
}
}
void ring_buffer_read_finish(ring_buffer *buffer, ring_buffer_loc loc)
{
pthread_spinlock_t *cell_lock = &buffer->locks[loc];
pthread_spin_lock(cell_lock);
buffer->states[loc] = NONE;
pthread_spin_unlock(cell_lock);
pthread_spin_lock(&buffer->waiting_writers_lock);
if (buffer->waiting_writers > 0) {
pthread_cond_signal(&buffer->value_read);
}
pthread_spin_unlock(&buffer->waiting_writers_lock);
}
void *ring_buffer_write_acquire(ring_buffer *buffer, ring_buffer_loc *loc)
{
bool is_waiting = false;
start:
pthread_spin_lock(&buffer->write_i_lock);
const int write_i = buffer->write_i;
pthread_spinlock_t *cell_lock = &buffer->locks[write_i];
pthread_spin_lock(cell_lock);
const int state = buffer->states[write_i];
if (state == SET || state == READING || state == WRITING) {
if (!is_waiting) {
is_waiting = true;
pthread_spin_lock(&buffer->waiting_writers_lock);
++buffer->waiting_writers;
pthread_mutex_lock(&buffer->value_read_lock);
pthread_spin_unlock(&buffer->waiting_writers_lock);
} else {
pthread_mutex_lock(&buffer->value_read_lock);
}
pthread_spin_unlock(cell_lock);
pthread_spin_unlock(&buffer->write_i_lock);
// "new" code:
// struct timespec ts;
// do {
// timespec_now_plus_ms(&ts, 5);
// } while (pthread_cond_timedwait(&buffer->value_read, &buffer->value_read_lock, &ts) == ETIMEDOUT && buffer->states[write_i] == state);
// pthread_mutex_unlock(&buffer->value_read_lock);
// "old" code (which hangs quite often):
pthread_cond_wait(&buffer->value_read, &buffer->value_read_lock);
pthread_mutex_unlock(&buffer->value_read_lock);
goto start;
} else if (state == NONE) {
if (is_waiting) {
pthread_spin_lock(&buffer->waiting_writers_lock);
--buffer->waiting_writers;
assert(buffer->waiting_writers >= 0);
pthread_spin_unlock(&buffer->waiting_writers_lock);
}
buffer->states[write_i] = WRITING;
ring_buffer_inc_index(buffer, &buffer->write_i);
pthread_spin_unlock(&buffer->write_i_lock);
pthread_spin_unlock(cell_lock);
*loc = write_i;
return &buffer->buffer[write_i * buffer->element_size];
} else {
printf("unknown state!\n");
exit(1);
}
}
void ring_buffer_write_finish(ring_buffer *buffer, ring_buffer_loc loc)
{
pthread_spinlock_t *cell_lock = &buffer->locks[loc];
pthread_spin_lock(cell_lock);
buffer->states[loc] = SET;
pthread_spin_unlock(cell_lock);
pthread_spin_lock(&buffer->waiting_readers_lock);
if (buffer->waiting_readers > 0) {
pthread_cond_signal(&buffer->value_written);
}
pthread_spin_unlock(&buffer->waiting_readers_lock);
}
/* just for debugging */
void ring_buffer_dump(const ring_buffer *buffer)
{
printf("RingBuffer\n");
printf(" Capacity: %d\n", buffer->capacity);
printf(" Element size: %d\n", buffer->element_size);
printf(" Read index: %d\n", buffer->read_i);
printf(" Write index: %d\n", buffer->write_i);
printf(" Cells:\n");
for (int i = 0; i < buffer->capacity; ++i) {
printf(" [%d]: STATE = ", i);
switch (buffer->states[i]) {
case NONE:
printf("NONE");
break;
case WRITING:
printf("WRITING");
break;
case READING:
printf("READING");
break;
case SET:
printf("SET");
break;
}
printf("\n");
}
printf("\n");
}
/*
* Test run
*/
struct write_read_n_conf {
ring_buffer *buffer;
int n;
};
static void *producer_thread(void *arg)
{
struct write_read_n_conf conf = *(struct write_read_n_conf *)arg;
for (int i = 0; i < conf.n; ++i) {
ring_buffer_loc loc;
int *value = ring_buffer_write_acquire(conf.buffer, &loc);
*value = i;
ring_buffer_write_finish(conf.buffer, loc);
if (i % 1000 == 0) {
printf("%d / %d\n", i, conf.n);
}
}
return NULL;
}
static void *consumer_thread(void *arg)
{
struct write_read_n_conf conf = *(struct write_read_n_conf *)arg;
int tmp;
bool ok = true;
for (int i = 0; i < conf.n; ++i) {
ring_buffer_loc loc;
const int *value = ring_buffer_read_acquire(conf.buffer, &loc);
tmp = *value;
ring_buffer_read_finish(conf.buffer, loc);
ok = ok && (tmp == i);
}
printf("ok = %d\n", ok);
return (void *)ok;
}
void write_read_n_parallel(int n)
{
ring_buffer *buffer = ring_buffer_create(50, sizeof(int));
struct write_read_n_conf conf = {
.buffer = buffer,
.n = n
};
pthread_t consumer;
pthread_t producer;
pthread_create(&consumer, NULL, consumer_thread, &conf);
pthread_create(&producer, NULL, producer_thread, &conf);
pthread_join(producer, NULL);
void *res;
pthread_join(consumer, &res); // hacky way to pass a bool: res == NULL means false, and otherwise true
assert(res != NULL);
}
int main() {
write_read_n_parallel(10000000);
}

linux kernel module memory checker

I'm developing a kernel memory checker to find memory leaks in kernel space.
I have two functions profile_vmalloc and profile_vfree, profile_vmalloc uses vmalloc to allocate memory and adds memory allocated info to a list, profile_vfree frees the allocated memory and removes that info from the list. How to replace vmalloc and vfree so that when I compile and run my module any kernel module allocating and freeing memory will use my functions ?
How do I use sysfs to create a read only file that will allow the user to see a summary of memory leaks?
This is what my code looks like so far
// Linux Kernel headers
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/vmalloc.h>
#define FILE_NAME_LENGTH 256
#define vmalloc(size) profile_malloc (block_size, __FILE__, __LINE__)
#define vfree(mem_ref) profile_free(mem_ref)
struct _MEM_INFO
{
const void *address;
size_t size;
char file_name[FILE_NAME_LENGTH];
size_t length;
};
typedef struct _MEM_INFO MEM_INFO;
struct _MEM_LEAK {
MEM_INFO mem_info;
struct _MEM_LEAK * next;
};
typedef struct _MEM_LEAK MEM_LEAK;
#undef vmalloc
#undef vfree
static MEM_PROFILER_LIST * ptr_start = NULL;
static MEM_PROFILER_LIST * ptr_next = NULL;
/*
* adds allocated memory info. into the list
*
*/
void add(MEM_INFO alloc_info)
{
MEM_PROFILER_LIST * mem_leak_info = NULL;
mem_leak_info = (MEM_PROFILER_LIST *) malloc (sizeof(MEM_PROFILER_LIST));
mem_leak_info->mem_info.address = alloc_info.address;
mem_leak_info->mem_info.size = alloc_info.size;
strcpy(mem_leak_info->mem_info.file_name, alloc_info.file_name);
mem_leak_info->mem_info.line = alloc_info.line;
mem_leak_info->next = NULL;
if (ptr_start == NULL)
{
ptr_start = mem_leak_info;
ptr_next = ptr_start;
}
else {
ptr_next->next = mem_leak_info;
ptr_next = ptr_next->next;
}
}
/*
* remove memory info. from the list
*
*/
void erase(unsigned pos)
{
unsigned int i = 0;
MEM_PROFILER_LIST * alloc_info, * temp;
if(pos == 0)
{
MEM_PROFILER_LIST * temp = ptr_start;
ptr_start = ptr_start->next;
free(temp);
}
else
{
for(i = 0, alloc_info = ptr_start; i < pos;
alloc_info = alloc_info->next, ++i)
{
if(pos == i + 1)
{
temp = alloc_info->next;
alloc_info->next = temp->next;
free(temp);
break;
}
}
}
}
/*
* deletes all the elements from the list
*/
void clear()
{
MEM_PROFILER_LIST * temp = ptr_start;
MEM_PROFILER_LIST * alloc_info = ptr_start;
while(alloc_info != NULL)
{
alloc_info = alloc_info->next;
free(temp);
temp = alloc_info;
}
}
/*
* profile of vmalloc
*/
void * profile_vmalloc (unsigned int size, const char * file, unsigned int line)
{
void * ptr = vmalloc (size);
if (ptr != NULL)
{
add_mem_info(ptr, size, file, line);
}
return ptr;
}
/*
* profile of free
*/
void profile_free(void * mem_ref)
{
remove_mem_info(mem_ref);
free(mem_ref);
}
/*
* gets the allocated memory info and adds it to a list
*
*/
void add_mem_info (void * mem_ref, unsigned int size, const char * file, unsigned int line)
{
MEM_INFO mem_alloc_info;
/* fill up the structure with all info */
memset( &mem_alloc_info, 0, sizeof ( mem_alloc_info ) );
mem_alloc_info.address = mem_ref;
mem_alloc_info.size = size;
strncpy(mem_alloc_info.file_name, file, FILE_NAME_LENGTH);
mem_alloc_info.line = line;
/* add the above info to a list */
add(mem_alloc_info);
}
/*
* if the allocated memory info is part of the list, removes it
*
*/
void remove_mem_info (void * mem_ref)
{
unsigned int i;
MEM_PROFILER_LIST * leak_info = ptr_start;
/* check if allocate memory is in our list */
for(i = 0; leak_info != NULL; ++i, leak_info = leak_info->next)
{
if ( leak_info->mem_info.address == mem_ref )
{
erase ( i );
break;
}
}
}
/*
* writes a memory leak summary to a file
*/
void mem_leak_summary(void)
{
unsigned int i;
MEM_PROFILER_LIST * mem_output;
FILE * fp_write = fopen (SUMMARY_FILE, "wt");
char info[1024];
if(fp_write != NULL)
{
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "%s\n", "-----------------------------------");
fwrite(info, (strlen(info) + 1) , 1, fp_write);
for(mem_output= ptr_start; mem_output!= NULL; mem_output= mem_output->next)
{
sprintf(info, "address : %d\n", leak_info->mem_output.address);
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "size : %d bytes\n", leak_info->mem_output.size);
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "line : %d\n", leak_info->mem_output.line);
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "%s\n", "-----------------------------------");
fwrite(info, (strlen(info) + 1) , 1, fp_write);
}
}
clear();
}
static int __init profiler_init(void)
{
return 0;
}
static void __exit profiler_cleanup(void)
{
printk("profiler module uninstalled\n");
}
module_init(profiler_init);
module_exit(profiler_cleanup);
MODULE_LICENSE("GPL");
How to replace vmalloc and vfree so
that when I compile and run my module any kernel module allocating and
freeing memory will use my functions ?
Step 1. In the files that call vmalloc & vfree, define macros:
#define vmalloc(x) profile_vmalloc(x)
#define vfree(x) profile_vfree(x)
This will ensure that your functions are called.
Step 2: In your definition of the profile_* functions, do you accounting and call the actual vmalloc/vfree functions.
You are already doing the step 2, so you just need to take care of step 1.

Writing improper number of frames using PortAudio?

Running my program, I appear to not be writing the correct amount of frames according to the index.
$ ./test
Now recording!! Please speak into the microphone.
index = 0
Writing to: test.flac
audio.h:
#include <stdint.h>
#include <string.h>
typedef struct
{
uint32_t duration;
uint16_t format_type;
uint16_t number_of_channels;
uint32_t sample_rate;
uint32_t frameIndex; /* Index into sample array. */
uint32_t maxFrameIndex;
char* recordedSamples;
} AudioData;
int recordFLAC(AudioData* data, const char *fileName);
AudioData* initAudioData(uint32_t sample_rate, uint16_t channels, uint32_t duration);
capture.c:
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <sndfile.h>
#include "audio.h"
AudioData* initAudioData(uint32_t sample_rate, uint16_t channels, uint32_t duration)
{
AudioData* data = malloc(sizeof(*data));
if (!data) return NULL;
data->duration = duration;
data->format_type = 1;
data->number_of_channels = channels;
data->sample_rate = sample_rate;
data->frameIndex = 0;
data->maxFrameIndex = sample_rate * duration;
data->recordedSamples = malloc(sizeof(data->maxFrameIndex));
if(!data->maxFrameIndex) return NULL;
return data;
}
static int recordCallback(const void *inputBuffer, void *outputBuffer, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
AudioData* data = (AudioData*)userData;
const char* buffer_ptr = (const char*)inputBuffer;
char* index_ptr = &data->recordedSamples[data->frameIndex];
(void) outputBuffer;
(void) timeInfo;
(void) statusFlags;
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
if(framesLeft < frameCount){
framesToCalc = framesLeft;
finished = paComplete;
}else{
framesToCalc = frameCount;
finished = paContinue;
}
if(!inputBuffer){
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = 0;
}
}else{
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = *buffer_ptr++;
}
}
data->frameIndex += framesToCalc;
return finished;
}
int recordFLAC(AudioData* data, const char *fileName)
{
PaStreamParameters inputParameters;
PaStream* stream;
int err = 0;
int totalFrames = data->maxFrameIndex;
int numSamples;
int numBytes;
char max, val;
double average;
numSamples = totalFrames * data->number_of_channels;
numBytes = numSamples;
data->recordedSamples = malloc(numBytes);
if(!data->recordedSamples)
{
printf("Could not allocate record array.\n");
goto done;
}
for(int i = 0; i < numSamples; i++) data->recordedSamples[i] = 0;
if((err = Pa_Initialize())) goto done;
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto done;
}
inputParameters.channelCount = data->number_of_channels; /* stereo input */
inputParameters.sampleFormat = data->format_type;
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
/* Record some audio. -------------------------------------------- */
err = Pa_OpenStream(&stream, &inputParameters, NULL, data->sample_rate, paFramesPerBufferUnspecified, paClipOff, recordCallback, &data);
if(err) goto done;
if((err = Pa_StartStream(stream))) goto done;
puts("Now recording!! Please speak into the microphone.");
while((err = Pa_IsStreamActive(stream)) == 1)
{
Pa_Sleep(1000);
printf("index = %d\n", data->frameIndex);
}
if( err < 0 ) goto done;
err = Pa_CloseStream(stream);
if(err) goto done;
/* Measure maximum peak amplitude. */
max = 0;
average = 0.0;
for(int i = 0; i < numSamples; i++)
{
val = data->recordedSamples[i];
val = abs(val);
if( val > max )
{
max = val;
}
average += val;
}
average /= (double)numSamples;
done:
Pa_Terminate();
if(err)
{
fprintf(stderr, "An error occured while using the portaudio stream\n");
fprintf(stderr, "Error number: %d\n", err);
fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
err = 1; /* Always return 0 or 1, but no other return codes. */
}
else
{
SF_INFO sfinfo;
sfinfo.channels = 1;
sfinfo.samplerate = data->sample_rate;
sfinfo.format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
// open to file
printf("Writing to: %s\n", fileName);
SNDFILE * outfile = sf_open(fileName, SFM_WRITE, &sfinfo);
if (!outfile) return -1;
// prepare a 3 second long buffer (sine wave)
const int size = data->sample_rate * 3;
// write the entire buffer to the file
sf_write_raw(outfile, data->recordedSamples, size);
// force write to disk
sf_write_sync(outfile);
// don't forget to close the file
sf_close(outfile);
}
return err;
}
I'm not quite sure where I am going wrong, I know I need to be writing more frames. Any suggestions?
There seems to be something wrong with your assumptions about the sample format. In the callback you are using char * (single bytes) for the sample format, but in your libsndfile call you're opening a 16 bit file with SF_FORMAT_PCM_16.
This is not so good:
data->format_type = 1;
I recommend using one of the symbolic constants in the PortAudio library for sample formatting. Maybe you want a 16 bit one? And if so, you want to be using short* not char* in the PA callback.
Finally, if your channel count is not 1, the copy loops are incorrect:
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = 0;
}
A "frame" contains data for all channels, so for example, if it's a stereo input your iteration needs to deal with both left and right channels like this:
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = 0; // left
*index_ptr++ = 0; // right
}
Same for the other loops.

Simple char device driver / module - Linux RedHat 8 (2.4.18) on VM segmentation fault after ./module_unload

edit: I fixed the code and turned it to a more compact code regarding memory allocations, everything works now . You might aware me if I'm doing something wrong
I'm not sure that the Write&Read implemantations are perfect....
#define ARRAY_LENGTH 128
#define MY_DEVICE "my_device"
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Anonymous");
/* globals */
int my_major = 0; /* will hold the major # of my device driver */
int g_index=0; /*index of elements we will act on*/
typedef struct _my_array_elem{
char* string;
int size;
} my_array_elem;
my_array_elem my_array [ARRAY_LENGTH] ; //global array of strings
int init_module(void)
{
int i;
//no need to malloc&free for this string?
char* our_names = "333333333 \n222222222";
my_major = register_chrdev(0,MY_DEVICE,&my_fops);
if (my_major < 0) {
printk(KERN_WARNING "can't get dynamic major\n");
return my_major;
}
my_array[0].string=our_names;
my_array[0].size=strlen(our_names);
for (i=1; i<ARRAY_LENGTH; i++) {
my_array[i].string=NULL;
my_array[i].size=-1;
}
return 0;
}
void cleanup_module(void)
{
int i;
int ret = unregister_chrdev(my_major, MY_DEVICE);
if (ret < 0){
printk("Error in unregister_chrdev: %d\n", ret);
}
//CHECK!!: do I need to free the names string? (index 0)?
for (i=1; i<ARRAY_LENGTH; i++){
kfree(&my_array[i].string);
}
return;
}
ssize_t my_read(struct file *filp,char *buf,size_t count,loff_t *f_pos)
{
int bytes_read = count;
if (g_index<0 || g_index>ARRAY_LENGTH-1) {
return -EINVAL; //illegal index
}
if (my_array[g_index].size < count){
bytes_read = my_array[g_index].size;
}
if (copy_to_user(buf, my_array[g_index].string, bytes_read)!=0){
return -ENOMEM;
}
return bytes_read;
}
ssize_t my_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
if (g_index<1 || g_index>ARRAY_LENGTH-1){
return -EINVAL;
}
if ((my_array[g_index].size) != -1){
kfree(&my_array[g_index].string);
}
char* temp_string=kmalloc(count, GFP_KERNEL);
if (temp_string == NULL){
return -ENOMEM; //Out of memory
}
if (copy_from_user((void*)temp_string, buf, count)){
kfree(temp_string);
return -ENOMEM; //Out of memory
}
my_array[g_index].string=temp_string;
my_array[g_index].size=count;
return count;
}
On first read:
my_array_elem* temp_elem=kmalloc(sizeof(my_array_elem), GFP_KERNEL);
....
copy_from_user((void*)temp_elem->string, buf, count)
You are copying the data from the user buf but the string address is not yet allocated.
You need something like:
temp_elem->string = kmalloc(count, GFP_KERNEL);
To be sincere, your handling of dynamic memory is a bit confusing... You should probably write a few functions that handle that instead of writing all the byte-mangling code in the read/write functions.

Code for writing and reading on a device file from a kernel module?

I have tried the following code many times .
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<asm/uaccess.h>
#include<linux/semaphore.h>
MODULE_LICENSE("DUAL BSD/GPL");
static int dev_open(struct inode *,struct file *);
static int dev_release(struct inode *,struct file *);
ssize_t dev_read(struct file *,char *, size_t ,loff_t *);
ssize_t dev_write(struct file *,const char *,size_t ,loff_t *);
static int major;
int dev_major = 0;
int dev_minor = 0;
struct cdev *cdev;
struct device {
char array[100];
struct semaphore sem;
}chr_arr;
struct file_operations dev_ops = {
.owner = THIS_MODULE,
.read = dev_read,
.write = dev_write,
.open = dev_open,
.release = dev_release
};
ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset)
{
int i;
i=copy_to_user(buf,chr_arr.array,count);
printk(KERN_ALERT"buff:%s",buf);
return i;
}
ssize_t dev_write(struct file *filp,const char *buf,size_t count,loff_t *offset)
{
//printk(KERN_ALERT"\nsorry,byebye");
int j;
//msg_ptr = kmalloc(count,GFP_KERNEL);
//for(j=0;j<count;j++)
if(count>100)
return -1;
j = copy_from_user(chr_arr.array,buf,count);
//printk(KERN_ALERT"msg_ptr:%s",msg_ptr);
return j;
}
static int dev_open(struct inode *inode,struct file *filp)
{
filp->private_data = inode->i_cdev;
if(down_interruptible(&chr_arr.sem))
{
printk(KERN_INFO " could not hold semaphore");
return -1;
}
//printk(KERN_ALERT"ah ha the device is open !now we can go further");
return 0;
}
static int dev_release(struct inode *inode,struct file *filp)
{
up(&chr_arr.sem);
//module_put(THIS_MODULE);
return 0;
}
static int init_device(void)
{
int result;
dev_t dev_no,dev;
result = alloc_chrdev_region(&dev_no,0,1,"chr_dev");
if(result < 0)
{
printk("sorry no major number left");
return result;
}
major = MAJOR(dev_no);
dev = MKDEV(major,0);
cdev = cdev_alloc();
cdev->ops = &dev_ops;
sema_init(&chr_arr.sem,1);
printk("the major number allocated is %d\n",major);
result = cdev_add(cdev,dev,1);
if(result < 0 )
{
printk(KERN_INFO "Unable to allocate cdev");
return result;
}
return 0;
}
static void clean_device(void)
{
cdev_del(cdev);
unregister_chrdev_region(major,1);
}
module_init(init_device);
module_exit(clean_device);
but its giving me the following warning.
CC [M] /home/karan/practice/scrw/scrw1.o
In file included from /usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess.h:571:0,
from /home/karan/practice/scrw/scrw1.c:4:
In function ‘copy_from_user’,inlined from ‘write’ at /home/karan/practice/scrw/scrw1.c:43:6:
/usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess_32.h:212:26: warning: call to ‘copy_from_user_overflow’ declared with attribute warning: copy_from_user() buffer size is not provably correct
Building modules, stage 2.
MODPOST 1 modules
CC /home/karan/practice/scrw/scrw1.mod.o
LD [M] /home/karan/practice/scrw/scrw1.ko
and then when I try to write echo hi > /dev/my_dev the screen freezes after 30 secs or so.
The problem is that you should return the number of bytes read/written in your read/write methods, the return value of copy_{from,to}_user() is 0 if everything goes well. Return e.g. count in your write method if copying succeeds:
unsigned long ret;
printk(KERN_INFO "Inside write \n");
if (count > sizeof(char_arr.array) - 1)
return -EINVAL;
ret = copy_from_user(char_arr.array, buff, count);
if (ret)
return -EFAULT;
char_arr.array[count] = '\0';
return count;
You should also make sure that a terminating '\0' character is appended when you copy to your buffer (if you'd like to deal only with strings). If it is binary data you deal with store its length in your struct as well.
An example read method:
ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset)
{
int len = count >= strlen(chr_arr.array) ? strlen(chr_arr.array) : count;
if (*offset >= strlen(chr_arr.array))
return 0;
if (copy_to_user(buf,chr_arr.array,len))
return -EFAULT;
return len;
}
Edit: messed up example code, fixing it.
Edit2: example read method.

Resources