ขออภัยล่วงหน้าหากโพสต์นี้ค่อนข้างหนาแน่น / ยุ่ง แต่ฉันมีเวลายากที่จะกำหนดได้ดีกว่า ... โดยทั่วไปฉันต้องการที่จะศึกษาว่าเกิดอะไรขึ้นกับการเขียนฮาร์ดดิสก์และฉันต้องการที่จะรู้ว่า:
- ความเข้าใจของฉันด้านล่างถูกต้องหรือไม่ถ้าไม่ฉันจะไปไหนผิด
- มีเครื่องมือที่ดีกว่าในการ "บันทึก" บันทึกข้อมูลเกี่ยวกับทุกด้านที่เกิดขึ้นบนพีซีระหว่างการเขียนดิสก์หรือไม่?
รายละเอียดเพิ่มเติม - ก่อนอื่นระบบปฏิบัติการที่ฉันใช้คือ:
$ 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
อุปกรณ์ (และฉันใช้พาร์ติชั่นอื่นเป็นดิสก์ "สแตนด์อะโลน" / mounts ด้วย) ในการค้นหาไดรเวอร์สำหรับอุปกรณ์นี้ฉันใช้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.979 เรา | } 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]
...
... และการตรวจสอบกับแหล่งที่มาของลินุกซ์ / ไดรเวอร์ / ATA / ata_piix.cยืนยันว่าเช่นย่อมเป็นฟังก์ชั่นในpiix_init_sata_map
ata_piix
ซึ่งน่าจะบอกฉันได้ว่า: โมดูลที่รวบรวมในเคอร์เนล (ดังนั้นพวกเขากลายเป็นส่วนหนึ่งของเคอร์เนลเสาหิน) "เสีย" ข้อมูลเกี่ยวกับโมดูลที่พวกเขามาจาก; อย่างไรก็ตามโมดูลที่โหลดได้ซึ่งสร้างขึ้นเป็น.ko
วัตถุเคอร์เนลแยกต่างหากเก็บรักษาข้อมูลนั้น (เช่น[psmouse]
แสดงไว้ข้างต้นในวงเล็บเหลี่ยม) ดังนั้นยังftrace
สามารถแสดงข้อมูล "โมดูลต้นทาง" เท่านั้นสำหรับฟังก์ชันเหล่านั้นที่มาจากโมดูลเคอร์เนลที่โหลดได้ ถูกต้องหรือไม่
การพิจารณาข้างต้นนี้เป็นความเข้าใจที่ฉันมีของกระบวนการปัจจุบัน:
- เมื่อถึงเวลาบูต
ata_piix
ไดรเวอร์จะสร้างการแมปหน่วยความจำ DMA (?) ระหว่าง/dev/sda
และฮาร์ดดิสก์- ด้วยเหตุนี้การเข้าถึง
/dev/sda
ผ่านทางอนาคตทั้งหมดata_piix
จะทำให้เคอร์เนลโปร่งใส (นั่นคือไม่สามารถติดตามได้) - เนื่องจากเคอร์เนลทั้งหมดจะเห็นเพียงแค่อ่าน / เขียนไปยังตำแหน่งหน่วยความจำ (ไม่จำเป็นต้องเรียกใช้ฟังก์ชันเคอร์เนลที่ตรวจสอบย้อนกลับได้) ซึ่ง จะไม่ถูกรายงานโดยผู้function_graph
ติดตาม
- ด้วยเหตุนี้การเข้าถึง
- ในเวลาบูต
sd
ไดรเวอร์จะ "แยกวิเคราะห์" พาร์ติชัน/dev/sda
ให้พร้อมใช้งานและอาจจัดการการแมปหน่วยความจำระหว่างพาร์ติชัน <-> อุปกรณ์ดิสก์- อีกครั้งนี้จะทำให้การดำเนินการเข้าถึงผ่าน
sd
โปร่งใสให้เคอร์เนล
- อีกครั้งนี้จะทำให้การดำเนินการเข้าถึงผ่าน
- เนื่องจากทั้งคู่
ata_piix
และsd
รวบรวมในเคอร์เนลแม้ว่าฟังก์ชั่นบางฟังก์ชั่นของพวกเขาจะถูกจับโดยftrace
เราไม่สามารถรับข้อมูลที่โมดูลฟังก์ชั่นเหล่านั้นจะมาจาก (นอกเหนือจากความสัมพันธ์ "คู่มือ" กับไฟล์ต้นฉบับ) - ในภายหลัง
mount
สร้างความสัมพันธ์ / การเชื่อมโยงระหว่างพาร์ติชันและโปรแกรมควบคุมระบบแฟ้มที่เกี่ยวข้อง(ในกรณีนี้ext4
)- จากจุดนี้เป็นต้นไปการเข้าถึงระบบไฟล์ที่เมาท์ทั้งหมดจะถูกจัดการโดย
ext4
ฟังก์ชั่น - ซึ่งสามารถติดตามได้โดยเคอร์เนล แต่ดังที่ext4
คอมไพล์ในเคอร์เนลตัวติดตามไม่สามารถให้ข้อมูลโมดูลที่มากับเราได้
- จากจุดนี้เป็นต้นไปการเข้าถึงระบบไฟล์ที่เมาท์ทั้งหมดจะถูกจัดการโดย
- ดังนั้นการเขียน "ทั่วไป" ที่ถูกเรียกใช้ผ่าน
ext4
ฟังก์ชั่นในที่สุดจะเข้าถึงตำแหน่งหน่วยความจำซึ่งการแม็พถูกสร้างโดยata_piix
- แต่นอกเหนือจากนั้นata_piix
จะไม่รบกวนโดยตรงกับการถ่ายโอนข้อมูล (อาจถูกจัดการโดย DMA (ภายนอกโปรเซสเซอร์) (s) และทำให้โปร่งใสกับมัน)
ความเข้าใจนี้ถูกต้องหรือไม่
คำถามย่อยที่เกี่ยวข้อง:
- ในการตั้งค่าของฉันด้านบนฉันสามารถระบุไดรเวอร์อุปกรณ์ PCI (
ata_piix
) และไดรเวอร์ระบบไฟล์ (ext4
); แต่มีไดรเวอร์อักขระหรือบล็อกที่ใช้บางแห่งในเส้นทางการดำเนินการ "เขียน" และหากเป็นเช่นนั้น - ไดรเวอร์ใดบ้างที่จะจัดการกับแคช (ดังนั้นการดำเนินการของดิสก์ที่ไม่จำเป็นถูกข้ามหรือปรับให้เหมาะสม)
- ฉันรู้ก่อนหน้า
/dev/shm
นี้ว่าเป็นระบบไฟล์ใน RAM;mount | grep shm
สำหรับฉันรายงาน:none on /dev/shm type tmpfs (rw,nosuid,nodev)
. นั่นหมายความว่า - ตรงกันข้ามกับ/dev/sda
-shm
ระบบไฟล์เพียงขาดการแมป (DMA) จากที่อยู่ "ของตัวเอง" ไปยังที่อยู่บัสไปยังอุปกรณ์ และทำให้ทุกการเข้าถึงผ่านทางtmpfs
ไดรเวอร์ระบบไฟล์ท้ายใน RAM จริง?