Crear un proceso en un modulo del kernel

Visitas: 243  
Tiempo total: 8 días con 7:3:36 hrs  

Hace algunos ayeres atrás, publique un código simple para crear un modulo Hola mundo! En freeBSD, ahora publico el código para crear un modulo que crea un proceso que muestra la información de la memoria (Similar al proceso meminfo). En si el Hola mundo es bastante fácil de realizar en freeBSD, pero en esta ocasión el código difiere en algunas instrucciones, por tratarse de otra distribución (Ubuntu 10.04 Lucid Lynx, kernel 2.6.32-38 x86_64).

Publicación anterior

http://www.elconspirador.com/2014/03/27/instalacion-de-freebsd-modulo-de-kernel-hola-mundo-e-interfaz-grafica-fluxbox/

Hola mundo

El siguiente código lo que hace es crear un modulo que cree un proceso, el cual contendrá el mensaje Hola mundo.

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>

#define PROCFS_NAME "procesox"

static int OS2_show(struct seq_file *m, void *v){
seq_printf(m, "Hola mundo\n");
return 0;
}

static int OS2_open(struct inode *inode, struct file *file){
return single_open(file, OS2_show, NULL);
}

static const struct file_operations OS2_fops = {
.owner = THIS_MODULE,
.open = OS2_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};

static int __init OS2_init(void){
printk(KERN_INFO "Cargando modulo.\r\n");
proc_create(PROCFS_NAME, 0, NULL, &OS2_fops);
printk(KERN_INFO "Completado. Procceso: /proc/%s.\r\n", PROCFS_NAME);
return 0;
}

static void __exit OS2_exit(void){
remove_proc_entry(PROCFS_NAME, NULL);
printk(KERN_INFO "Modulo deshabilitado.\r\n");
}

module_init(OS2_init);
module_exit(OS2_exit);

MODULE_LICENSE("GPL");

El código anterior, funciona de la siguiente manera: Al final del código observamos las dos instrucciones, que definen las funciones de inicio y finalización del modulo que estamos creando:

module_init(OS2_init);
module_exit(OS2_exit);

Tanto en las funciones de inicio como finalización, observamos la variable PROCS_NAME que define el nombre del proceso que se creara y se eliminara. También observamos en la función de inicio, la creación del proceso con la instrucción proc_create, a la cual le enviamos la dirección de memoria de la estructura que contiene la configuración del proceso:

static const struct file_operations OS2_fops = {
.owner = THIS_MODULE,
.open = OS2_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};

En esta estructura, observamos la llamada a la función OS2_open, esta función, devuelve la siguiente instrucción:

return single_open(file, OS2_show, NULL);

Que se ejecuta cada vez que llamamos al proceso, a continuación, definimos el código que mostrara nuestro proceso, en la función OS2_show.

Como crear el modulo

Para crear el modulo, creamos un archivo llamado OS2.c, copiamos el código c del modulo en el archivo y para tener todo más claro lo creamos en una carpeta llamada kernel. Con el comando touch Makefile creamos el archivo y agregamos el siguiente texto:

obj-m += OS2.o

A continuación buscamos la carpeta /lib/modules/$(Shell úname –r)/build, es decir la versión del kernel que estamos utilizando, y ejecutamos el siguiente código:

make -C /lib/modules/2.6.32-38-generic/build M=$PWD modules
sudo insmod OS2.ko
dmesg | tail -1
cat /proc/procesox
sudo rmmod OS2.ko
dmesg | tail -1

Con insmod cargamos el Nuevo modulo creado, mostramos los mensajes del modulo con el commando dmesg | tail -1, con cat /proc/procesox imprimimos el resultado del Hola mundo del proceso, a continuación descargamos (finalizamos) el modulo con el comando rmmod.

Mostrar la información de la memoria

Lo que hacemos es únicamente editar la función OS2_show agregando las variables globales e instrucciones necesarias para hacer funcionar el código:

/* to get works meminfo */
#include <linux/hugetlb.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/mmzone.h>
#include <linux/quicklist.h>
#include <linux/swap.h>
#include <linux/vmstat.h>
#include <linux/atomic.h>
#include <asm/page.h>
#include <asm/pgtable.h>

struct sysinfo i;
unsigned long committed;
unsigned long allowed;
struct vmalloc_info vmi;
long cached;
unsigned long pages[NR_LRU_LISTS];
int lru;

static int OS2_show(struct seq_file *m, void *v){
seq_printf(m, "Proceso:\n");
seq_printf(m, "\n");

#define K(x) ((x) << (PAGE_SHIFT - 10))
si_meminfo(&i);
for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
pages[lru] = global_page_state(NR_LRU_BASE + lru);

seq_printf(m,"MemTotal: %8lu kB\n",K(i.totalram));
seq_printf(m,"MemFree: %8lu kB\n",K(i.freeram));
seq_printf(m,"Buffers: %8lu kB\n",K(i.bufferram));
seq_printf(m,"Active: %8lu kB\n",K(pages[LRU_ACTIVE_ANON] + pages[LRU_ACTIVE_FILE]));
seq_printf(m,"Inactive: %8lu kB\n",K(pages[LRU_INACTIVE_ANON] + pages[LRU_INACTIVE_FILE]));
seq_printf(m,"Active(anon): %8lu kB\n",K(pages[LRU_ACTIVE_ANON]));
seq_printf(m,"Inactive(anon): %8lu kB\n",K(pages[LRU_INACTIVE_ANON]));
seq_printf(m,"Active(file): %8lu kB\n",K(pages[LRU_ACTIVE_FILE]));
seq_printf(m,"Inactive(file): %8lu kB\n",K(pages[LRU_INACTIVE_FILE]));
seq_printf(m,"Unevictable: %8lu kB\n",K(pages[LRU_UNEVICTABLE]));
seq_printf(m,"Mlocked: %8lu kB\n",K(global_page_state(NR_MLOCK)));
#ifdef CONFIG_HIGHMEM
seq_printf(m,"HighTotal: %8lu kB\n",K(i.totalhigh));
seq_printf(m,"HighFree: %8lu kB\n",K(i.freehigh));
seq_printf(m,"LowTotal: %8lu kB\n",K(i.totalram-i.totalhigh));
seq_printf(m,"LowFree: %8lu kB\n",K(i.freeram-i.freehigh));
#endif
#ifndef CONFIG_MMU
seq_printf(m,"MmapCopy: %8lu kB\n",K((unsigned long) atomic_long_read(&mmap_pages_allocated)));
#endif
seq_printf(m,"SwapTotal: %8lu kB\n",K(i.totalswap));
seq_printf(m,"SwapFree: %8lu kB\n",K(i.freeswap));
#undef K
return 0;
}

El código anterior lo obtenemos del código fuente del proceso meminfo, únicamente agregamos lo que necesitamos mostrar junto a las librerías necesarias. Algunas publicaciones en internet, utilizan distribuciones de GNU/Linux diferentes u otras versiones del kernel, por este motivo algunas instrucciones cambiaran, haciendo que el código mostrado aquí no funcione en por ejemplo freeBSD.

Referencias

[http://www.thegeekstuff.com/2012/04/create-proc-files/]
[http://www.thegeekstuff.com/2012/04/linux-lkm-basics/]
[http://www.linuxchix.org/content/courses/kernel_hacking/lesson8]
[http://linux.die.net/lkmpg/x769.html]
[http://linux.die.net/lkmpg/x710.html]
[http://www.cyberciti.biz/faq/check-ram-in-ubuntu/]
[http://www.thegeekstuff.com/2013/07/write-linux-kernel-module/]
[http://crashcourse.ca/introduction-linux-kernel-programming/lesson-12-adding-proc-files-your-modules-part-2]
[http://lxr.free-electrons.com/source/fs/proc/meminfo.c]


Para recibir boletines de información, por favor escribe tu correo electrónico:

Por favor ingrese un correo electrónico valido.
Registrado correctamente!