Çekirdek alanında sabit disk yazmayı gözlemleme (sürücüler / modüller ile)


13

Bu yazı biraz yoğun / dağınıksa önceden özür dilerim, ama daha iyi formüle etmekte zorlanıyorum ... Temel olarak, bir sabit disk yazma üzerine neler olduğunu incelemek istiyorum ve bilmek istiyorum:

  • Aşağıdaki anlayışım doğru mu - değilse, nerede yanlış gidiyorum?
  • Bir disk yazma sırasında, bilgisayarda meydana gelen tüm yönler hakkında günlük verilerini "yakalamak" için daha iyi bir araç var mı?

Daha ayrıntılı olarak - ilk olarak, kullandığım işletim sistemi:

$ 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

Yani, aşağıdaki basit (örneğin işlemlerin başarısızlığı için olağan kontroller atlanır) kullanıcı alanı C programı var 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;
}

Bunu ile inşa ediyorum gcc -g -O0 -o wtest wtest.c. Şimdi, yazmaya çalıştığımdan beri /tmp, kök altında bir dizin olduğuna dikkat /ediyorum - bu yüzden kontrol ediyorum 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)
...

Bu yüzden, kök dosya sistemim cihazın /bir bölümüdür /dev/sda(ve diğer bölümleri de "bağımsız" diskler / bağlar olarak kullanıyorum). Bu aygıtın sürücüsünü bulmak için şunu kullanıyorum 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
...

Yani, /dev/sdasabit disk görünüşte sürücü ata_piix(ve sd) tarafından ele alınmaktadır .

$ 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

Ben çok askıya olarak eski syslog çekmek zorunda, ama yukarıda ata_piix(ve sd) sürücü ilk kez başladığında , önyükleme zamanında sistem pasajı uygun snippet gibi görünüyor .

İlk kafa karışıklığım, ata_piixveya sdsürücüleri başka türlü gözlemleyemem :

$ 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

Öyleyse ilk sorum - ata_piixmodülü burada neden göremiyorum , sadece önyükleme zamanı günlüklerinde? Çünkü ata_piix(ve sd) (yüklenebilir) .koçekirdek modülleri olarak inşa edilmesinin aksine (monolitik) çekirdeğe yerleşik sürücüler olarak mı inşa edilmiş ?

Tamam - şimdi, programı ftraceLinux yerleşik işlev izleyicisi ile çalıştırdıktan sonra neler olduğunu gözlemlemeye çalışıyorum .

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
'

... ve işte ftracegünlükle ilgili bir pasaj write:

4604.352690 | 0) wtest-31632 | | sys_write () {
 4604.352690 | 0) wtest-31632 | 0.750 bize | 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 bize | }
 4604.352697 | 0) wtest-31632 | 3.573 bize | }
 4604.352697 | 0) wtest-31632 | 4.979 bize | }
 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 bize | ) (_Cond_resched;
 4604.352703 | 0) wtest-31632 | 1.994 bize | }
 4604.352704 | 0) wtest-31632 | | __generic_file_aio_write () {
...
 4604.352728 | 0) wtest-31632 | | file_update_time () {
...
 4604.352732 | 0) wtest-31632 | 0.756 bize | 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 bize | ) (_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 bize | ) (Mnt_drop_write;
 4604.352822 | 0) wtest-31632 | + 93.541 bize | }
 4604.352823 | 0) wtest-31632 | | generic_file_buffered_write () {
 4604.352824 | 0) wtest-31632 | 0.654 bize | iov_iter_advance ();
 4604.352825 | 0) wtest-31632 | | generic_perform_write () {
 4604.352826 | 0) wtest-31632 | 0.709 bize | 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 bize | ) (__Block_write_begin;
 4604.352849 | 0) wtest-31632 | + 21.128 bize | }
 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 bize | ) (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 bize | ) (Mutex_unlock;
 4604.352911 | 0) wtest-31632 | 0.727 bize | generic_write_sync ();
 4604.352912 | 0) wtest-31632 | ! 212.259 bize | }
 4604.352913 | 0) wtest-31632 | ! 213.845 bize | }
 4604.352914 | 0) wtest-31632 | ! 215.286 bize | }
 4604.352914 | 0) wtest-31632 | 0.685 bize | __fsnotify_parent ();
 4604.352916 | 0) wtest-31632 | | fsnotify () {
 4604.352916 | 0) wtest-31632 | 0.907 bize | ) (__Srcu_read_lock;
 4604.352918 | 0) wtest-31632 | 0.685 bize | ) (__Srcu_read_unlock;
 4604.352920 | 0) wtest-31632 | 3.958 bize | }
 4604.352920 | 0) wtest-31632 | ! 228.409 bize | }
 4604.352921 | 0) wtest-31632 | ! 231.334 bize | }

Bu benim ikinci karışıklık noktam - Beklendiği gibi write()bir çekirdek alanı ile sonuçlanan kullanıcı alanını gözlemleyebilirim sys_write(); ve içinde sys_write(), ben (örn güvenlikle ilgili işlevleri gözlemlemek apparmor_file_permission()(örn), "jenerik" yazma fonksiyonları generic_file_aio_write(),) ext4(örn ilgili işlevleri dosya sistemi ext4_journal_start_sb()) - ama do not ile ilgili her şeyi gözlemlemek ata_piix(veya sd) sürücülerin?!

Sayfa İzleme ve profil oluşturma - Yocto Projesi kullanarak anlaşılacağı blkiçinde izleyici ftraceblok aygıt operasyon hakkında daha fazla bilgi almak için, ancak bu örnekle benim için hiçbir şey bildirir. Ayrıca, Linux Dosya Sistemi Sürücüleri - Annon Inglorion (tutorfs) , dosya sistemlerinin çekirdek modülleri / sürücüleri olarak da (can?) Uygulandığını ve bunun da böyle olduğunu tahmin ediyorum ext4.

Son olarak, daha önce function_graphizleyicinin gösterdiği işlevin yanındaki köşeli parantezlerde sürücü adını gözlemlediğime yemin edebilirdim , ama sanırım bir şeyler karıştırdım - muhtemelen yığın (geri) izlerinde böyle görünebilir, ancak değil fonksiyon grafiğinde. Ayrıca şunları da inceleyebilirim /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]
...

... ve kaynak Linux / drivers / ata / ata_piix.c ile kontrol ederek , örneğin piix_init_sata_mapgerçekten bir işlev olduğunu doğrulayın ata_piix. Muhtemelen bana şunu söylemelidir: çekirdekte derlenen modüller (böylece monolitik çekirdeğin bir parçası olurlar) hangi modülden geldikleri bilgisini "kaybederler"; bununla birlikte, ayrı .koçekirdek nesneleri olarak inşa edilen yüklenebilir modüller bu bilgiyi korur (örneğin [psmouse], köşeli parantez içinde gösterilmiştir). Bu nedenle, ftracesadece yüklenebilir çekirdek modüllerinden gelen işlevler için yalnızca "kaynak modül" bilgilerini gösterebilir. Bu doğru mu?

Yukarıdakiler dikkate alındığında, şu anda bu süreçle ilgili sahip olduğum anlayış:

  • Önyükleme zamanında ata_piixsürücü /dev/sdave sabit disk arasında bir DMA (?) Bellek eşlemesi oluşturur
    • bu nedenle, gelecekteki tüm erişimleri /dev/sdaaracılığı ata_piix(izlenebilir değildir) çekirdeğe şeffaf olacak - çekirdek görecekti tüm beri, sadece (ille değil spesifik izlenebilir çekirdek fonksiyonları çağrıları) bellek konumlarına yazar / okur, hangi function_graphizleyici tarafından rapor edilmez
  • Önyükleme zamanında, sdsürücü ayrıca bölümlerini "ayrıştırır", /dev/sdakullanılabilir hale getirir ve muhtemelen bölümler <-> disk aygıtı arasındaki bellek eşlemelerini işler.
    • yine, erişim işlemlerini sdçekirdeğe şeffaf hale getirmelidir
  • Her ikisi de ata_piixve sdçekirdek içinde derlendiğinden, işlevlerinden bazıları yakalansa bile ftrace, bu işlevlerin hangi modülden geleceği hakkında bilgi alamayız (kaynak dosyalarıyla "manuel" korelasyon dışında)
  • Daha sonra mountbir bölüm ile ilgili dosya sistemi sürücüsü arasında bir ilişki / bağ kurar (bu durumda ext4)
    • bu noktadan sonra, bağlı dosya sistemine tüm erişim ext4, çekirdek tarafından izlenebilir işlevler tarafından gerçekleştirilecektir; ancak ext4çekirdekte derlendiği gibi , izleyici bize kaynak modül bilgilerini veremez
  • Dolayısıyla, ext4işlevler aracılığıyla çağrılan gözlenen "genel" yazma işlemleri sonuçta eşlemesi tarafından oluşturulan bellek konumlarına erişecektir ata_piix- ancak bunun dışında ata_piixveri aktarımlarına doğrudan müdahale etmez (muhtemelen DMA tarafından işlenir (işlemcinin dışında) ve dolayısıyla şeffaftır).

Bu anlayış doğru mu?

İlgili bazı sorular:

  • Yukarıdaki kurulumumda bir PCI aygıt sürücüsü ( ata_piix) ve bir dosya sistemi sürücüsü ( ext4); ancak "yazma" yürütme yolunda bir yerde kullanılan karakter ya da blok sürücüleri var mı?
  • Bu sürücülerden hangileri önbelleğe almayı işleyebilir (böylece gereksiz disk işlemleri atlanır veya optimize edilir?)
  • Bundan önce /dev/shmRAM'de bir dosya sistemi olduğunu biliyorum ; mount | grep shmBenim için raporlar: none on /dev/shm type tmpfs (rw,nosuid,nodev). Demek oluyor o - aksine /dev/sda- shmdosya sistemi basitçe bir cihaz doğru otobüs adreslerine "kendi" adrresses (DMA) eşleştirmesini yoksun; ve böylece tmpfsdosya sistemi sürücüsü üzerinden tüm erişim gerçek RAM ile sonuçlanır?

4
Merhaba sdaau. Bu iyi bir soru, ancak bu yazının uzunluğu aşırı ve orada birkaç soru var. Yardım masası soruları sormaktan ziyade, çoğunlukla burada aldığımız şeyleri anlamaya çalıştığınız övgüye değer. Bu soruların her biri kendi başına uzun bir cevabı hak edecektir. En azından yayınınızı açıkça tanımlanmış parçalara ayırmanızı ve her parçayı ayrı bir soruya koymanızı ve böylece bir dizi soru oluşturmanızı öneririm.
Faheem Mitha

Ardından bu soruları birlikte veya sırayla gönderebilirsiniz. Bir soru içinde başka bir soruya (veya sorulara) başvurursanız, sorun değil.
Faheem Mitha

1
Sorunuzu temizleme konusunda ipuçları istiyorsanız, sohbet odasına girmenizi ve oradaki insanlarla konuşmanızı öneririm. Burada zaten bunun hakkında konuşuyorduk. :-)
Faheem Mitha

Yorum için çok teşekkürler, @FaheemMitha - Ben de benzer şüphelerim vardı, ama soruları nasıl keseceğimden gerçekten emin değildim - ve şimdiye kadar bunun için sohbeti kullanabileceğimin farkında değildim (ve meraklı değildim) bu tür tavsiyeleri sormak için meta kullanma); kesinlikle bir dahaki sefere sohbet verecek. Neyse ki, bu kez çok kabul edilebilir bir cevap ile çalıştı ... Şerefe!
sdaau

@sdaau, disk erişiminin nasıl izleneceğini anladınız mı?
Ransh

Yanıtlar:


10

Bir soruda çok fazla şey sordunuz - teknik olarak değil, sanırım “bu anlayış doğru mu” hızlı bir şekilde cevaplanabilir: hayır. Ama bu yararlı bir cevap değil.

İlk olarak, çekirdeğiniz konusunda haklısınız ata_piixve sd_modderlenmiş olursunuz. Bu, çekirdeği yapılandırırken yaptığınız bir seçimdir - atlayabilir, ekleyebilir veya bir modül olarak ekleyebilirsiniz. (Ext4 ile aynı).

İkincisi, yazarların gerçekte olduğundan çok daha basit olduğunu varsaydınız. Bir yazmanın nasıl çalıştığının temel taslağı, dosya sistemi kodunun tampon belleğin bir parçası olarak belleğe yazılacak verileri koyması ve yazılması gereken ("kirli") olarak işaretlemesidir. (RAM'de zaten çok fazla olmadıkça, bu durumda aslında yazma yapmak zorunda kalır ...)

Daha sonra, çeşitli şeyler ( bdflushçekirdek ipliği gibi) kirli sayfaları diske temizler. Bu, sd, scsi, libata, ata_piix, io zamanlayıcılar, PCI, vb. Üzerinden çağrıları gördüğünüz zamandır. Bu yazma işleminde büyük olasılıkla DMA söz konusu olduğunda, aktarılacak veriler ve belki de komuttur. Ancak en azından SATA'da olan disk yazma işlemleri, temelde "veri X ile X kesimini yaz" anlamına gelen komutlar göndererek işlenir. Ancak kesinlikle tüm diski bellek eşleyerek ele alınmaz (düşünün: 32 bit makinelerde 4GiB'den çok daha büyük diskleri kullanabilirsiniz).

Önbellek, dosya sistemi, blok katmanı vb. İle birlikte bellek yönetimi alt sistemi (sürücü değil) tarafından gerçekleştirilir.

tmpfsözeldir, temelde tamamen önbellektir. Asla atılmayan veya geri yazılmayan özel önbelleği (takas edilebilir olsa da). Kodu mm/shmem.cve diğer birçok yerde ack-grep --cc CONFIG_TMPFSbulabilirsiniz ( bulmaya çalışın ).

Temel olarak, diske yazmak çekirdeğin alt sistemlerinin iyi bir kısmından geçer; networking, aklınıza gelen tek büyük örnek. Düzgün bir şekilde açıklanması, kitap boyu çaba gerektirir; Aradığınızı tavsiye ederim.


Merhaba @derobert - Cevabınız için çok, çok teşekkürler; tam da eksik olduğum bilgileri içeriyor! Başlangıçta çekirdek alanı ile kullanıcı arasında basit bir örnek aramaya başladım, ancak yakında bir sabit disk yazma işleminin tam olarak anladığım bir şey olmadığını ve o kadar da önemsiz olmadığını fark ettim. uzun çaba! Şerefe!
sdaau

Küçük bir not: sudo bash...OP'deki komut dosyasında bu cevaptaki açıklamanın bir kısmı (örn. Kirli sayfaların yıkanması) gözlemlenebilir : ftrace bellek artırılır ( echo 8192 > $KDBGPATH/buffer_size_kb); ve çağrıdan sync ;sonra eklenir ./wtest ;. Sonra görebilir flush-8, kworkeraltında ( kthreaddin ps axf) ve synckendisi, süreçler olarak ftraceörneğin gibi fonksiyonları çağrı ata_bmdma_setup()(bir parçası olan libata, ata_piixüzerine inşa) ya da get_nr_dirty_inodes().
sdaau

4

İlk sorum şu: ata_piix modülünü neden sadece önyükleme zamanı günlüklerinde gözlemleyemiyorum? Ata_piix (ve sd), (yüklenebilir) .ko çekirdek modülleri olarak inşa edilmesinin aksine (monolitik) çekirdeğe yerleşik sürücüler olarak inşa edildiğinden mi?

Yapılandırmanızın ne olduğunu tahmin etmek zorunda değilsiniz. Makinemde var

$ uname -a
Linux orwell 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux

Bu çekirdek için yapılandırma dosyası adresinde bulunur /boot/config-3.2.0-4-amd64.

Sen sordun ata_piix. Yukarıdaki .configdosyayı ararken görüyoruz CONFIG_ATA_PIIX=m. bunu yaparak onaylayabiliriz

dlocate ata_piix.ko   

alternatif olarak

dpkg -S ata_piix.ko

linux-image-3.2.0-4-amd64: /lib/modules/3.2.0-4-amd64/kernel/drivers/ata/ata_piix.ko

En azından benim çekirdeğimde, bu bir modül.


Bunun için çok teşekkürler, @FaheemMitha - yapılandırma dosyasını daha önce duyduğumda (ve kullandığımda), bazı nedenlerden dolayı bu örnekte tamamen unuttum; güzel benekli! :)Benim sistemimde, muhtemelen bu çekirdeği kastedilmesi gereken bir modül olarak değil, "çekirdek içi" oluşturmak grep ATA_PIIX /boot/config-2.6.38-16-genericolduğunu söylüyor . Şerefe! CONFIG_ATA_PIIX=yata_piix
sdaau
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.