Вибачте заздалегідь, якщо ця публікація трохи щільна / безладна, але мені важко сформулювати її краще ... В основному, я хотів би вивчити, що відбувається під час запису на жорсткий диск, і я хотів би знати:
- Чи правильно моє розуміння нижче - а якщо ні, то де я помиляюся?
- Чи є кращий інструмент для "захоплення" даних журналу про всі аспекти, що відбуваються на ПК під час запису на диск?
Більш детально - по-перше, ОС, яку я використовую, це:
$ 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
Отже, у мене є така проста програма (наприклад, звичайні перевірки на відмову від операцій пропускаються) програма C користувача-простору 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;
}
Я будую це з gcc -g -O0 -o wtest wtest.c
. Тепер, оскільки я намагаюся написати /tmp
, зазначу, що це каталог під коренем /
- тому я перевіряю 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)
...
Отже, моя коренева файлова система /
- це один розділ /dev/sda
пристрою (і я використовую інші розділи як "автономні" диски / кріплення також). Щоб знайти драйвер цього пристрою, я використовую 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
...
Отже, /dev/sda
жорсткий диск, мабуть, обробляється ata_piix
(і 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
Мені доводиться витягувати з старого syslog, оскільки я дуже призупиняю, але вищезгадане здається правильним фрагментом із syslog під час завантаження, де драйвер ata_piix
(і sd
) запускається вперше.
Перший мій плутанина полягає в тому, що я інакше не можу спостерігати за драйверами ata_piix
або 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
Тож перше моє запитання - чому я не можу спостерігати ata_piix
тут за модулем, лише в журналах завантаження? Це тому, що ata_piix
(і sd
) вбудовані як вбудовані драйвери в (монолітне) ядро, на відміну від їх побудови як (завантажуваних) .ko
модулів ядра?
Правильно - тому зараз я намагаюся спостерігати, що відбувається при запуску програми із ftrace
вбудованим функцією відстеження функцій 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
'
... і ось фрагмент ftrace
журналу щодо write
:
4604.352690 | 0) wtest-31632 | | sys_write () { 4604.352690 | 0) wtest-31632 | 0,750 нас | 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 нас | common_file_perm (); 4604.352696 | 0) wtest-31632 | 2.198 нас | } 4604.352697 | 0) wtest-31632 | 3,573 нас | } 4604.352697 | 0) wtest-31632 | 4,997 нас | } 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 нас | _cond_resched (); 4604.352703 | 0) wtest-31632 | 1.994 нас | } 4604.352704 | 0) wtest-31632 | | __generic_file_aio_write () { ... 4604.352728 | 0) wtest-31632 | | file_update_time () { ... 4604.352732 | 0) wtest-31632 | 0,756 нас | 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 нас | _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 нас | mnt_drop_write (); 4604.352822 | 0) wtest-31632 | + 93,541 нас | } 4604.352823 | 0) wtest-31632 | | generic_file_buffered_write () { 4604.352824 | 0) wtest-31632 | 0,654 нас | iov_iter_advance (); 4604.352825 | 0) wtest-31632 | | generic_perform_write () { 4604.352826 | 0) wtest-31632 | 0,709 нас | 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 нас | __block_write_begin (); 4604.352849 | 0) wtest-31632 | + 21.128 нас | } 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 нас | 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 нас | mutex_unlock (); 4604.352911 | 0) wtest-31632 | 0,727 нас | generic_write_sync (); 4604.352912 | 0) wtest-31632 | ! 212.259 нас | } 4604.352913 | 0) wtest-31632 | ! 213.845 нас | } 4604.352914 | 0) wtest-31632 | ! 215.286 нас | } 4604.352914 | 0) wtest-31632 | 0,685 нас | __fsnotify_parent (); 4604.352916 | 0) wtest-31632 | | fsnotify () { 4604.352916 | 0) wtest-31632 | 0,907 нас | __srcu_read_lock (); 4604.352918 | 0) wtest-31632 | 0,685 нас | __srcu_read_unlock (); 4604.352920 | 0) wtest-31632 | 3,958 нас | } 4604.352920 | 0) wtest-31632 | ! 228.409 нас | } 4604.352921 | 0) wtest-31632 | ! 231.334 нас | }
Це мій другий пункт плутанини - я можу спостерігати, як користувальницький простір write()
отримав з ядром sys_write()
, як очікувалося; і в межах sys_write()
, я спостерігаю функції, пов'язані з безпекою (наприклад apparmor_file_permission()
), "загальні" функції запису (наприклад generic_file_aio_write()
), ext4
функції, пов'язані з файловою системою (наприклад ext4_journal_start_sb()
), - але я не спостерігаю нічого, пов'язаного з ata_piix
(або sd
) драйверами ?!
Сторінка « Відстеження та профілювання» - проект Yocto пропонує скористатися засобом blk
відстеження, ftrace
щоб отримати більш детальну інформацію про роботу блокових пристроїв, але в цьому прикладі для мене нічого не повідомляється. Крім того, драйвери файлової системи Linux - Annon Inglorion (tutorfs) припускають, що файлові системи (можуть?) Також (бути) реалізовані як модулі / драйвери ядра, і я гадаю, що ext4
так і є.
Нарешті, я міг присягнути, що раніше я спостерігав ім'я драйвера у квадратних дужках поруч із функцією, показаною function_graph
трекером, але, мабуть, я змішав речі - це, ймовірно, може виглядати так у стеках (назад), але не у графіку функцій. Крім того, я можу перевірити /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]
...
... і перевіривши з джерелом Linux / драйвери / ata / ata_piix.c , підтвердьте, що, наприклад piix_init_sata_map
, дійсно є функцією в ata_piix
. Що, мабуть, повинно мені сказати, що: модулі, складені в ядрі (так вони стають частиною монолітного ядра), "втрачають" інформацію про те, з якого модуля вони походять; однак завантажувані модулі, побудовані як окремі .ko
об'єкти ядра, зберігають цю інформацію (наприклад, [psmouse]
показану вище у квадратних дужках). Таким чином, також ftrace
можна було показати лише інформацію про "вихідний модуль" лише для тих функцій, що надходять із завантажуваних модулів ядра. Це правильно?
Вище взяте до уваги, це розуміння того процесу, який я маю зараз:
- Під час завантаження
ata_piix
драйвер встановлює відображення пам'яті DMA (?) Між/dev/sda
жорстким диском та жорстким диском- через це всі майбутні звернення до
/dev/sda
viaata_piix
будуть прозорими до ядра (тобто не відстежуються) - оскільки всі ядра бачать, просто читаються / записуються в місця пам'яті (не обов'язково викликає певні функції відстежуваних ядер), які не повідомляєтьсяfunction_graph
трасером
- через це всі майбутні звернення до
- Під час завантаження
sd
драйвер ще більше "розбере" розділи/dev/sda
, зробить їх доступними та, можливо, обробляє відображення пам'яті між розділами <-> дискового пристрою- знову ж таки, це повинно зробити операції доступу через
sd
прозорі до ядра
- знову ж таки, це повинно зробити операції доступу через
- Оскільки обидва
ata_piix
іsd
компілюються в ядрі, навіть якщо деякі їх функції в кінцевому підсумку захопленіftrace
, ми не можемо отримати інформацію, з якого модуля ці функції беруться (крім "ручної" кореляції з вихідними файлами) - Пізніше
mount
встановлюється зв'язок / прив'язка між розділом та відповідним драйвером файлової системи (у цьому випадкуext4
)- з цього моменту всі звернення до змонтованої файлової системи оброблялися б
ext4
функціями, які простежуються ядром; але, якext4
складено в ядрі, трекер не може дати нам інформацію про вихідний модуль
- з цього моменту всі звернення до змонтованої файлової системи оброблялися б
- Таким чином, спостережуване "загальне" записування, викликане через
ext4
функції, в кінцевому рахунку отримає доступ до місць пам'яті, відображення яких встановлюєтьсяata_piix
- але крім цього,ata_piix
не перешкоджає безпосередньо передачі даних (цим, ймовірно, керує DMA (поза процесором) (і), і таким чином прозорі до цього).
Чи правильно це розуміння?
Деякі пов'язані з цим питання
- Під час налаштування я можу визначити драйвер пристрою PCI (
ata_piix
) та драйвер файлової системи (ext4
); але чи є драйвери символів або блоків, які використовуються десь на шляху виконання "запису", і якщо так, то які вони? - Хто з цих драйверів оброблятиме кешування (настільки непотрібні дискові операції пропускаються чи оптимізуються?)
- Я знаю з того, що
/dev/shm
це файлова система в оперативній пам'яті;mount | grep shm
для мене повідомляє:none on /dev/shm type tmpfs (rw,nosuid,nodev)
. Чи означає це, що - на відміну від/dev/sda
- уshm
файловій системі просто не вистачає (DMA) відображення від "власних" адрес до адрес шини до пристрою; і, отже, всі доступ черезtmpfs
драйвер файлової системи закінчується фактичною оперативною пам'яттю?