अग्रिम में माफी अगर यह पोस्ट थोड़ी घनी / गड़बड़ है, लेकिन मुझे इसे तैयार करने में मुश्किल समय आ रहा है ... मूल रूप से, मैं यह अध्ययन करना चाहूंगा कि हार्ड डिस्क पर क्या होता है, और मैं जानना चाहता हूं:
- क्या मेरी समझ सही है - और यदि नहीं, तो मैं गलत कहाँ जा रहा हूँ?
- क्या डिस्क पर लिखने के दौरान, पीसी पर होने वाले सभी पहलुओं के बारे में लॉग डेटा को "कैप्चर" करने का एक बेहतर उपकरण है?
अधिक विस्तार से - पहले, मैं जिस ओएस का उपयोग कर रहा हूं वह है:
$ 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
इसलिए, मेरे पास निम्नलिखित सरल हैं (जैसे कि संचालन की विफलता के लिए सामान्य जांच छोड़ दी जाती है) उपयोगकर्ता-अंतरिक्ष सी कार्यक्रम 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
मुझे पुराने सस्पेल से खींचने के लिए है क्योंकि मैं बहुत सस्पेंड करता हूं, लेकिन ऊपर बूट समय में सिस्लॉग से उचित स्निपेट की तरह लगता है, जहां 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
लिनक्स निर्मित फ़ंक्शन ट्रेसर के साथ प्रोग्राम चलाने पर क्या होता है ।
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
पेज ट्रेसिंग एंड प्रोफाइलिंग - योक्टो प्रोजेक्ट ब्लॉक डिवाइस ऑपरेशन के बारे में अधिक जानकारी प्राप्त करने के लिए blk
ट्रेसर का उपयोग करने का सुझाव देता है ftrace
, लेकिन यह इस उदाहरण के साथ मेरे लिए कुछ भी रिपोर्ट नहीं करता है। इसके अलावा, लिनक्स फाइलसिस्टम ड्राइवर्स - एनॉन इनग्लोरियन (टुटोरोफ्स) सुझाव देते हैं कि फाइलसिस्टम हैं (हो सकता है।) भी (हो) कर्नेल मॉड्यूल / ड्राइवर के रूप में लागू किया जाता है, और मैं अनुमान लगा रहा हूं कि यह मामला 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
चालक एक/dev/sda
हार्ड डिस्क के बीच DMA (?) मेमोरी मैपिंग स्थापित करता है- इस वजह से, भविष्य की सभी को पहुँचता
/dev/sda
के माध्यम सेata_piix
गिरी (जो है, मिल नहीं) के लिए पारदर्शी होना होगा - सब के बाद से गिरी देखना होगा, बस पढ़ता / स्मृति स्थल के लिए लिखते हैं (जरूरी नहीं कि विशिष्ट मिल गिरी कार्यों के लिए कॉल), जो कर रहे हैंfunction_graph
ट्रैसर द्वारा रिपोर्ट नहीं की गई है
- इस वजह से, भविष्य की सभी को पहुँचता
- बूट समय पर,
sd
ड्राइवर इसके विभाजन को "पार्स" करेगा/dev/sda
, उन्हें उपलब्ध कराएगा, और संभवतया विभाजन के बीच मेमोरी मैपिंग को हैंडल करेगा <-> डिस्क डिवाइस- फिर से, यह
sd
कर्नेल के लिए पारदर्शी के माध्यम से पहुंच संचालन करना चाहिए
- फिर से, यह
- दोनों के बाद से
ata_piix
औरsd
इन-गिरी संकलित किए जाते हैं, उनके कार्यों खत्म करते के कुछ लोगों द्वारा कब्जा कर लिया जा रहा है, भले हीftrace
, हम एक सूचना जिनमें से उन कार्यों मॉड्यूल नहीं मिल सकता से आएगा (अलग से स्रोत फ़ाइलों के साथ "मैन्युअल" सहसंबंध) - बाद में,
mount
एक विभाजन के बीच एक संबंध / बंधन स्थापित करता है, और संबंधित फाइलसिस्टम चालक (इस मामले मेंext4
)- इस बिंदु से, माउंट किए गए फाइल सिस्टम तक पहुंच के सभी
ext4
कार्यों को संभाला जाएगा - जो कर्नेल द्वारा पता लगाने योग्य हैं; लेकिन जैसाext4
कि इन-कर्नेल संकलित है, अनुरेखक हमें मूल मॉड्यूल जानकारी नहीं दे सकता है
- इस बिंदु से, माउंट किए गए फाइल सिस्टम तक पहुंच के सभी
- इसलिए, मनाया गया "जेनेरिक" लिखता है, जिसे
ext4
फ़ंक्शन के माध्यम से कहा जाता है, अंततः मेमोरी स्थानों तक पहुंच जाएगा, जिनकी मैपिंग द्वारा स्थापित किया गया हैata_piix
- लेकिन इसके अलावा,ata_piix
डेटा ट्रांसफर के साथ सीधे हस्तक्षेप नहीं करता है (यह संभवतः डीएमए द्वारा नियंत्रित किया जा रहा है (प्रोसेसर के बाहर) (s), और इस प्रकार यह पारदर्शी है)।
क्या यह समझ सही है?
कुछ संबंधित उपशाखाएँ:
- ऊपर मेरे सेटअप में, मैं एक PCI डिवाइस ड्राइवर (
ata_piix
) और एक फाइल सिस्टम ड्राइवर (ext4
) की पहचान कर सकता हूं ; लेकिन क्या चरित्र या ब्लॉक ड्राइवर "लिखने" निष्पादन पथ पर कहीं उपयोग किए जाते हैं, और यदि हां, तो वे कौन से हैं? - उन ड्राइवरों में से कौन कैशिंग को संभालेगा (इसलिए अनावश्यक डिस्क संचालन को छोड़ दिया गया है या अनुकूलित किया गया है?)
- मुझे पहले से पता है कि
/dev/shm
रैम में एक फाइलसिस्टम है;mount | grep shm
मेरे लिए रिपोर्ट:none on /dev/shm type tmpfs (rw,nosuid,nodev)
। क्या इसका मतलब यह है कि - इसके विपरीत/dev/sda
-shm
फाइलसिस्टम में बस (डीएमए) मैपिंग का अभाव है "अपने दम पर" एक डिवाइस की ओर बस पते को स्वीकार करता है; और इस प्रकारtmpfs
फाइल सिस्टम ड्राइवर के माध्यम से सभी एक्सेस वास्तविक रैम में समाप्त हो जाती है?