quinta-feira, 15 de outubro de 2015

Administração dos módulos do kernel

O kernel (núcleo do sistema operacional) do Linux é modular, ou seja, trabalha com componentes que podem ou não estar carregados. Módulos podem habilitar suporte a algum hardware, habilitar funções especiais ou melhorar a segurança do sistema. Desabilitando os módulos sem uso torna o kernel mais enxuto, podendo ser usado em máquinas menos potentes.

Os módulos ficam instalados na pasta /lib/modules/<kernel>/kernel

$ ls /lib/modules/3.16.0-4-686-pae/kernel/
arch  crypto  drivers  fs  lib  mm  net  sound

Em cada pasta há centenas de módulos. Para listar o módulos atualmente carregados na memória use o comando lsmod.

$ lsmod
Module                   Size  Used by
nls_utf8               12416        0 
nls_cp437            12417        0 
vfat                      16967        0 
fat                        52647        1 vfat
...

Nesta listagem temos os módulos carregados e suas dependências. Por exemplo, o módulo vfat depende do módulo fat. Não é possível retirar o módulo fat sem antes retirar o vfat.

Vamos fazer uma demonstração retirando o módulos que controla a placa de rede. Primeiramente temos que descobrir qual é o módulos usado pela nossa interface.

$ dmesg  | grep eth
[    1.349952] e1000e 0000:00:19.0 eth0: registered PHC clock
[    1.349957] e1000e 0000:00:19.0 eth0: (PCI Express:2.5GT/s:Width x1) 50:e5:49:fc:de:9b
[    1.349959] e1000e 0000:00:19.0 eth0: Intel(R) PRO/1000 Network Connection
[    1.350007] e1000e 0000:00:19.0 eth0: MAC: 10, PHY: 11, PBA No: FFFFFF-0FF
[   11.915452] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
[   15.036594] e1000e: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[   15.036631] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[   69.254588] device eth0 entered promiscuous mode

Vemos que o módulo da placa de rede é o e1000e. Agora, como root, executamos o comando rmmod.

# rmmod e1000e

Agora a interface de rede não está mais disponível.

$ ifconfig eth0
eth0: erro obtendo informações da interface: %s: dispositivo não encontrado

Vamos recarregar o módulo.

# insmod e1000e
insmod: ERROR: could not load module e1000e: No such file or directory

O erro ocorre porque o insmod precisa do endereço completo do arquivo de módulo. Para saber onde o arquivo se encontra podemos usar o comando modinfo, que também fornece outras informações sobre um módulo.

$ modinfo e1000e
filename:       /lib/modules/3.16.0-4-686-pae/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko
version:        2.3.2-k
license:        GPL
description:    Intel(R) PRO/1000 Network Driver
author:         Intel Corporation, <linux.nics@intel.com>
srcversion:     95081067188F78203E7ECF8
alias:          pci:v00008086d000015B8sv*sd*bc*sc*i*
alias:          pci:v00008086d000015B7sv*sd*bc*sc*i*
alias:          pci:v00008086d00001570sv*sd*bc*sc*i*
alias:          pci:v00008086d0000156Fsv*sd*bc*sc*i*
alias:          pci:v00008086d000015A3sv*sd*bc*sc*i*
alias:          pci:v00008086d000015A2sv*sd*bc*sc*i*
alias:          pci:v00008086d000015A1sv*sd*bc*sc*i*
alias:          pci:v00008086d000015A0sv*sd*bc*sc*i*
...
alias:          pci:v00008086d0000105Fsv*sd*bc*sc*i*
alias:          pci:v00008086d0000105Esv*sd*bc*sc*i*
depends:        ptp
intree:         Y
vermagic:       3.16.0-4-686-pae SMP mod_unload modversions 686 
parm:           debug:Debug level (0=none,...,16=all) (int)
parm:           copybreak:Maximum size of packet that is copied to a new buffer on receive (uint)
parm:           TxIntDelay:Transmit Interrupt Delay (array of int)
parm:           TxAbsIntDelay:Transmit Absolute Interrupt Delay (array of int)
parm:           RxIntDelay:Receive Interrupt Delay (array of int)
parm:           RxAbsIntDelay:Receive Absolute Interrupt Delay (array of int)
parm:           InterruptThrottleRate:Interrupt Throttling Rate (array of int)
parm:           IntMode:Interrupt Mode (array of int)
parm:           SmartPowerDownEnable:Enable PHY smart power down (array of int)
parm:           KumeranLockLoss:Enable Kumeran lock loss workaround (array of int)
parm:           WriteProtectNVM:Write-protect NVM [WARNING: disabling this can lead to 
corrupted NVM] (array of int)
parm:           CrcStripping:Enable CRC Stripping, disable if your BMC needs the CRC (array of int)

Agora, com o caminho completo do arquivo, podemos carregar o módulo logado como root.

# insmod /lib/modules/3.16.0-4-686-pae/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko

E agora temos a interface de rede novamente.

# ifconfig eth0
eth0      Link encap:Ethernet  Endereço de HW 50:e5:49:fc:de:9b  
          inet end.: 172.20.120.4  Bcast:172.20.255.255  Masc:255.255.0.0
          endereço inet6: 2001:470:db7e:0:8000::1/64 Escopo:Global
          endereço inet6: fe80::52e5:49ff:fefc:de9b/64 Escopo:Link
          UP BROADCASTRUNNING MULTICAST  MTU:1500  Métrica:1
          RX packets:343124704 errors:407 dropped:0 overruns:0 frame:272
          TX packets:13277281 errors:0 dropped:0 overruns:0 carrier:0
          colisões:0 txqueuelen:1000 
          RX bytes:59616917901 (55.5 GiB)  TX bytes:1435011340 (1.3 GiB)
          IRQ:20 Memória:fe400000-fe420000 

Se tentarmos remover um módulo que outros módulos dependam dele teremos uma mensagem de erro. 

# rmmod fat
rmmod: ERROR: Module fat is in use by: vfat

Neste caso temos que remover primeiro o módulo vfat para depois remove o fat

# rmmod vfat
# rmmod fat

Agora, para recarregar o módulo vfat temos que primeiro carregar o módulo fat. Ou podemos usar o comando modprobe para carregar o módulo junto com suas dependências. 

# modprobe vfat
# lsmod  | grep fat
vfat                   16967  0 
fat                     52647  1 vfat

Reparem que, diferentemente do comando insmod, modprobe não precisa no endereço completo do arquivo de módulo. Você também pode remover um módulo usando "modprobe -r".

Uma listagem de módulos e suas dependências está no arquivo /lib/modules/3.16.0-4-686-pae/modules.dep. Para vermos as dependências relacionadas ao módulo fat digitamos:

$ grep fat /lib/modules/3.16.0-4-686-pae/modules.dep
kernel/fs/fat/fat.ko:
kernel/fs/fat/vfat.ko: kernel/fs/fat/fat.ko
kernel/fs/fat/msdos.ko: kernel/fs/fat/fat.ko

Podemos notar que os módulos vfat e msdos dependem do módulo fat.