리눅스 가상 파일 시스템 (VFS)
리눅스 커널의 가상 파일 시스템(Virtual File System, VFS)은 다양한 저장 장치와 파일 시스템 유형을 사용자 애플리케이션에 일관된 방식으로 제공하기 위한 추상화 계층입니다. 이 계층 덕분에 애플리케이션은 실제 파일 시스템의 종류(예: ext4, NTFS, XFS 등)에 관계없이 동일한 시스템 호출 인터페이스를 사용하여 파일 및 디렉터리에 접근할 수 있습니다.
VFS의 주요 이점은 다음과 같습니다:
- 애플리케이션 개발 단순화: 개발자는 통일된 API를 통해 여러 저장 매체에 접근할 수 있습니다.
- 새로운 파일 시스템 통합 용이성: 새로운 파일 시스템을 커널에 추가할 때, VFS가 정의한 표준 인터페이스만 구현하면 되므로 커널 핵심부를 수정할 필요가 없습니다.
VFS의 핵심 구성 요소: 네 가지 주요 객체
VFS는 파일 시스템의 다양한 측면을 관리하기 위해 네 가지 핵심 객체를 사용합니다. 이들은 파일 시스템의 구조와 동작을 추상화하는 데 필수적인 역할을 합니다.
1. 슈퍼블록 (Superblock)
슈퍼블록은 파일 시스템 전체에 대한 메타데이터를 담고 있는 객체입니다. 이는 파일 시스템의 특정 인스턴스에 대한 정보를 포함하며, 파일 시스템이 마운트될 때 생성됩니다. 일반적으로 디스크의 특정 섹터에 저장되지만, procfs나 sysfs와 같은 메모리 기반 파일 시스템의 경우 사용 시 메모리에 동적으로 생성됩니다.
다음은 슈퍼블록 구조체의 핵심 필드와 관련 메서드를 보여주는 예시입니다:
/*
* VFS 슈퍼블록 정보를 담는 구조체 정의
*/
struct vfs_superblock_info {
struct list_head superblock_list_entry; /* 모든 슈퍼블록을 연결하는 리스트 */
const struct superblock_methods_table *op_table; /* 슈퍼블록 관련 연산 함수 테이블 */
struct dentry *mount_root_dentry; /* 파일 시스템 마운트 지점의 디렉터리 항목 */
struct mutex access_mutex; /* 슈퍼블록 동기화를 위한 뮤텍스 */
int ref_count; /* 슈퍼블록 참조 횟수 */
struct list_head active_inodes; /* 이 파일 시스템의 활성 아이노드 리스트 */
struct mtd_info *storage_device_info; /* 저장 장치 관련 정보 */
fmode_t mount_flags; /* 파일 시스템 마운트 권한 및 플래그 */
};
/*
* 슈퍼블록이 구현해야 하는 연산 메서드들
*/
struct superblock_methods_table {
struct inode *(*create_new_inode)(struct vfs_superblock_info *sb_ptr); /* 새 아이노드 객체 생성 및 초기화 */
void (*release_inode_object)(struct inode *inode_obj); /* 지정된 아이노드 객체 해제 */
void (*mark_inode_dirty)(struct inode *inode_obj); /* 아이노드가 수정되었음을 VFS에 알림 */
int (*persist_inode_to_disk)(struct inode *inode_obj, int sync_wait); /* 아이노드를 디스크에 기록 (동기화 여부 지정) */
void (*on_last_ref_drop)(struct inode *inode_obj); /* 아이노드에 대한 마지막 참조가 사라졌을 때 호출 */
void (*remove_inode_from_storage)(struct inode *inode_obj); /* 지정된 아이노드를 디스크에서 삭제 */
void (*cleanup_superblock)(struct vfs_superblock_info *sb_ptr); /* 파일 시스템 언마운트 시 슈퍼블록 해제 */
void (*update_disk_superblock)(struct vfs_superblock_info *sb_ptr); /* 디스크의 슈퍼블록 정보 갱신 */
int (*synchronize_filesystem)(struct vfs_superblock_info *sb_ptr, int wait_for_completion); /* 파일 시스템 데이터 동기화 */
int (*query_fs_status)(struct dentry *dir_entry, struct kstatfs *status_buf); /* 파일 시스템 상태 정보 조회 */
int (*reconfigure_mount)(struct vfs_superblock_info *sb_ptr, int *flags_ptr, char *data_options); /* 새로운 옵션으로 파일 시스템 재마운트 */
void (*invalidate_inode_data)(struct inode *inode_obj); /* 아이노드 관련 데이터 페이지 해제 및 초기화 */
void (*initiate_unmount)(struct vfs_superblock_info *sb_ptr); /* 언마운트 작업 시작 (중단 가능) */
};
2. 아이노드 (Inode)
아이노드는 VFS의 핵심 개념 중 하나로, 파일 시스템 내의 모든 파일이나 디렉터리에 대한 메타데이터를 담고 있는 객체입니다. 여기서 '파일'은 일반 파일뿐만 아니라 디렉터리, 심볼릭 링크, 특수 장치 파일 등 파일 시스템이 관리하는 모든 유형의 데이터를 의미합니다. 아이노드 자체는 데이터 블록을 직접 포함하지 않고, 해당 데이터 블록의 위치를 가리키는 포인터를 포함합니다.
슈퍼블록과 마찬가지로 아이노드도 실제로는 디스크에 저장되어 있다가, 파일이나 디렉터리에 접근될 때 메모리에 로드되어 vfs_inode_object 구조체로 표현됩니다.
다음은 아이노드 구조체의 중요한 필드와 관련 연산자들의 예시입니다:
/*
* VFS 아이노드 객체 정보를 담는 구조체 정의
*/
struct vfs_inode_object {
struct hlist_node hash_table_entry; /* 아이노드 빠른 검색을 위한 해시 테이블 엔트리 */
struct list_head global_inode_list; /* 모든 아이노드를 연결하는 리스트 */
struct list_head superblock_inode_list; /* 특정 슈퍼블록에 속한 아이노드 리스트 */
struct list_head associated_dentries; /* 이 아이노드에 연결된 디렉터리 항목 리스트 */
unsigned long unique_id; /* 아이노드 번호 */
atomic_t reference_count; /* 아이노드 참조 횟수 */
unsigned int hard_link_count; /* 하드 링크 수 */
uid_t owner_uid; /* 소유자 사용자 ID */
gid_t group_gid; /* 소유 그룹 ID */
struct timespec last_access_time; /* 마지막 접근 시간 */
struct timespec last_modification_time; /* 마지막 수정 시간 */
struct timespec creation_time; /* 생성 시간 (또는 마지막 상태 변경 시간) */
const struct file_object_operations *inode_method_table; /* 아이노드 관련 연산 함수 테이블 */
const struct file_operations *file_method_default; /* 기본 파일 연산 함수 (파일인 경우) */
struct vfs_superblock_info *parent_superblock; /* 관련 슈퍼블록 포인터 */
struct address_space *address_space_map; /* 파일 데이터의 주소 공간 매핑 */
struct address_space device_address_map; /* 장치 주소 공간 매핑 */
unsigned int status_flags; /* 파일 시스템 관련 플래그 */
void *private_data_ptr; /* 파일 시스템별 전용 데이터 포인터 */
};
/*
* 아이노드가 구현해야 하는 연산 메서드들
*/
struct file_object_operations {
/* 새 디렉터리 항목(dentry)에 대한 아이노드를 생성합니다. */
int (*create_file_entry)(struct inode *parent_inode, struct dentry *new_dentry, int mode, struct nameidata *nd);
/* 특정 디렉터리에서 주어진 파일명에 해당하는 아이노드를 찾습니다. */
struct dentry *(*find_entry_in_dir)(struct inode *parent_inode, struct dentry *target_dentry, struct nameidata *nd);
/* 하드 링크를 생성합니다. */
int (*create_hard_link)(struct dentry *old_dentry, struct inode *target_inode, struct dentry *new_dentry);
/* 심볼릭 링크를 따라가 대상 아이노드를 찾습니다. */
void *(*resolve_symlink)(struct dentry *symlink_dentry, struct nameidata *nd);
/* resolve_symlink 호출 후 정리 작업을 수행합니다. */
void (*cleanup_symlink_context)(struct dentry *symlink_dentry, struct nameidata *nd, void *link_context);
/* 파일의 크기를 변경합니다 (잘라내기/확장). */
void (*resize_file_content)(struct inode *inode_obj);
};
3. 디렉터리 항목 (Dentry)
디렉터리 항목(dentry)은 파일 시스템 경로의 한 구성 요소를 나타내는 객체입니다. 슈퍼블록이나 아이노드와 달리, 디렉터리 항목은 디스크에 실제 저장되지 않고, 전적으로 메모리에서 관리됩니다. 이는 디렉터리 구조를 캐시하고 파일 경로를 아이노드에 매핑하는 데 사용됩니다. 각 디렉터리 항목은 파일 또는 디렉터리의 이름과 해당 아이노드를 연결하며, 디렉터리 트리의 계층 구조를 나타냅니다.