Módulo del kernel que interactúa con llamada al sistema (C)

Iniciado por kaostias, 30 Noviembre 2013, 12:55 PM

0 Miembros y 1 Visitante están viendo este tema.

kaostias

Buenas, estoy programando un módulo propio para el kernel de linux (Estoy trabajando sobre debian 6 con kernel 2.6.39.4) que interactúa con una llamada al sistema. Son dos muy sencillos. La llamada funciona perfectamente y exporta funcionalidad que permite a un módulo insertarse en una lista de entradas y registrar en ella dos funciones, una de escritura y otra de lectura.

El módulo es un contador, y las funciones de lectura y escritura son la suma del contador y la consulta del número actual. Su escritura sólo suma si todo va bien, y su lectura devuelve en el buffer del usuario la copia del valor. El problema es que al hacer el makefile del módulo recibo el error:

Citar
"insmod: error inserting 'ModuloUsaKifs.ko': -1 Unknown symbol in module"

Y no sé exáctamente por qué no reconoce Kifs, que según creo, está integrado en el sistema correctamente (Incluidas las fuentes, modificado el planificador, añadido a la tabla de llamadas, incluida la cabecera, compilado el kernel, instalado el nuevo, y probado con un programa aparte, aunque sólo pruebo sys_kifs, mi llamada al sistema, exporto también create_kifs_entry y remove_kifs_entry mediante <linux/kifs.h>)
Este es mi makefile, es muy estándar y no contemplo nada especial, porque se supone que kifs ya está en las fuentes de linux y así lo incluyo en el módulo.
¿Podría alguien orientarme hacia dónde está mi fallo?

Citarobj-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


Este es el módulo. Siento la falta de comentarios, todavía no lo he acabado y está un poco guarro(Esto es como tener visita con la casa sucia) Tengo algunos includes de más porque aún no los he borrado, he reutilizado algo de código de aquí y allá.

#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/kifs.h>
#include <asm-generic/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("List Kernel Module para DSO");
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);
//initialices the module
int sum(char *user_buffer, unsigned int maxchars, void *data){
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_ALERT) "problemas en lect";
return -EINVAL;
}
return len;

}

int metodoInicial(void){

counter = 0;
if(create_kifs_entry("counter",sum,lect,NULL))
{
counter = 0;
printk(KERNEL_ALERT "modulo abierto correctamente");
}
printk(KERNEL_ALERT "Error, módulo counter incorrectamente agregado a kifs");
}

void metodoFinal(void){

if(remove_kifs_entry("counter")){
printk(KERNEL_ALERT "modulo cerrado correctamente");
}
printk(KERNEL_ALERT "Error, módulo counter incorrectamente borrado de kifs");
}

module_init(metodoInicial);
module_exit(metodoFinal);



Esta es la llamada al sistema, por si pudiese ser algo relacionado con esto, sinceramente ya no sé qué puede ser porque me estoy volviendo loco.

#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 fuction 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;
}


Y por si acaso también subo el .h de kifs, mi llamada al sistema.

#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 fuction 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


Muchas gracias por vuestro tiempo




Para ser concretos el mensaje del sistema es:
Citar


make -C /lib/modules/2.6.39.4.mikernel/build M=/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs modules
make[1]: se ingresa al directorio `/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]: se sale del directorio `/usr/src/linux-headers-2.6.39.4.mikernel'


- ¡Éste código sin documentar es un galimatías!
- Es tuyo, de hace 3 semanas
- ¡Es una obra maestra aunque esté sin documentar! ¿Qué decías que hace?

dato000

No termino de entender en que consiste el archivo del modulo ModuloUsaKifs.ko

No se que tipo de variable es esta:

kifs_entry_t* create_kifs_entry

Y en cambio en el remove_kifs_entry hay un retorno de cero siempre.


No se tanto sobre el uso de makefile, pero creo que debe ser un problema con la libreria kifs.h



kaostias

#2
Gracias por tu respuesta dato000

remove_kifs_entry devuelve -EINVAL cuando no se encuentra el dato o la lista está vacía, es un valor de la librería errno.h (Creo), echale un ojo y lo verás

kifs_entry_t* te devuelve un puntero a la propia entrada de kifs que yo he creado (No me gusta mucho, yo devolvería un entero pero las indicaciones me obligan a ello). kifs_entry_t es una estructura, puedes comprobar su forma en el .h que está subido.

ModuloUsaKifs es el .c primero que he subido. Consta de dos métodos, sum y lect:
-sum
Lo único que hace es incrementar un contador que se inicializa en 0 en la carga del módulo
-Escritura
Devuelve en el buffer del usuario el valor del contador en una cadena de caracteres y devuelve el número de caracteres de la cadena


Muchas gracias por tu tiempo

Por si a alguien más le sirve de guía, dmesg | tail me da la siguiente info

Citar
[ 1818.076342] ModuloUsaKifs: Unknown symbol remove_kifs_entry (err 0)
[ 1818.076590] ModuloUsaKifs: Unknown symbol create_kifs_entry (err 0)





¿Podría ser algo relacionado con la siguiente línea? ¿Cómo paso la función por parámetro? (*read_kifs o write_kifs)?

kifs_entry_t* create_kifs_entry(const char* entryname,
read_kifs_t *read_kifs,
write_kifs_t *write_kifs,
void* data);


Yo la paso así:

create_kifs_entry("counter",sum,lect,NULL)

Y la declaración es la siguiente:

int sum(char *user_buffer, unsigned int maxchars, void *data)

¿Puede alguien con más experiencia que yo orientarme?




Gracias por la respuesta. Investigando y preguntando en otros foros, alguien me dio la solución al problema, y es añadir las siguientes dos líneas al final del todo de mi llamada al sistema, "kifs.c":

EXPORT_SYMBOL(create_kifs_entry);
EXPORT_SYMBOL(remove_kifs_entry);
- ¡Éste código sin documentar es un galimatías!
- Es tuyo, de hace 3 semanas
- ¡Es una obra maestra aunque esté sin documentar! ¿Qué decías que hace?