커널 공간에서 하드 디스크 쓰기 관찰 (드라이버 / 모듈 사용)


13

이 게시물이 약간 조밀하거나 어색한 경우 사전에 사과하지만 더 잘 공식화하는 데 어려움을 겪고 있습니다 ... 기본적으로 하드 디스크 쓰기시 발생하는 사항을 연구하고 싶습니다.

  • 아래의 내 이해가 정확합니까? 아니면 어디에서 잘못 되었습니까?
  • 디스크 쓰기 도중 PC에서 발생하는 모든 측면에 대한 로그 데이터를 "캡처"하는 더 좋은 도구가 있습니까?

자세한 내용은 먼저 사용중인 OS는 다음과 같습니다.

$ 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입니까?

그렇습니다. 이제 ftraceLinux 내장 함수 추적 프로그램으로 프로그램을 실행하면 어떤 일이 발생하는지 관찰하려고합니다 .

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 us | }
 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 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 우리 | 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 us | }
 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 / drivers / 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_piixsd끝내는 그 기능 중 일부에 의해 포착되는 경우에도에서 커널 컴파일 ftrace, 우리가에서 온 것 그 기능을 모듈있는 정보를 얻을 수 없다 (떨어져에서 소스 파일과 "수동"상관 관계)
  • 나중에 mount파티션과 해당 파일 시스템 드라이버 (이 경우 ext4) 사이의 관계 / 바인딩을 설정합니다.
    • 이 시점부터 마운트 된 파일 시스템에 대한 모든 액세스 ext4는 커널에 의해 추적 가능한 기능에 의해 처리됩니다 . 그러나 ext4커널 내에서 컴파일 된 것처럼 추적 프로그램은 원래 모듈 정보를 제공 할 수 없습니다.
  • 따라서 ext4함수 를 통해 호출 된 "일반적인"쓰기 는 궁극적으로 매핑이 설정된 메모리 위치에 액세스합니다. ata_piix그러나 그 이외의 경우 ata_piix데이터 전송을 직접 방해하지 않습니다 (아마도 DMA (프로세서 외부)에서 처리 함) (들), 따라서 투명합니다).

이 이해가 맞습니까?

관련 하위 질문 :

  • 위의 설정에서 PCI 장치 드라이버 ( ata_piix)와 파일 시스템 드라이버 ( ext4)를 식별 할 수 있습니다 . "쓰기"실행 경로 어딘가에 사용되는 문자 또는 블록 드라이버가 있습니까? 그렇다면 어떤 것입니까?
  • 캐싱을 처리 할 드라이버는 무엇입니까 (따라서 불필요한 디스크 작업을 건너 뛰거나 최적화 하시겠습니까?)
  • 전에는 /dev/shmRAM의 파일 시스템 이라는 것을 알고 있습니다 . mount | grep shm나를 위해 보고서 : none on /dev/shm type tmpfs (rw,nosuid,nodev). 합니까 그 평균이 - 달리 /dev/sda- shm파일 시스템이 간단하게하는 장치에 버스 주소 "자신의"adrresses에서 (DMA) 매핑이 부족; 따라서 tmpfs파일 시스템 드라이버 를 통한 모든 액세스 는 실제 RAM으로 끝나는가?

4
안녕 sdaau. 이것은 좋은 질문이지만이 게시물의 길이는 너무 길며 몇 가지 질문이 있습니다. 헬프 데스크 질문을하는 것보다는 이해하기 위해 노력하는 것이 좋습니다. 이는 우리가 주로 여기에 도달하는 것입니다. 이 질문들 각각은 그 자체로 긴 대답을 얻을 만합니다. 최소한 게시물을 명확하게 정의 된 조각으로 나누고 각 조각을 별도의 질문에 넣어 일련의 질문을 만드는 것이 좋습니다.
Faheem Mitha

그런 다음 이러한 질문을 함께 또는 순차적으로 게시 할 수 있습니다. 질문 내에서 다른 질문을 참조하면 괜찮습니다.
Faheem Mitha

1
질문을 정리하는 데 도움이 필요한 정보가 필요하면 대화방으로 들어가서 사람들과 대화하는 것이 좋습니다. 우리는 이미 그것에 대해 이야기하고 있습니다. :-)
Faheem Mitha

@FaheemMitha의 의견에 감사드립니다. 비슷한 의심이 있었지만 실제로 질문을 줄이는 방법을 모르겠습니다. 지금까지 채팅을 사용할 수 있다는 것을 알지 못했습니다. 그런 종류의 조언을 묻는 메타를 사용); 다음 번에 채팅을 시도해보십시오. 고맙게도 이번에는 매우 수용 가능한 답변으로 해결되었습니다 ... 건배!
sdaau

@ sdaau, 디스크 액세스를 모니터링하는 방법을 알아 냈습니까?
ransh

답변:


10

"이 이해가 맞습니까?"라는 질문에 빨리 대답 할 수있을 것입니다. 그러나 그것은 유용한 답변이 아닙니다.

첫째, 당신은에 대한 권리있어 ata_piixsd_mod컴파일에있는 커널에 분명히. 이는 커널을 구성하기위한 선택입니다. 커널을 생략하거나 포함 시키거나 모듈로 포함시킬 수 있습니다. (ext4와 동일).

둘째, 쓰기가 실제보다 훨씬 단순하다고 가정했습니다. 쓰기 작동 방식의 기본 개요는 파일 시스템 코드가 데이터를 버퍼 캐시의 일부로 메모리에 기록하고 기록 할 필요 ( "더러운")로 표시한다는 것입니다. (RAM에 이미 너무 많은 것이 없다면 실제로 쓰기를 수행해야합니다 ...)

나중에, bdflush커널 스레드 와 같은 다양한 것들이 실제로 더티 페이지를 디스크로 플러시합니다. 이것은 sd, scsi, libata, ata_piix, io scheduler, PCI 등을 통한 호출을 볼 때입니다. 해당 쓰기에 DMA가있을 가능성이 높지만 전송 될 데이터 및 명령 일 수 있습니다. 그러나 적어도 SATA에서 디스크 쓰기는 기본적으로 "데이터 Y로 섹터 X 쓰기"를 의미하는 명령을 전송하여 처리됩니다. 그러나 전체 디스크를 메모리 매핑하여 처리 할 수는 없습니다 (32 비트 시스템에서 4GiB보다 훨씬 큰 디스크를 사용할 수 있음).

캐싱은 파일 시스템, 블록 레이어 등과 함께 메모리 관리 서브 시스템 (드라이버 아님)에 의해 처리됩니다.

tmpfs특별 합니다. 기본적으로 전적으로 캐시입니다. 버려지거나 다시 쓰지 않는 특별한 캐시입니다 (스왑 아웃 가능하더라도). 코드 mm/shmem.c와 다른 여러 위치 에서 코드를 찾을 수 있습니다 (코드 ack-grep --cc CONFIG_TMPFS찾기).

기본적으로 디스크 쓰기는 커널 서브 시스템의 상당 부분을 통과합니다. 네트워킹은 제가 생각할 수있는 유일한 주요 사항입니다. 책을 제대로 설명하려면 책 길이가 필요합니다. 하나를 찾는 것이 좋습니다.


안녕하세요 @derobert-답변 해 주셔서 감사합니다. 내가 잃어버린 정확한 정보가 들어 있습니다! 원래 사용자와 커널 공간에 대한 간단한 그림을 찾는 것으로 시작했지만 곧 하드 디스크 쓰기가 내가 완전히 이해하는 것이 아니며 그다지 쉽지 않다는 사실을 깨달았습니다. 노력 노력! 건배!
sdaau

작은 참고 사항 : sudo bash...OP 의 스크립트 에서이 답변의 일부 설명 (예 : 더티 페이지 플러싱)을 볼 수 있습니다 . ftrace 메모리가 증가합니다 ( echo 8192 > $KDBGPATH/buffer_size_kb); 및 sync ;사후이 추가됩니다 ./wtest ;호출. 그럼 볼 수있는 flush-8, kworker(이하 kthreaddps axf)과 sync그 자체를 처리로서 ftrace예와 같은 함수를 호출 ata_bmdma_setup()(일부인 libata, ata_piix토대로이) 또는 get_nr_dirty_inodes().
sdaau

4

그래서 첫 번째 질문은-왜 부팅시 로그에서만 ata_piix 모듈을 볼 수 없습니까? ata_piix (및 sd)가 (로드 가능한) .ko 커널 모듈로 빌드되는 것이 아니라 (모 놀리 식) 커널에서 내장 드라이버로 빌드 되었기 때문입니까?

구성이 무엇인지 짐작할 필요가 없습니다. 내 컴퓨터에는

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

이 커널의 설정 파일은 다음 위치에 있습니다. /boot/config-3.2.0-4-amd64 .

에 대해 물었습니다 ata_piix. 위 .config파일을 검색하면이 나타납니다 CONFIG_ATA_PIIX=m. 우리는 이것을함으로써 이것을 확인할 수 있습니다

dlocate ata_piix.ko   

대안 적으로

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

적어도 내 커널에서는 모듈입니다.


@FaheemMitha에 대해 많은 감사를 전합니다. 이전에 구성 파일에 대해 들어 본 적이 있지만 어떤 이유로 든이 예제에서 완전히 잊어 버렸습니다. 멋지게 발견되었습니다! :)내 시스템 에서이 커널에서 의미 하는 것은 모듈이 아니라 "커널 내"빌드 grep ATA_PIIX /boot/config-2.6.38-16-generic라고 말합니다 . 건배! CONFIG_ATA_PIIX=yata_piix
sdaau
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.