VFS

EEEFFEE·2023년 12월 29일

raspberrypi4-kernel

목록 보기
12/12

23.12.22 최초 작성

1. Virtual File System

  • 사용자 공간과 파일 시스템을 연결해주는 layer
  • 파일 시스템에 접근하는 일관적인 interface 를 지원
  • 함수 직접 호출이 아닌 함수 포인터를 호출하는 방식으로 작동

1.1 관련 자료구조

  • include/linux/fs.h

  • struct file

    • 사용자 관점에서 현재 열려있는 파일 관리 위한 자료구조
  • struct inode

    • 파일 시스템 단계에서 파일 관리하기 위한 자료구조
  • struct address_space

    • 파일의 메모리 주소공간과 page cache 관리하기 위한 자료구조
  • struct dentry

    • 파일 이름과 inode 관계 관리하기 위한 자료구조
  • struct super_block

    • 파일 시스템을 관리하기 위한 자료구조

1.2 자료구조간 관계

  • task_structfiles 자료구조에서 files_struct를 가르킴

  • files_struct는 파일 디스크립터를 가리키며 이 안에는 struct file자료구조와 inode, inode가 속한 struct super_block, f_dentry

  • struct file구조는 linkek list로 관리되며 파일 시스템을 조작하는 함수를 가리키는 함수 포인터(f_op), struct dentry를 가리키는 포인터(f_dentry)를 가짐

  • struct inode에는 inode와 파일 시스템을 조작하는 함수를 가리키는 함수 포인터(i_op, i_fop), 해당 inode가 속하는 struct super_block을 가리키는 포인터(i_sb), struct address_space를 나타내는 메모리 상의 주소를 가리키는 포인터(i_mapping) 존재

  • struct dentry에는 dentry를 조작하는 함수를 가리키는 함수 포인터(d_ops), 해당 inode가 속하는 struct super_block을 가리키는 포인터(d_sb), struct inode를 가리키는 포인터(d_inode)와 파일 이름을 저장하는 공간(NAME)을 관리

  • struct address_space에는 address_space를 조작하는 함수를 가리키는 함수 포인터(a_ops),struct inode를 가리키는 포인터(host), page를 관리하는 tree를 가리키는 포인터(page_tree)를 가짐

1.3 layer structure 확장

  1. application

    • 사용자가 파일을 사용하기 위한 프로그램
  2. libarary

    • system call을 더 간략하게 추상화한 계층
    • user modekernel mode사이의 전환 수행
  3. system call

    • 파일에 대한 인터페이스 지원 (open(), read(), write())
  4. virtual file system

    • 파일 시스템 인터페이스를 범용 인터페이스로 추상화한 계층
    • page/buffer cache를 통해 I/O 내용 기록
  5. specific file system

    • 각 디스크 블록을 file로 추상화
    • 각 파일과 디스크 블록을 연결
    • page/buffer cache를 통해 I/O 내용 기록
  6. block layer

    • 다양한 저장장치를 하나의 블록 장치로 추상화한 계층
    • page/buffer cache를 통해 I/O 내용 기록
    • I/O schedule 및 Journaling 담당
  7. device driver

    • device를 디스크 블록(disk block)의 집합으로 추상화
    • 디스크 블록의 크기는 페이지 프레임과 동일하며 실제 디스크와 매핑 됨
  8. device

    • 실제 물리적 장치를 말하며 platter, track, sector, cylinder, spindle로 구성 됨
    • head, arm을 통해 특정 구역의 데이터 읽음
    • seek time, rotational latency, transmission time등의 성능 지표가 있음

1.4 VFS 기능

파일 시스템과 다른 요소들 간의 상호작용

시스템 콜InitVMBlock Device
open (inode operation)
read (file_operation)
readdir (dentry_operation)
register, mount
(superblock, fs_type)
readpage, writepage
(address_space_operation)
bio_submit, bread, bwrite
(request, bio)

파일 시스템 함수

  • 함수 구현

    • 내부 함수 : 파일 시스템 내에서 사용하는 함수
    • 외부 함수 : 다른 시스템이 파일 시스템의 기능을 호출할 때 사용하는 함수

//	/src/linux-source ~~/fs/(파일 시스템)
balloc.c								//디스크 블록  관련 함수 관리
dir.c									//디렉토리 관련 함수 관리
file.c									//파일, inode 관련 함수 관리
inode.c									//inode 관리하는 함수
namei.c									//address space 관련 함수 관리
super.c									//superblock 관련 함수 관리

2. 제어 흐름 분석

ext2 기준

2.1 초기화

1. 파일 시스템 등록

  • module_init()에 등록된 init_ext2_fs()함수 실행
  • fs/ext2/super.c
    • init_ext2_fs()register_filesystem()을 호출해 ext2_fs_type을 인자로 넘겨 줌
    • ext2_fs_type은 정해져 있음
static struct file_system_type ext2_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "ext2",
	.mount		= ext2_mount,
	.kill_sb	= kill_block_super,
	.fs_flags	= FS_REQUIRES_DEV,
};
  • fs/filesystem.c
    • register_filesystem()에서 ext2_fs_typefind_filesystem()에게 넘겨줘

2. mount

  • fs/namespace.c

    • sys_mount()를 통해 do_mount() 호출, do_mount()는 상태를 확인하고 path_mount()호출
    • path_mount()를 통해 do_new_mount() 호출
    • do_new_mount()register_filesystem()에서 등록한 파일 시스템 불러옴, vfs_get_tree() 호출
  • fs/super.c

    • vfs_get_tree()에서 fc->ops->get_tree에 등록된 legacy_get_tree() 호출
  • fs/fs_context.c

    • legacy_get_tree()에서 fc->fs->type->mount등록된 ext2_mount() 호출
  • fs/ext2/super.c

    • ext2_mount()에서 mount_bdev()를 호출
  • fs/super.c

    • mount_bdev()에서 인자를 전달해 ext2_fill_super() 호출
  • fs/ext2/super.c

    • ext2_fill_super()에서 bread()를 호출해 superblock을 읽고 초기화, ext2_iget()을 통해 rootinode를 찾고 d_make_root()를 통해 마운트 포인트에 연결

2.2 open

1. 파일 찾기

  • fs/open.c
    • sys_open()에서 do_sys_open()호출, do_sys_open()에서 do_sys_openat2()호출
    • do_sys_openat2()에서 get_unused_fd()로 쓰이지 않는 fd 찾고 do_filp_open()호출
  • fs/namei.c
    • do_filp_open()를 통해 path_openat() 호출, path_openat()를 통해 link_path_walk() 호출
    • link_path_walk()에서 walk_component()를 통해 링크를 탐색하면서 경로가 유효한지 확인
    • walk_component()에서 lookup_fast()를 통해 캐시를 탐색해서 없으면 lookup_slow()를 호출
  • lookup_slow()에서 i_op->lookup()에 등록된 ext2_lookup() 함수 호출
    • fs/ext2/namei.c
      • ext2_lookup()에서 ext2_inode_by_name() 호출
    • fs/ext2/dir.c
      • ext2_inode_by_name()에서 이름으로 인자를 받아 inode탐색, ext2_find_entry() 호출

      • fs/ext2/dir.c

        • ext2_find_entry()에서 ext2_get_page()호출해 페이지(블록) 탐색, ext2_match()를 호출해 찾고자 하는 파일 이름과 일치하는 inode 탐색

2. 파일 수준 열기

  • fs/namei.c

    • do_open()에서 vfs_open()호출
  • fs/open.c

    • vfs_open()에서 do_entry_open()호출해 f->op_open()에 등록된 함수 호출

2.3 read/write

1. 시스템 호출 및 파일 조작

  • fs/read_write.c

    • sys_read()ksys_read()호출
    • ksys_read()vfs_read()호출, 권한 검사해 f_op->read에 등록된 read_iter() 함수 호출
  • include/linux/fs.h

    • read_iter() : vectored I/O를 지원해 I/O 횟수를 줄여줌, ext2_file_read_iter()를 호출
  • fs/ext2/file.c

    • ext2_file_read_iter() : ext2_dax_read_iter()를 통해 직접 저장장치에 접근하거나 ext2_dax_read_iter()를 통해 페이지 캐시를 확인함

    • mm/filemap.c

      • ext2_dax_read_iter()에서 generic_file_buffered_read() 호출
      • generic_file_buffered_read()에서 get_page()를 통해 페이지 캐시를 탐색해 있으면 해당 페이지를 반환, 없으면 generic_file_buffered_read_no_cached_page() 호출
      • generic_file_buffered_read()에서 a_ops->readpage()에 등록된 함수 ext2_readpage() 호출
    • fs/ext2/inode.c

      • ext2_readpage()에서 mpage_readpage()호출
    • mm/filemap.c

      • mpage_readpage()에서 I/O에 필요한 자료구조인struct bio를 조작하기 위해 do_mpage_readpage()호출
      • do_mpage_readpage()에서 ext2_get_block()을 통해 조작할 블록 가져옴

0개의 댓글