Disculpas de antemano si esta publicación es un poco densa / desordenada, pero me cuesta formularla mejor ... Básicamente, me gustaría estudiar qué sucede en una escritura en el disco duro, y me gustaría saber:
- ¿Es correcto mi entendimiento a continuación? Y si no, ¿dónde me estoy equivocando?
- ¿Existe una herramienta mejor para "capturar" datos de registro, sobre todos los aspectos que suceden en la PC, durante una escritura de disco?
Más detalladamente: primero, el sistema operativo que estoy usando es:
$ uname -a
Linux mypc 2.6.38-16-generic #67-Ubuntu SMP Thu Sep 6 18:00:43 UTC 2012 i686 i686 i386 GNU/Linux
Por lo tanto, tengo el siguiente programa simple de espacio de usuario C (por ejemplo, se omiten las comprobaciones habituales de falla de operaciones) wtest.c
:
#include <stdio.h>
#include <fcntl.h> // O_CREAT, O_WRONLY, S_IRUSR
int main(void) {
char filename[] = "/tmp/wtest.txt";
char buffer[] = "abcd";
int fd;
mode_t perms = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
fd = open(filename, O_RDWR|O_CREAT, perms);
write(fd,buffer,4);
close(fd);
return 0;
}
Construyo esto con gcc -g -O0 -o wtest wtest.c
. Ahora, ya que estoy tratando de escribir /tmp
, noto que es un directorio bajo la raíz /
, así que verifico mount
:
$ mount
/dev/sda5 on / type ext4 (rw,errors=remount-ro,commit=0)
...
/dev/sda6 on /media/disk1 type ext4 (rw,uhelper=hal,commit=0)
/dev/sda7 on /media/disk2 type ext3 (rw,nosuid,nodev,uhelper=udisks,commit=0,commit=0,commit=0,commit=0,commit=0,commit=0)
...
Por lo tanto, mi sistema de archivos raíz /
es una partición del /dev/sda
dispositivo (y también estoy usando otras particiones como discos / montajes "independientes"). Para encontrar el controlador para este dispositivo, uso hwinfo
:
$ hwinfo --disk
...
19: IDE 00.0: 10600 Disk
...
SysFS ID: /class/block/sda
SysFS BusID: 0:0:0:0
...
Hardware Class: disk
Model: "FUJITSU MHY225RB"
...
Driver: "ata_piix", "sd"
Driver Modules: "ata_piix"
Device File: /dev/sda
...
Device Number: block 8:0-8:15
...
Entonces, el /dev/sda
disco duro aparentemente es manejado por ata_piix
(y sd
) el controlador.
$ grep 'ata_piix\| sd' <(gunzip </var/log/syslog.2.gz)
Jan 20 09:28:31 mypc kernel: [ 1.963846] ata_piix 0000:00:1f.2: version 2.13
Jan 20 09:28:31 mypc kernel: [ 1.963901] ata_piix 0000:00:1f.2: PCI INT B -> GSI 19 (level, low) -> IRQ 19
Jan 20 09:28:31 mypc kernel: [ 1.963912] ata_piix 0000:00:1f.2: MAP [ P0 P2 P1 P3 ]
Jan 20 09:28:31 mypc kernel: [ 2.116038] ata_piix 0000:00:1f.2: setting latency timer to 64
Jan 20 09:28:31 mypc kernel: [ 2.116817] scsi0 : ata_piix
Jan 20 09:28:31 mypc kernel: [ 2.117068] scsi1 : ata_piix
Jan 20 09:28:31 mypc kernel: [ 2.529065] sd 0:0:0:0: [sda] 488397168 512-byte logical blocks: (250 GB/232 GiB)
Jan 20 09:28:31 mypc kernel: [ 2.529104] sd 0:0:0:0: Attached scsi generic sg0 type 0
Jan 20 09:28:31 mypc kernel: [ 2.529309] sd 0:0:0:0: [sda] Write Protect is off
Jan 20 09:28:31 mypc kernel: [ 2.529319] sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00
Jan 20 09:28:31 mypc kernel: [ 2.529423] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
Jan 20 09:28:31 mypc kernel: [ 2.674783] sda: sda1 sda2 < sda5 sda6 sda7 sda8 sda9 sda10 >
Jan 20 09:28:31 mypc kernel: [ 2.676075] sd 0:0:0:0: [sda] Attached SCSI disk
Jan 20 09:28:31 mypc kernel: [ 4.145312] sd 2:0:0:0: Attached scsi generic sg1 type 0
Jan 20 09:28:31 mypc kernel: [ 4.150596] sd 2:0:0:0: [sdb] Attached SCSI removable disk
Tengo que retirarme del syslog anterior ya que suspendo mucho, pero lo anterior parece ser el fragmento adecuado del syslog en el momento del arranque, donde el controlador ata_piix
(y sd
) se activa por primera vez.
Mi primer punto de confusión es que no puedo observar los controladores ata_piix
o sd
:
$ lsmod | grep 'ata_piix\| sd'
$
$ modinfo sd
ERROR: modinfo: could not find module sd
$ modinfo ata_piix
ERROR: modinfo: could not find module ata_piix
Entonces, mi primera pregunta es: ¿por qué no puedo observar el ata_piix
módulo aquí, solo en los registros de tiempo de arranque? ¿Es porque ata_piix
(y sd
) están construidos como controladores incorporados en el núcleo (monolítico), en lugar de estar construidos como .ko
módulos de núcleo (cargables) ?
Bien, ahora estoy tratando de observar qué sucede al ejecutar el programa con el ftrace
rastreador de funciones incorporado de Linux.
sudo bash -c '
KDBGPATH="/sys/kernel/debug/tracing"
echo function_graph > $KDBGPATH/current_tracer
echo funcgraph-abstime > $KDBGPATH/trace_options
echo funcgraph-proc > $KDBGPATH/trace_options
echo 0 > $KDBGPATH/tracing_on
echo > $KDBGPATH/trace
echo 1 > $KDBGPATH/tracing_on ; ./wtest ; echo 0 > $KDBGPATH/tracing_on
cat $KDBGPATH/trace > wtest.ftrace
'
... y aquí hay un fragmento del ftrace
registro sobre write
:
4604.352690 | 0) wtest-31632 | El | sys_write () { 4604.352690 | 0) wtest-31632 | 0.750 nosotros | fget_light (); 4604.352692 | 0) wtest-31632 | El | vfs_write () { 4604.352693 | 0) wtest-31632 | El | rw_verify_area () { 4604.352693 | 0) wtest-31632 | El | security_file_permission () { 4604.352694 | 0) wtest-31632 | El | apparmor_file_permission () { 4604.352695 | 0) wtest-31632 | 0.811 nosotros | common_file_perm (); 4604.352696 | 0) wtest-31632 | 2.198 nosotros | } 4604.352697 | 0) wtest-31632 | 3.573 nosotros | } 4604.352697 | 0) wtest-31632 | 4.979 nosotros | } 4604.352698 | 0) wtest-31632 | El | do_sync_write () { 4604.352699 | 0) wtest-31632 | El | ext4_file_write () { 4604.352700 | 0) wtest-31632 | El | generic_file_aio_write () { 4604.352701 | 0) wtest-31632 | El | mutex_lock () { 4604.352701 | 0) wtest-31632 | 0.666 nosotros | _cond_resched (); 4604.352703 | 0) wtest-31632 | 1.994 nosotros | } 4604.352704 | 0) wtest-31632 | El | __generic_file_aio_write () { ... 4604.352728 | 0) wtest-31632 | El | file_update_time () { ... 4604.352732 | 0) wtest-31632 | 0.756 nosotros | mnt_want_write_file (); 4604.352734 | 0) wtest-31632 | El | __mark_inode_dirty () { ... 4604.352750 | 0) wtest-31632 | El | ext4_mark_inode_dirty () { 4604.352750 | 0) wtest-31632 | 0.679 nosotros | _cond_resched (); 4604.352752 | 0) wtest-31632 | El | ext4_reserve_inode_write () { ... 4604.352777 | 0) wtest-31632 | El | __ext4_journal_get_write_access () { ... 4604.352795 | 0) wtest-31632 | El | ext4_mark_iloc_dirty () { ... 4604.352806 | 0) wtest-31632 | El | __ext4_journal_stop () { ... 4604.352821 | 0) wtest-31632 | 0.684 nosotros | mnt_drop_write (); 4604.352822 | 0) wtest-31632 | + 93.541 nosotros | } 4604.352823 | 0) wtest-31632 | El | generic_file_buffered_write () { 4604.352824 | 0) wtest-31632 | 0.654 nosotros | iov_iter_advance (); 4604.352825 | 0) wtest-31632 | El | generic_perform_write () { 4604.352826 | 0) wtest-31632 | 0,709 nosotros | iov_iter_fault_in_readable (); 4604.352828 | 0) wtest-31632 | El | ext4_da_write_begin () { 4604.352829 | 0) wtest-31632 | El | ext4_journal_start_sb () { ... 4604.352847 | 0) wtest-31632 | 1.453 nosotros | __block_write_begin (); 4604.352849 | 0) wtest-31632 | + 21.128 nosotros | } 4604.352849 | 0) wtest-31632 | El | iov_iter_copy_from_user_atomic () { 4604.352850 | 0) wtest-31632 | El | __kmap_atomic () { ... 4604.352863 | 0) wtest-31632 | 0.672 nosotros | mark_page_accessed (); 4604.352864 | 0) wtest-31632 | El | ext4_da_write_end () { 4604.352865 | 0) wtest-31632 | El | generic_write_end () { 4604.352866 | 0) wtest-31632 | El | block_write_end () { ... 4604.352893 | 0) wtest-31632 | El | __ext4_journal_stop () { ... 4604.352909 | 0) wtest-31632 | 0.655 nosotros | mutex_unlock (); 4604.352911 | 0) wtest-31632 | 0.727 nosotros | generic_write_sync (); 4604.352912 | 0) wtest-31632 | ! 212.259 nosotros | } 4604.352913 | 0) wtest-31632 | ! 213.845 nosotros | } 4604.352914 | 0) wtest-31632 | ! 215.286 nosotros | } 4604.352914 | 0) wtest-31632 | 0.685 nosotros | __fsnotify_parent (); 4604.352916 | 0) wtest-31632 | El | fsnotify () { 4604.352916 | 0) wtest-31632 | 0.907 nosotros | __srcu_read_lock (); 4604.352918 | 0) wtest-31632 | 0.685 nosotros | __srcu_read_unlock (); 4604.352920 | 0) wtest-31632 | 3.958 nosotros | } 4604.352920 | 0) wtest-31632 | ! 228.409 nosotros | } 4604.352921 | 0) wtest-31632 | ! 231.334 nosotros | }
Este es mi segundo punto de confusión: puedo observar el espacio de usuario write()
resultante con un espacio de núcleo sys_write()
, como se esperaba; y dentro de sys_write()
, observo funciones relacionadas con la seguridad (p apparmor_file_permission()
. ej. ), funciones de escritura "genéricas" (p generic_file_aio_write()
. ej. ), ext4
funciones relacionadas con el sistema de archivos (p ext4_journal_start_sb()
. ej. ), pero no observo nada relacionado con ata_piix
(o sd
) controladores.
La página Tracing and Profiling - Yocto Project sugiere usar el blk
trazador ftrace
para obtener más información sobre el funcionamiento del dispositivo de bloque, pero no informa nada para mí con este ejemplo. Además, Controladores del sistema de archivos de Linux: Annon Inglorion (tutorfs) sugiere que los sistemas de archivos también se pueden implementar como módulos / controladores de kernel, y supongo que ese es el caso ext4
también.
Finalmente, podría haber jurado que anteriormente había observado el nombre del conductor entre corchetes junto a la función mostrada por el function_graph
trazador, pero supongo que había mezclado las cosas, probablemente puede parecer así en los trazados de pila (atrás), pero no en el gráfico de funciones. Además, puedo inspeccionar /proc/kallsyms
:
$ grep 'piix\| sd\|psmouse' /proc/kallsyms
...
00000000 d sd_ctl_dir
00000000 d sd_ctl_root
00000000 d sdev_class
00000000 d sdev_attr_queue_depth_rw
00000000 d sdev_attr_queue_ramp_up_period
00000000 d sdev_attr_queue_type_rw
00000000 d sd_disk_class
...
00000000 t piix_init_sata_map
00000000 t piix_init_sidpr
00000000 t piix_init_one
00000000 t pci_fixup_piix4_acpi
...
00000000 t psmouse_show_int_attr [psmouse]
00000000 t psmouse_protocol_by_type [psmouse]
00000000 r psmouse_protocols [psmouse]
00000000 t psmouse_get_maxproto [psmouse]
...
... y comprobando con la fuente Linux / drivers / ata / ata_piix.c , confirme que, por ejemplo, sí piix_init_sata_map
es una función en ata_piix
. Lo que probablemente debería decirme que: los módulos que se compilan en el núcleo (para que se conviertan en parte del núcleo monolítico) "pierden" la información sobre el módulo del que provienen; sin embargo, los módulos cargables que se construyen como .ko
objetos de kernel separados , conservan esa información (por ejemplo, se [psmouse]
muestra entre corchetes). Por lo tanto, también ftrace
solo podría mostrar información del "módulo de origen", solo para aquellas funciones que provienen de módulos del núcleo cargables. ¿Es esto correcto?
Teniendo en cuenta lo anterior, esta es la comprensión que tengo del proceso actualmente:
- En el momento del arranque, el
ata_piix
controlador establece una asignación de memoria DMA (?) Entre/dev/sda
y el disco duro- debido a esto, todos los accesos futuros a
/dev/sda
viaata_piix
serán transparentes para el kernel (es decir, no rastreables), ya que todo el kernel vería, son solo lecturas / escrituras en ubicaciones de memoria (no necesariamente llamadas a funciones específicas del kernel rastreable), que no son reportados por elfunction_graph
trazador
- debido a esto, todos los accesos futuros a
- En el momento del arranque, el
sd
controlador además "analizará" las particiones/dev/sda
, las hará disponibles y posiblemente manejará las asignaciones de memoria entre particiones <-> dispositivo de disco- nuevamente, esto debería hacer que las operaciones de acceso sean
sd
transparentes para el núcleo
- nuevamente, esto debería hacer que las operaciones de acceso sean
- Dado que ambos
ata_piix
ysd
están compilados en el núcleo, incluso si algunas de sus funciones terminan siendo capturadas porftrace
, no podemos obtener una información de qué módulo vendrían esas funciones (aparte de la correlación "manual" con los archivos fuente) - Más adelante,
mount
establece una relación / enlace entre una partición y el controlador del sistema de archivos correspondiente (en este casoext4
)- a partir de este momento, todos los accesos al sistema de archivos montado serían manejados por
ext4
funciones, que el núcleo puede rastrear; pero comoext4
se compila en el núcleo, el trazador no puede proporcionarnos la información del módulo de origen
- a partir de este momento, todos los accesos al sistema de archivos montado serían manejados por
- Entonces, las escrituras "genéricas" observadas, llamadas a través de
ext4
funciones, finalmente accederían a ubicaciones de memoria, cuyo mapeo se establece porata_piix
, pero aparte de eso,ata_piix
no interfiere directamente con las transferencias de datos (probablemente sea manejado por DMA (fuera del procesador (s), y por lo tanto transparente para ello).
¿Es correcto este entendimiento?
Algunas preguntas secundarias relacionadas:
- En mi configuración anterior, puedo identificar un controlador de dispositivo PCI (
ata_piix
) y un controlador de sistema de archivos (ext4
); pero, ¿hay controladores de caracteres o bloques utilizados en alguna parte de la ruta de ejecución de "escritura" y, de ser así, cuáles son? - ¿Cuál de esos controladores manejaría el almacenamiento en caché (por lo que se saltan u optimizan las operaciones innecesarias del disco?)
- Sé de antes que
/dev/shm
es un sistema de archivos en RAM;mount | grep shm
para mí informa:none on /dev/shm type tmpfs (rw,nosuid,nodev)
. ¿Significa eso que, en contraste con/dev/sda
, elshm
sistema de archivos simplemente carece de la asignación (DMA) de direcciones "propias" a direcciones de bus hacia un dispositivo; y por lo tanto todos los accesos a través deltmpfs
controlador del sistema de archivos terminan en la RAM real?
fuente
Respuestas:
Has hecho demasiadas preguntas en una pregunta, bueno, técnicamente no, ya que supongo que "esta comprensión es correcta" se puede responder rápidamente: no. Pero esa no es una respuesta útil.
Primero, tienes razón
ata_piix
ysd_mod
aparentemente estás compilado en tu núcleo. Esa es una elección que realiza al configurar el kernel: puede omitirlo, incluirlo o incluirlo como módulo. (Lo mismo con ext4).En segundo lugar, ha asumido que las escrituras son mucho más simples de lo que realmente son. El esquema básico de cómo funciona una escritura es que el código del sistema de archivos coloca los datos que se escribirán en la memoria, como parte de la memoria caché del búfer, y los marca como necesarios para ser escritos ("sucios"). (A menos que ya haya demasiado de eso en la RAM, en cuyo caso se ve obligado a escribir ...)
Más tarde, varias cosas (como el
bdflush
hilo del núcleo) en realidad descargan las páginas sucias en el disco. Esto es cuando vería llamadas a través de sd, scsi, libata, ata_piix, io Schedulers, PCI, etc. Si bien es muy probable que DMA esté involucrado en esa escritura, son los datos a transferir, y tal vez el comando. Pero las escrituras en disco, al menos en SATA, se manejan enviando comandos que básicamente significan "escribir sector X con datos Y". Pero definitivamente no se maneja mediante el mapeo de memoria de todo el disco (considere: puede usar discos mucho más grandes que 4GiB en máquinas de 32 bits).El subsistema de administración de memoria (no un controlador) maneja el almacenamiento en caché, junto con el sistema de archivos, la capa de bloques, etc.
tmpfs
es especial, básicamente es completamente caché. Es solo un caché especial que nunca se descarta ni se vuelve a escribir (aunque se puede cambiar). Puede encontrar el código enmm/shmem.c
y en otros lugares (intenteack-grep --cc CONFIG_TMPFS
encontrarlos).Básicamente, escribir en el disco pasa por una buena parte de los subsistemas del núcleo; La creación de redes es la única importante que se me ocurre que no está involucrada en su ejemplo. Explicarlo adecuadamente requiere un esfuerzo de larga duración; Recomiendo buscar uno.
fuente
sudo bash...
script en el OP: ftrace memory (echo 8192 > $KDBGPATH/buffer_size_kb
); ysync ;
se agrega después de la./wtest ;
llamada. Entonces puedo verflush-8
,kworker
(debajokthreadd
deps axf
), y ensync
sí mismo, como procesos enftrace
llamadas a funciones como por ejemploata_bmdma_setup()
(que es parte delibata
, que seata_piix
basa en), oget_nr_dirty_inodes()
.No tiene que adivinar cuál es su configuración. En mi máquina tengo
El archivo de configuración para este núcleo se encuentra en
/boot/config-3.2.0-4-amd64
.Usted preguntó
ata_piix
. Buscando el.config
archivo anterior , vemosCONFIG_ATA_PIIX=m
. podemos confirmar esto haciendoalternativamente
Entonces, al menos en mi kernel, es un módulo.
fuente
:)
En mi sistema,grep ATA_PIIX /boot/config-2.6.38-16-generic
diceCONFIG_ATA_PIIX=y
, lo que probablemente debería significar en este núcleo,ata_piix
es construir "en el núcleo", y no como un módulo. ¡Salud!