Ich entschuldige mich im Voraus, wenn dieser Beitrag ein wenig unübersichtlich ist, aber es fällt mir schwer, ihn besser zu formulieren.
- Ist mein Verständnis unten richtig - und wenn nicht, wo gehe ich falsch?
- Gibt es ein besseres Tool zum "Erfassen" von Protokolldaten zu allen Aspekten, die auf dem PC während eines Schreibvorgangs auftreten?
Genauer gesagt: Das Betriebssystem, das ich verwende, ist:
$ 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
So habe ich folgendes einfaches (zB die üblichen Prüfungen auf Betriebsstörungen werden übersprungen) User-Space-C-Programm 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;
}
Ich baue das mit gcc -g -O0 -o wtest wtest.c
. Da ich nun versuche zu schreiben /tmp
, stelle ich fest, dass es sich um ein Verzeichnis unter dem Stammverzeichnis handelt /
- also überprüfe ich Folgendes 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)
...
Mein Root-Dateisystem /
ist also eine Partition des /dev/sda
Geräts (und ich verwende auch andere Partitionen als "eigenständige" Festplatten / Mounts). Um den Treiber für dieses Gerät zu finden, benutze ich 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
...
Die /dev/sda
Festplatte wird also anscheinend vom ata_piix
(und sd
) Treiber verwaltet.
$ 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
Ich muss aus älterem Syslog ziehen, da ich viel aussetze, aber das obige scheint das richtige Snippet aus dem Syslog beim Booten zu sein, wo der ata_piix
(und sd
) Treiber zum ersten Mal einschaltet.
Mein erster Punkt der Verwirrung ist, dass ich die ata_piix
oder sd
Fahrer nicht anders beobachten kann :
$ 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
Meine erste Frage lautet also: Warum kann ich das ata_piix
Modul hier nicht nur in Startprotokollen beobachten ? Liegt es daran, dass ata_piix
(und sd
) als integrierte Treiber im (monolithischen) Kernel erstellt werden und nicht als (ladbare) .ko
Kernelmodule?
Ich versuche jetzt zu beobachten, was passiert, wenn das Programm mit dem in ftrace
Linux integrierten Funktionstracer ausgeführt wird.
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
'
... und hier ist ein Auszug aus dem ftrace
Protokoll über write
:
4604.352690 | 0) wtest-31632 | | sys_write () { 4604.352690 | 0) wtest-31632 | 0,750 us | fget_light (); 4604.352692 | 0) wtest-31632 | | vfs_write () { 4604.352693 | 0) wtest-31632 | | rw_verify_area () { 4604.352693 | 0) wtest-31632 | | security_file_permission () { 4604.352694 | 0) wtest-31632 | | apparmor_file_permission () { 4604.352695 | 0) wtest-31632 | 0,811 us | common_file_perm (); 4604.352696 | 0) wtest-31632 | 2.198 us | } 4604.352697 | 0) wtest-31632 | 3,573 us | } 4604.352697 | 0) wtest-31632 | 4.979 us | } 4604.352698 | 0) wtest-31632 | | do_sync_write () { 4604.352699 | 0) wtest-31632 | | ext4_file_write () { 4604.352700 | 0) wtest-31632 | | generic_file_aio_write () { 4604.352701 | 0) wtest-31632 | | mutex_lock () { 4604.352701 | 0) wtest-31632 | 0,666 us | _cond_resched (); 4604.352703 | 0) wtest-31632 | 1.994 us | } 4604.352704 | 0) wtest-31632 | | __generic_file_aio_write () { ... 4604.352728 | 0) wtest-31632 | | file_update_time () { ... 4604.352732 | 0) wtest-31632 | 0,756 us | mnt_want_write_file (); 4604.352734 | 0) wtest-31632 | | __mark_inode_dirty () { ... 4604.352750 | 0) wtest-31632 | | ext4_mark_inode_dirty () { 4604.352750 | 0) wtest-31632 | 0,679 us | _cond_resched (); 4604.352752 | 0) wtest-31632 | | ext4_reserve_inode_write () { ... 4604.352777 | 0) wtest-31632 | | __ext4_journal_get_write_access () { ... 4604.352795 | 0) wtest-31632 | | ext4_mark_iloc_dirty () { ... 4604.352806 | 0) wtest-31632 | | __ext4_journal_stop () { ... 4604.352821 | 0) wtest-31632 | 0,684 us | mnt_drop_write (); 4604.352822 | 0) wtest-31632 | + 93.541 us | } 4604.352823 | 0) wtest-31632 | | generic_file_buffered_write () { 4604.352824 | 0) wtest-31632 | 0,654 us | iov_iter_advance (); 4604.352825 | 0) wtest-31632 | | generic_perform_write () { 4604.352826 | 0) wtest-31632 | 0,709 us | iov_iter_fault_in_readable (); 4604.352828 | 0) wtest-31632 | | ext4_da_write_begin () { 4604.352829 | 0) wtest-31632 | | ext4_journal_start_sb () { ... 4604.352847 | 0) wtest-31632 | 1,453 us | __block_write_begin (); 4604.352849 | 0) wtest-31632 | + 21.128 us | } 4604.352849 | 0) wtest-31632 | | iov_iter_copy_from_user_atomic () { 4604.352850 | 0) wtest-31632 | | __kmap_atomic () { ... 4604.352863 | 0) wtest-31632 | 0,672 us | mark_page_accessed (); 4604.352864 | 0) wtest-31632 | | ext4_da_write_end () { 4604.352865 | 0) wtest-31632 | | generic_write_end () { 4604.352866 | 0) wtest-31632 | | block_write_end () { ... 4604.352893 | 0) wtest-31632 | | __ext4_journal_stop () { ... 4604.352909 | 0) wtest-31632 | 0,655 us | mutex_unlock (); 4604.352911 | 0) wtest-31632 | 0,727 us | generic_write_sync (); 4604.352912 | 0) wtest-31632 | ! 212.259 us | } 4604.352913 | 0) wtest-31632 | ! 213.845 us | } 4604.352914 | 0) wtest-31632 | ! 215.286 us | } 4604.352914 | 0) wtest-31632 | 0,685 us | __fsnotify_parent (); 4604.352916 | 0) wtest-31632 | | fsnotify () { 4604.352916 | 0) wtest-31632 | 0,907 us | __srcu_read_lock (); 4604.352918 | 0) wtest-31632 | 0,685 us | __srcu_read_unlock (); 4604.352920 | 0) wtest-31632 | 3.958 us | } 4604.352920 | 0) wtest-31632 | ! 228.409 us | } 4604.352921 | 0) wtest-31632 | ! 231.334 us | }
Dies ist mein zweiter Punkt der Verwirrung - ich kann den User-Space beobachten, der sich erwartungsgemäß write()
mit einem Kernel-Space ergibt sys_write()
; und in der sys_write()
ich sicherheitsrelevante Funktionen (zB beobachten apparmor_file_permission()
), „generische“ Schreibfunktionen (zB generic_file_aio_write()
), ext4
Dateisystem verwandte Funktionen (zB ext4_journal_start_sb()
) - aber ich weiß nicht beobachte alles im Zusammenhang mit ata_piix
(oder sd
) -Treiber?
Auf der Seite Nachverfolgung und Profilerstellung - Yocto Project wird vorgeschlagen , den blk
Tracer in ftrace
zu verwenden, um weitere Informationen über den Betrieb von Blockgeräten zu erhalten. In diesem Beispiel wird jedoch nichts gemeldet . Außerdem schlagen Linux-Dateisystemtreiber - Annon Inglorion (tutorfs) vor, dass Dateisysteme auch als Kernelmodule / -treiber (implementiert) werden (können?), Und ich vermute, dass dies auch der Fall ist ext4
.
Schließlich hätte ich schwören können, dass ich früher den Treibernamen in eckigen Klammern neben der vom function_graph
Tracer angezeigten Funktion gesehen habe , aber ich glaube, ich hatte etwas verwechselt - es kann wahrscheinlich in Stack- (Back-) Traces so aussehen, aber nicht im Funktionsgraphen. Außerdem kann ich Folgendes einsehen /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]
...
... und überprüfe mit Linux / drivers / ata / ata_piix.c , ob zB piix_init_sata_map
tatsächlich eine Funktion in ist ata_piix
. Was mir wahrscheinlich sagen sollte: Module, die im Kernel kompiliert sind (damit sie Teil des monolithischen Kernels werden), "verlieren" die Informationen darüber, von welchem Modul sie stammen; Bei den ladbaren Modulen, die als separate .ko
Kernelobjekte erstellt wurden, bleiben diese Informationen jedoch erhalten (z. B. [psmouse]
oben in eckigen Klammern angegeben). Somit ftrace
könnten auch nur "Ursprungsmodul" -Informationen angezeigt werden, und zwar nur für die Funktionen, die von ladbaren Kernelmodulen stammen. Ist das richtig?
Unter Berücksichtigung des oben Gesagten ist dies das Verständnis, das ich derzeit von dem Prozess habe:
- Beim Booten erstellt der
ata_piix
Treiber eine DMA-Speicherzuordnung (?) Zwischen/dev/sda
und der Festplatte- Aus diesem Grund sind alle zukünftigen Zugriffe auf
/dev/sda
Viaata_piix
für den Kernel transparent (dh nicht nachvollziehbar) - da jeder Kernel nur Lese- / Schreibzugriffe auf Speicherorte ausführen würde (nicht unbedingt Aufrufe bestimmter nachvollziehbarer Kernelfunktionen) werden vomfunction_graph
Tracer nicht gemeldet
- Aus diesem Grund sind alle zukünftigen Zugriffe auf
- Beim Booten
sd
"analysiert" der Treiber außerdem die Partitionen von/dev/sda
, stellt sie zur Verfügung und verarbeitet möglicherweise die Speicherzuordnungen zwischen den Partitionen <-> Plattenlaufwerken- Auch dies sollte die Zugriffsoperationen über
sd
für den Kernel transparent machen
- Auch dies sollte die Zugriffsoperationen über
- Da beide
ata_piix
undsd
im Kernel kompiliert sindftrace
, können wir keine Informationen darüber erhalten, von welchem Modul diese Funktionen stammen würden (abgesehen von der "manuellen" Korrelation mit Quelldateien) , auch wenn einige ihrer Funktionen erfasst werden. - Baut später
mount
eine Beziehung / Bindung zwischen einer Partition und dem entsprechenden Dateisystemtreiber auf (in diesem Fallext4
)- Ab diesem Zeitpunkt würden alle Zugriffe auf das bereitgestellte Dateisystem von
ext4
Funktionen verwaltet, die vom Kernel nachverfolgt werden können. aber wieext4
im Kernel kompiliert wird, kann der Tracer gibt uns nicht die Ursprungsmodul Informationen
- Ab diesem Zeitpunkt würden alle Zugriffe auf das bereitgestellte Dateisystem von
- Somit würden die beobachteten "generischen" Schreibvorgänge, die über
ext4
Funktionen aufgerufen werden , letztendlich auf Speicherorte zugreifen, deren Zuordnung durchata_piix
- aber anders als das - festgelegt wird,ata_piix
die Datenübertragung nicht direkt stören (sie wird wahrscheinlich von DMA (außerhalb des Prozessors) verarbeitet (s) und damit für sie transparent).
Ist dieses Verständnis richtig?
Einige verwandte Unterfragen:
- In meinem obigen Setup kann ich einen PCI-Gerätetreiber (
ata_piix
) und einen Dateisystemtreiber (ext4
) identifizieren . Aber gibt es Zeichen- oder Blocktreiber, die irgendwo im Ausführungspfad "Schreiben" verwendet werden, und wenn ja, welche? - Welcher dieser Treiber würde das Caching handhaben (so dass unnötige Festplattenoperationen übersprungen oder optimiert werden?)
- Ich kenne von
/dev/shm
vorhin ein Dateisystem im RAM;mount | grep shm
für mich berichtet:none on /dev/shm type tmpfs (rw,nosuid,nodev)
. Bedeutet das, dass/dev/sda
demshm
Dateisystem - im Gegensatz zu - einfach die (DMA-) Zuordnung von "seinen" Adressen zu Busadressen zu einem Gerät fehlt? und somittmpfs
landen alle Zugriffe über den Dateisystemtreiber im eigentlichen RAM?