Reputation: 321
I'm new in stackoverflow, at least as an asker. First of all I want to apologize for my orthography because of this is not my mother language, and frankly I have forgotten it for a long time.
I'm programming a kernel module for Debian 6 (kernel 2.6.39.4) that interacts with a call to the system made by me. They are both easy, because I am doing it with learning purposes. The Syscall looks like it is working and exports to the user a functionality that allows to insert into a entry list and register in that two functions, one that reads and another one that writes.
The module is just a counter, whose reading and writing functions are an addition to the counter value and the consult of the current counter value. If everything is okay the writing function adds one to the counter, and the read function returns to the user the counter into a buffer. The problem happens when I use the makefile, then I receive this message (Everything that was in Spanish has been literally translated)
make -C /lib/modules/2.6.39.4.mikernel/build M=/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs modules
make[1]: acess to the directory `/usr/src/linux-headers-2.6.39.4.mikernel'
Building modules, stage 2.
MODPOST 1 modules
WARNING: "create_kifs_entry" [/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs/ModuloUsaKifs.ko] undefined!
WARNING: "remove_kifs_entry" [/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs/ModuloUsaKifs.ko] undefined!
make[1]: get out of the directory `/usr/src/linux-headers-2.6.39.4.mikernel'
And I do not recognise why the create and remove functions are not supported. the "kifs" syscall is (I think) correctly implemented (Included .h and .c, modifyed the schedule, added to the syscall table, has the kernel compiled, instaled, and tested with a program) I only have proved "sys_kifs" the syscall, but not the .h functions. This is the makefile I use.
obj-m = ModuloUsaKifs.o
all :
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean :
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
And this is the module. I'm sorry for the lack of documentations and because of the kernel messages are in Spanish. I feel like people entering my uncleaned toilet. I have some extra includes I will remove later. ModuloUsaKifs.c
#define PROC_ENTRY "mymodule"
#ifdef __KERNEL__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/kifs.h>
#include <asm-generic/errno-base.h>
#include <asm-generic/errno.h>
#include <asm-generic/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("List Kernel Module para DSO");
MODULE_AUTHOR("Kaostias");
MODULE_LICENSE("GPL");
#else
//#include <iostream>
//#include <linux/list.h>
#include <string.h>
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include "kifs.h"
#endif
int counter;
//typedef int (*read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
//typedef int (*write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
/**********************/
/* módulo en sí mismo */
/**********************/
int sum(char *user_buffer, unsigned int maxchars, void *data){
char str [256];
if (copy_from_user(str, user_buffer, maxchars)) {
return -EFAULT;
}
counter++;
return maxchars;
}
int lect(const char *user_buffer, unsigned int maxchars, void *data){
char buf[32];
int len=sprintf(buf,"%d\n",counter);
if (len> maxchars)
{
return -EINVAL;
}
if(copy_to_user(buf, user_buffer, len)){
printk(KERN_INFO "problemas en lect");
return -EINVAL;
}
return len;
}
int metodoInicial(void){
counter = 0;
if(create_kifs_entry("counter",sum,lect,NULL) != NULL)
{
counter = 0;
printk(KERN_INFO "modulo abierto correctamente");
return 0;
}
printk(KERN_INFO "Error, módulo counter incorrectamente agregado a kifs");
return -EINVAL;
}
void metodoFinal(void){
if(remove_kifs_entry("counter")){
printk(KERN_INFO "modulo cerrado correctamente");
}
printk(KERN_INFO "Error, módulo counter incorrectamente borrado de kifs");
}
/*********************************/
/* Registra el init y el cleanup */
/*********************************/
module_init(metodoInicial);
module_exit(metodoFinal);
Here is the header of "kifs"
#ifndef KIFS_H
#define KIFS_H
#include <linux/list.h> /* list_head */
#define MAX_KIFS_ENTRY_NAME_SIZE 50
/* Callback prototypes for kifs entries */
typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
/* Descriptor interface for the entries */
typedef struct
{
char entryname[MAX_KIFS_ENTRY_NAME_SIZE];
read_kifs_t *read_kifs;
write_kifs_t *write_kifs;
void *data;
struct list_head links; /* Set of links in kifs */
}kifs_entry_t;
enum {
KIFS_READ_OP=0,
KIFS_WRITE_OP,
KIFS_NR_OPS};
/* This function must ensure that no entry will be created as long as another entry with the same name already exists.
* == Return Value ==
* NULL Entry name already exists or No space is availables
* Pointer to the kifs entry
* */
kifs_entry_t* create_kifs_entry(const char* entryname,
read_kifs_t *read_kifs,
write_kifs_t *write_kifs,
void* data);
/* Remove kifs entry
* == Return Value ==
* -1 Entry does not exist
* 0 success
* */
int remove_kifs_entry(const char* entry_name);
/* Implementation of kifs() system call
* == Return Value ==
* -EINVAL Unsupported operation (NULL callback) or Entry not exists
* -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...)
* otherwise: Number of chars read/written (Usually maxchars value)
*/
asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars);
/* KIFS's global initialization */
void init_kifs_entry_set(void);
#endif
Here is the kifs.c itself
//#include "list.h"
#include <linux/kifs.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm-generic/errno-base.h>
#include <asm-generic/errno.h>
#include <asm-generic/uaccess.h>
/*
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Modulo KIFS para DSO");
MODULE_AUTHOR("Ismel Gonjal Montero");
*/
/* Callback prototypes for kifs entries */
/*
typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
*/
/* Valores de lectura y escritura */
/*
enum {
KIFS_READ_OP=0,
KIFS_WRITE_OP,
KIFS_NR_OPS};
*/
/***********************************/
/* Declaraciones de kifs */
/***********************************/
#define MAX_KIFS_ENTRIES 10
LIST_HEAD(entry_list);
LIST_HEAD(free_list);
kifs_entry_t pool[MAX_KIFS_ENTRIES];
/***********************************/
/* Declaraciones de clipboard */
/***********************************/
#define MAX_KIFS_CHARS 512
char clipboard[MAX_KIFS_CHARS];
/************************************/
/* Declaracion de funciones */
/************************************/
int read_list (char *user_buffer, unsigned int maxchars, void *data);
/******************************************************************************/
/* CLIPBOARD */
/******************************************************************************/
int read_clipboard (char *user_buffer, unsigned int maxchars, void *data){
int total = strlen(clipboard);
if (total>maxchars)
{
return -EINVAL;
}
if (copy_to_user(user_buffer, clipboard, total))
{
printk(KERN_ALERT "Fallo en copy_to_user()");
return -EINVAL;
}
return total;
}
int write_clipboard (const char *user_buffer, unsigned int maxchars, void *data){
if (maxchars>MAX_KIFS_CHARS-1)
{
printk(KERN_ALERT "Excede tamanio");
return -EINVAL;
}
if (copy_from_user(clipboard, user_buffer, maxchars))
{
printk(KERN_ALERT "Fallo en copy_from_user()");
return -EINVAL;
}
clipboard[maxchars]='\0';
return maxchars;
}
/****************************************************/
/* Código de KIFS */
/****************************************************/
/* KIFS's global initialization */
void init_kifs_entry_set(void){
int i = 0;
//añade a la lista todas las entradas de freelist
for(i =0; i<MAX_KIFS_ENTRIES;i++){
list_add_tail(&pool[i].links,&free_list);
}
clipboard[0]='\0';
create_kifs_entry("list", read_list,NULL,NULL);
create_kifs_entry("clipboard", read_clipboard,write_clipboard ,NULL);
printk(KERN_ALERT "Inicializado kifs");
}
/*
* Recibe un buffer de usuario, que llenará con una lista de las entradas
* de la lista entry_list
*/
int read_list (char *user_buffer, unsigned int maxchars, void *data){
int total = 0;
char buf[512];
struct list_head* pos = entry_list.next;
kifs_entry_t* item;
printk(KERN_ALERT "Entra en read_list");
list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
total+= sprintf(&buf[total],"%s\n",item->entryname);
}
if (copy_to_user(user_buffer,buf,total))
{
printk(KERN_ALERT "Fallo en copy_to_user()");
return -EINVAL;
}
printk(KERN_ALERT "Sale de read_list por las buenas");
return total;
}
/* This function must ensure that no entry will be created as long as another entry with the same name already exists.
* == Return Value ==
* NULL Entry name already exists or No space is availables
* Pointer to the kifs entry
* */
kifs_entry_t* create_kifs_entry(const char* entryname,
read_kifs_t *read_kifs,
write_kifs_t *write_kifs,
void* data){
kifs_entry_t* item;
struct list_head* pos = entry_list.next;
kifs_entry_t* itemFound = NULL;
printk(KERN_ALERT "Creando entrada %s en Kifs",entryname);
//Si la lista no está vacía
list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
if (strcmp(item->entryname,entryname) ==0){
itemFound = item;
break;
}
}
if (itemFound != NULL) {
printk(KERN_ALERT "El item existe");
return NULL;
}
//No hay espacio
if(free_list.next == &free_list) {
printk(KERN_ALERT "Error, lista llena");
return NULL;
}
pos = free_list.next;
item = list_entry(pos, kifs_entry_t, links);
item->read_kifs = read_kifs;
item->write_kifs = write_kifs;
item->data = NULL;
strcpy(item->entryname, entryname);
list_del(pos);
list_add_tail(pos,&entry_list);
printk(KERN_ALERT "Entrada %s creada correctamente", entryname);
return item;
}
/* Implementation of kifs() system call
* == Return Value ==
* -EINVAL Unsupported operation (NULL callback) or Entry not exists
* -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...)
* otherwise: Number of chars read/written (Usually maxchars value)
*/
asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars){
struct list_head* pos;// = entry_list.next;
kifs_entry_t* item;// = list_entry(pos, kifs_entry_t, links);
kifs_entry_t* itemFound = NULL;
int ret = 0;
//char usrBfr[512];
printk(KERN_ALERT "Entrado a sys_kifs");
/* Se comprueba que la llamada has sido correcta */
list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
if (strcmp(item->entryname,entry_name) ==0){
itemFound = item;
break;
}
}
if (itemFound == NULL){
printk(KERN_ALERT "La entrada %s no existe", entry_name);
return -EINVAL;
}
/* copy_from_user(usrBfr, user_buffer, maxchars);
usrBfr[maxchars]='\0';
printk(KERN_ALERT "Se ha copiado el parametro %s de la entrada %s",usrBfr, entry_name);
printk(KERN_ALERT "Hay items en la lista");
*/
/* llamadas que dependen del valor de lectura/escritura */
if(op_mode == KIFS_READ_OP && item->read_kifs!=NULL ){
ret = itemFound->read_kifs(user_buffer,maxchars,NULL);
//printk(KERN_ALERT "El item utilizado es %s, en el método de lectura",user_buffer);
}else if(op_mode == KIFS_WRITE_OP && item->write_kifs!=NULL ){
ret = itemFound->write_kifs(user_buffer,maxchars,NULL); //No sé qué pasar de valor aquí
//printk(KERN_ALERT "El item utilizado es %s, en el método de escritura",usrBfr);
}else{
ret=-EINVAL;
printk(KERN_ALERT "Algo va mal");
}
return ret;
}
/* Remove kifs entry
* == Return Value ==
* -1 Entry does not exist
* 0 success
* */
int remove_kifs_entry(const char* entry_name){
struct list_head* pos = entry_list.next;
kifs_entry_t* item = list_entry(pos, kifs_entry_t, links);
kifs_entry_t* itemFound = NULL;
printk(KERN_ALERT "Intentando eliminar entrada de Kifs");
list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
if (strcmp(item->entryname,entry_name) ==0){
itemFound = item;
break;
}
}
if (itemFound == NULL) {
printk(KERN_ALERT "La lista de kifs está vacía");
return -EINVAL;
}
list_del(pos);
item->data = NULL;
strcpy(item->entryname,"");
item->read_kifs = NULL;
item->write_kifs = NULL;
list_add_tail(pos,&free_list);
printk(KERN_ALERT "Entrada eliminada correctamente");
return 0;
}
And here is if it would be necessary the result of dmesg concerned to this issue
[ 1818.076342] ModuloUsaKifs: Unknown symbol remove_kifs_entry (err 0)
[ 1818.076590] ModuloUsaKifs: Unknown symbol create_kifs_entry (err 0)
Upvotes: 2
Views: 735
Reputation: 879
From the comments to the question:
You need to export the function names using EXPORT_SYMBOL for other parts of the kernel to call these functions. Exporting these symbols will create an entry in the symbol table from where they are looked up by other modules/kernel code. You do not need to export if only your module is using these functions.
In your case, these functions are defined in one module and are being used in another. So:
Just add EXPORT_SYMBOL(create_kifs_entry); and EXPORT_SYMBOL(remove_kifs_entry); to your code
Upvotes: 1