Z góry przepraszam, jeśli ten post jest trochę gęsty / niechlujny, ale mam trudności z jego lepszym sformułowaniem ... Zasadniczo chciałbym przestudiować, co dzieje się podczas zapisu na dysku twardym i chciałbym wiedzieć:
- Czy moje rozumienie poniżej jest prawidłowe - a jeśli nie, to gdzie się mylę?
- Czy istnieje lepsze narzędzie do „przechwytywania” danych dziennika o wszystkich aspektach zachodzących na komputerze podczas zapisu na dysku?
Bardziej szczegółowo - po pierwsze, używam systemu operacyjnego:
$ 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
Mam więc następujący prosty (np. Zwykłe kontrole niepowodzenia operacji) program C w przestrzeni użytkownika 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;
}
Buduję to za pomocą gcc -g -O0 -o wtest wtest.c
. Teraz, skoro próbuję pisać /tmp
, zauważam, że jest to katalog pod rootem /
- więc sprawdzam 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)
...
Tak więc mój główny system plików /
to jedna partycja /dev/sda
urządzenia (i używam innych partycji jako „samodzielnych” dysków / montowań). Aby znaleźć sterownik dla tego urządzenia, używam 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
...
Tak więc /dev/sda
dysk twardy jest najwyraźniej obsługiwany przez sterownik ata_piix
(i sd
).
$ 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
Muszę pobierać ze starszego sysloga, ponieważ dużo zawieszam, ale powyższe wydaje się być właściwym fragmentem sysloga z sysloga w czasie uruchamiania, w którym sterownik ata_piix
(i sd
) uruchamia się po raz pierwszy.
Moim pierwszym zamieszaniem jest to, że nie mogę inaczej obserwować sterowników ata_piix
lub sd
sterowników:
$ 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
Moje pierwsze pytanie brzmi: dlaczego nie mogę obserwować ata_piix
modułu tutaj, tylko w dziennikach rozruchu? Czy to dlatego, że ata_piix
(i sd
) są wbudowane jako wbudowane sterowniki w (monolitycznym) jądrze, a nie jako (ładowane) .ko
moduły jądra?
Tak - teraz próbuję obserwować, co dzieje się po uruchomieniu programu z ftrace
wbudowanym modułem śledzenia funkcji w systemie 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
'
... a oto fragment ftrace
dziennika dotyczący 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 | }
To mój drugi punkt pomyłki - zgodnie z oczekiwaniami mogę obserwować przestrzeń użytkownika write()
wynikającą z przestrzeni jądra sys_write()
; a na terenie sys_write()
, ja obserwować funkcje związane z bezpieczeństwem (np apparmor_file_permission()
), „rodzajowe” funkcje zapisu (np generic_file_aio_write()
) ext4
filesystem funkcje towarzyszące (np ext4_journal_start_sb()
) - ale ja nie wszystko związane obserwować ata_piix
(lub sd
) kierowców?
Strona Śledzenie i profilowanie - Projekt Yocto sugeruje użycie modułu blk
śledzącego, ftrace
aby uzyskać więcej informacji o działaniu urządzenia blokowego, ale w tym przykładzie nic mi nie zgłasza. Również sterowniki systemu plików Linux - Annon Inglorion (tutorfs) sugerują, że systemy plików są (mogą?) Również być (być) implementowane jako moduły / sterowniki jądra, i przypuszczam, że ext4
tak też jest.
Na koniec mogłem przysiąc, że wcześniej obserwowałem nazwę sterownika w nawiasach kwadratowych obok funkcji pokazanej przez function_graph
znacznik, ale wydaje mi się, że pomieszałem rzeczy - prawdopodobnie może to wyglądać tak w śladach stosu (z tyłu), ale nie na wykresie funkcji. Ponadto mogę sprawdzić /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]
...
... i sprawdzając za pomocą źródłowego Linux / drivers / ata / ata_piix.c , potwierdź, że np. piix_init_sata_map
rzeczywiście jest funkcją w ata_piix
. Co prawdopodobnie powinno mi powiedzieć, że: moduły skompilowane w jądrze (aby stały się częścią jądra monolitycznego) „tracą” informacje o tym, z którego modułu pochodzą; jednak moduły ładowalne, które są zbudowane jako osobne .ko
obiekty jądra, zachowują tę informację (np. [psmouse]
pokazano powyżej w nawiasach kwadratowych). Dlatego też ftrace
mógł pokazywać tylko informacje o „module inicjującym”, tylko dla funkcji pochodzących z ładowalnych modułów jądra. Czy to jest poprawne?
Biorąc powyższe pod uwagę, rozumiem obecnie proces:
- W czasie uruchamiania
ata_piix
sterownik ustanawia mapowanie pamięci DMA (?) Pomiędzy/dev/sda
i dyskiem twardym- z tego powodu wszystkie przyszłe dostępy do
/dev/sda
viaata_piix
będą przezroczyste dla jądra (to znaczy, że nie można go śledzić) - ponieważ wszystkie jądra by to zobaczyły, są to tylko odczyty / zapisy do miejsc w pamięci (niekoniecznie wywołania określonych funkcji śledzenia jądra), które nie są zgłaszane przezfunction_graph
tracer
- z tego powodu wszystkie przyszłe dostępy do
- W czasie uruchamiania
sd
sterownik „parsuje” partycje/dev/sda
, udostępnia je i ewentualnie obsługuje mapowania pamięci między partycjami <-> urządzenia dyskowego- znowu powinno to uczynić operacje dostępu
sd
przejrzystymi dla jądra
- znowu powinno to uczynić operacje dostępu
- Ponieważ oba
ata_piix
isd
są kompilowane w jądra, nawet jeśli niektóre z ich funkcji nie kończy się rejestrowany przezftrace
nie możemy uzyskać informacje, z których te funkcje modułu będzie pochodzić z (oprócz „manual” korelacja z plików źródłowych) - Później
mount
ustanawia relację / powiązanie między partycją a odpowiednim sterownikiem systemu plików (w tym przypadkuext4
)- od tego momentu wszystkie dostępy do zamontowanego systemu plików będą obsługiwane przez
ext4
funkcje - które są identyfikowalne przez jądro; ale jakext4
skompilowano w jądrze, moduł śledzący nie może przekazać nam informacji o module źródłowym
- od tego momentu wszystkie dostępy do zamontowanego systemu plików będą obsługiwane przez
- Tak więc zaobserwowane „ogólne” zapisy, wywoływane przez
ext4
funkcje, ostatecznie uzyskałyby dostęp do lokalizacji pamięci, których mapowanie jest ustanawiane przezata_piix
- ale poza tym,ata_piix
nie zakłóca bezpośrednio transferu danych (prawdopodobnie jest obsługiwany przez DMA (poza procesorem) (s), a zatem przejrzyste dla niego).
Czy to zrozumienie jest prawidłowe?
Niektóre powiązane pytania:
- W powyższej konfiguracji mogę zidentyfikować sterownik urządzenia PCI (
ata_piix
) i sterownik systemu plików (ext4
); ale czy są jakieś sterowniki znaków lub bloków używane gdzieś na ścieżce wykonania „zapisu”, a jeśli tak, to jakie? - Który ze sterowników obsłużyłby buforowanie (więc niepotrzebne operacje na dysku są pomijane lub optymalizowane?)
- Wiem wcześniej, że
/dev/shm
jest to system plików w pamięci RAM;mount | grep shm
dla mnie raporty:none on /dev/shm type tmpfs (rw,nosuid,nodev)
. Czy to oznacza, że - w przeciwieństwie do/dev/sda
- wshm
systemie plików po prostu brakuje (DMA) mapowanie z „własnymi” adrresses do adresów autobusowego w kierunku urządzenia; a zatem wszystkie dostępy za pośrednictwemtmpfs
sterownika systemu plików kończą się w rzeczywistej pamięci RAM?