블록 드라이버는 어떤 스레드에서 블록 장치에 명령을 실행합니까?

블록 드라이버는 어떤 스레드에서 블록 장치에 명령을 실행합니까?

나는 블록 I/O 요청 순서가 다음과 같다는 것을 배웠기 때문에 현재 "Linux 커널 이해"라는 책을 읽고 있습니다. 사용자 공간 호출 => vfs 호출 => I/O 스케줄러 호출 => 블록 장치 드라이버 호출.

블록 장치 드라이버가 블록 장치(하드 디스크 등)에 명령을 내리는 곳이 어디인지 알고 싶습니다. 전용 디스패치 커널 스레드에서 명령을 실행합니까, 아니면 블록 I/O 요청이 시작되는 사용자 프로세스 스레드에서 실행합니까?

답변1

동기식 IO를 수행하지 않으면 쓰기를 수행하는 사용자는 kjournald 스레드에서 대기열을 제거하기 위한 트랜잭션을 생성하게 됩니다. (참고: 저는 다음을 사용하고 있습니다.외부 3파일 시스템 및일기=주문함, 주어진 궤도를 사용하여리눅스 3.0-rc7)

IO 스케줄러의lift_dispatch_fn 메서드에 중단점을 배치하여 무슨 일이 일어나고 있는지 확인할 수 있습니다(예: 최종 기한 IO 스케줄러의 경우deadline_dispatch_requests).

장치 대기열은 두 가지 방식으로 작동합니다.

실행될 kjournald 스레드에서 호출됩니다(ext3 파일 시스템, 기본 커밋=5로 마운트되어 5초마다 실행되도록 예약됨).

#0  deadline_dispatch_requests (q=, force=0) at block/deadline-iosched.c:246
#1  __elv_next_request (q=<optimized out>) at block/blk.h:86
#2  blk_peek_request (q=q@entry=) at block/blk-core.c:1829
#3  scsi_request_fn (q=) at drivers/scsi/scsi_lib.c:1511
#4  __blk_run_queue (q=) at block/blk-core.c:305
#5  queue_unplugged (q=, depth=1, from_schedule=<optimized out>) at block/blk-core.c:2673
#6  blk_flush_plug_list (plug=plug@entry=, from_schedule=from_schedule@entry=false) at block/blk-core.c:2755
#7  blk_finish_plug (plug=plug@entry=) at block/blk-core.c:2762
#8  journal_commit_transaction (journal=journal@entry=) at fs/jbd/commit.c:412
#9  kjournald (arg=) at fs/jbd/journal.c:152
#10 kthread (_create=) at kernel/kthread.c:96
#11 kernel_thread_helper () at arch/x86/kernel/entry_64.S:1161
#12 ?? ()

인터럽트에서 호출됨:

#0  deadline_dispatch_requests (q=, force=0) at block/deadline-iosched.c:246
#1  __elv_next_request (q=<optimized out>) at block/blk.h:86
#2  blk_peek_request (q=q@entry=) at block/blk-core.c:1829
#3  scsi_request_fn (q=) at drivers/scsi/scsi_lib.c:1511
#4  __blk_run_queue (q=) at block/blk-core.c:305
#5  blk_run_queue (q=q@entry=) at block/blk-core.c:339
#6  scsi_run_queue (q=q@entry=) at drivers/scsi/scsi_lib.c:449
#7  scsi_next_command (cmd=cmd@entry=) at drivers/scsi/scsi_lib.c:502
#8  scsi_end_request (requeue=<optimized out>, bytes=<optimized out>, error=<optimized out>, cmd=) at drivers/scsi/scsi_lib.c:574
#9  scsi_io_completion (cmd=cmd@entry=, good_bytes=<optimized out>) at drivers/scsi/scsi_lib.c:822
#10 scsi_finish_command (cmd=cmd@entry=) at drivers/scsi/scsi.c:847
#11 scsi_softirq_done (rq=<optimized out>) at drivers/scsi/scsi_lib.c:1456
#12 blk_done_softirq (h=<optimized out>) at block/blk-softirq.c:34
#13 __do_softirq () at kernel/softirq.c:238
#14 call_softirq () at arch/x86/kernel/entry_64.S:1210
#15 do_softirq () at arch/x86/kernel/irq_64.c:80
#16 invoke_softirq () at kernel/softirq.c:325
#17 irq_exit () at kernel/softirq.c:340
#18 smp_apic_timer_interrupt (regs=<optimized out>) at arch/x86/kernel/apic/apic.c:862
#19 <signal handler called>
#20 irq_stack_union ()

이제 동기 호출을 수행하는 경우 다음과 같이 request_fn 메서드가 쓰기 시스템 호출에서 직접 실행됩니다.

#0  deadline_dispatch_requests (q=, force=0) at block/deadline-iosched.c:246
#1  __elv_next_request (q=<optimized out>) at block/blk.h:86
#2  blk_peek_request (q=q@entry=) at block/blk-core.c:1829
#3  scsi_request_fn (q=) at drivers/scsi/scsi_lib.c:1511
#4  __blk_run_queue (q=) at block/blk-core.c:305
#5  queue_unplugged (q=, depth=1, from_schedule=<optimized out>) at block/blk-core.c:2673
#6  blk_flush_plug_list (plug=<optimized out>, from_schedule=from_schedule@entry=false) at block/blk-core.c:2755
#7  blk_flush_plug (tsk=<optimized out>) at include/linux/blkdev.h:880
#8  io_schedule () at kernel/sched.c:5669
#9  sleep_on_page (word=<optimized out>) at mm/filemap.c:182
#10 __wait_on_bit (wq=, q=q@entry=, action=action@entry=<sleep_on_page>, mode=mode@entry=2) at kernel/wait.c:202
#11 wait_on_page_bit (page=page@entry=, bit_nr=bit_nr@entry=13) at mm/filemap.c:571
#12 wait_on_page_writeback (page=) at include/linux/pagemap.h:394
#13 filemap_fdatawait_range (mapping=mapping@entry=, start_byte=start_byte@entry=0, end_byte=end_byte@entry=511) at mm/filemap.c:292
#14 filemap_write_and_wait_range (mapping=, lstart=0, lend=511) at mm/filemap.c:371
#15 filemap_write_and_wait_range (mapping=mapping@entry=, lstart=lstart@entry=0, lend=lend@entry=511) at mm/filemap.c:378
#16 vfs_fsync_range (file=, start=start@entry=0, end=end@entry=511, datasync=0) at fs/sync.c:176
#17 generic_write_sync (file=file@entry=, pos=pos@entry=0, count=count@entry=512) at fs/sync.c:242
#18 generic_file_aio_write (iocb=<optimized out>, iov=, nr_segs=1, pos=<optimized out>) at mm/filemap.c:2614
#19 do_sync_write (filp=, buf=<optimized out>, len=<optimized out>, ppos=) at fs/read_write.c:348
#20 vfs_write (file=file@entry=, buf=buf@entry="", count=<optimized out>, count@entry=512, pos=pos@entry=) at fs/read_write.c:377
#21 sys_write (fd=<optimized out>, buf="", count=512) at fs/read_write.c:429

답변2

현재 이해에 따르면 사용자 공간 프로세스는 시스템에 I/O 반환을 요청합니다. 그런 다음 프로세스는 작업이 완료되었음을 나타내는 커널의 인터럽트를 기다립니다. 사용자 공간은 커널이 데이터를 검색하는 방법에 신경 쓰지 않으며 신경써서도 안됩니다. vfs는 아마도 캐시 어딘가에서 데이터를 찾았을 것이므로 I/O 스케줄러는 사용자 프로세스와 아무 관련이 없습니다.

관련 정보