강좌
클라우드/리눅스에 관한 강좌입니다.
리눅스 분류

Step by Step 커널 프로그래밍 강좌⑤

작성자 정보

  • 웹관리자 작성
  • 작성일

컨텐츠 정보

본문

Step by Step 커널 프로그래밍 강좌

파일시스템마운트

 

 

이번 강좌에서는 파일 시스템의 동작과정에 대하여 알아보기로 한다. 파일 시스템의 read/write 대한 내용은 다른 많은 리눅스 커널 책에도 소개되어 있다. 그러므로 이번 강좌와 다음 강좌에서는 파일 시스템의 마운트 과정에 대하여 자세히 분석하며 파일 시스템의 동작 과정을 이해하도록 예정이다.

 

_ 김민찬 KLDP 멤버, 전문 프로그래머

 

연재 순서

커널 프로그래밍 환경 구축하기와 특징

모듈 구현하기

리눅스 커널의 메모리 관리

커널의 동기화에 관하여

파일 시스템 마운트 1

파일 시스템 마운트 2

 

sys_mount 함수 호출 과정을 항상 참조하라

이번 강좌에서는 파일 시스템의 분석을 위해 간단한 파일 시스템을 사용하며 분석할 것이다. rkfs라는 파일 시스템이며 이 파일 시스템에 관련된 사항은 다음 URL 참조하면 된다.

 

http://www.geocities.com/ravikiran_uvs/articles/rkfs.html

 

먼저 사용자가 파일시스템을 mount 하게 되면 커널의 다른 system call들과 마찬가지로 커널의 sys_mount 함수가 호출된다.

먼저 sys_mount 분석하기 전에 주의 사항이 있다. 함수는 여러 중요한 함수들이 굉장히 깊이 있게 연결되어 있다. 그러므로 소스를 분석하다 보면 자신이 지금 어디에 서있는지 길을 잃어버리는 경우가 많다. 그러므로 항상 [그림 1] 참조하여 자신이 지금 어느 곳에 서있는지 기억하고 있어야 것이다.

 

sys_mount 인자로 넘겨받은 데이터들을 커널 메모리에 복사한 , 실제적인 mount operation 처리하는 do_mount 함수를 호출한다.

do_mount 함수는 기본적인 sys_mount 함수의 C++ overriding 같은 역할을 한다. 넘겨받은 파라미터 flags 따라서 실제 일을 담당하는 함수 하나를 호출해준다. 호출되는 함수들은 다음과 같다.

 

do_remount : flags MS_REMOUNT 옵션이 있을

do_loopback : flags MS_BIND 옵션이 있을

do_move_mount : flags MS_MOVE 있을

do_new_mount: 외의 모든 경우

 

위의 함수를 호출하기 , 먼저 sys_mount로부터 넘겨받은 파라미터들의 간단한 유효성 검사를 수행한다. 다음 mount point dentry, vfsmount 등의 구조체를 얻어오기위하여 path_lookup 함수를 호출한다. vfsmount 다음과 같은 필드를 갖는다.

 

image001.jpg

 

 

struct vfsmount

{

struct list_head mnt_hash;

struct vfsmount *mnt_parent; // 우리의 vfsmount가 마운트된 파일이 속해있는 vfsmount

struct dentry *mnt_mountpoint; /* mount point 파일 과 관련된 dentry /*

struct dentry *mnt_root; /* root of the mounted tree */

struct super_block *mnt_sb; /* vfsmount root inode 관련된 superblock */

struct list_head mnt_mounts; /* vfsmountchildren vfsmount들의 리스트 /*

struct list_head mnt_child; /* child간의 연결 리스트 /*

atomic_t mnt_count;

int mnt_flags;

int mnt_expiry_mark; /* true if marked for expiry */

char *mnt_devname; /* Name of device e.g./dev/dsk/hda1 */

struct list_head mnt_list;

struct list_head mnt_fslink; /* link in fs-specific expiry list */

struct namespace *mnt_namespace; /* containing namespace */

};

1. vfsmount 구조체

 

 

do_new_mount 함수에 대한 호출

다음으로 do_new_mount 함수에 대한 호출을 살펴볼 것이다.

do_new_mount 다음과 같이 호출된다.

 

static int do_new_mount(struct nameidata *nd, char *type, int flags,

int mnt_flags, char *name, void *data)

{

struct vfsmount *mnt;

if (!type || !memchr(type, 0, PAGE_SIZE))

return -EINVAL;

/* we need capabilities... */

if (!capable(CAP_SYS_ADMIN))

return -EPERM;

mnt = do_kern_mount(type, flags, name, data);

if (IS_ERR(mnt))

return PTR_ERR(mnt);

return do_add_mount(mnt, nd, mnt_flags, NULL);

}

코드 1. do_new_mount

 

함수는 파라미터로 nameidata 구조체와 type, flags,mnt_flags, mount되는 device name, data_page 받는다. 함수는 함수는 do_kern_mount 함수를 호출하여 superblock, dentry, address_space 관련된 구조체들을 생성하고 연결한다. 그런 do_add_mount 함수를 호출하여

namespace tree 연결시킨다. 함수를 자세히 살펴보기로 하자.

 

 

do_kern_mount() 함수는 다음과 같다.

 

struct vfsmount *

do_kern_mount(const char *fstype, int flags, const

char *name, void *data)

{

struct file_system_type *type = get_fs_type(fstype);

struct super_block *sb = ERR_PTR(-ENOMEM);

struct vfsmount *mnt;

int error;

char *secdata = NULL;

if (!type)

return ERR_PTR(-ENODEV);

mnt = alloc_vfsmnt(name);

if (!mnt)

goto out;

...

sb = type get_sb(type, flags, name, data);

if (IS_ERR(sb))

goto out_free_secdata;

error = security_sb_kern_mount(sb, secdata);

if (error)

goto out_sb;

mnt mnt_sb = sb;

mnt mnt_root = dget(sb s_root);

mnt mnt_mountpoint = sb s_root;

mnt mnt_parent = mnt;

mnt mnt_namespace = current namespace;

up_write(&sb s_umount);

put_filesystem(type);

return mnt;

코드 2. do_kern_mount

 

 

함수는 먼저 get_fs_type 아규먼트로 패스된 fstype 패스 mount file_system_type 구조체를 찾는다

 

struct file_system_type {

const char *name;

int fs_flags;

struct super_block *(*get_sb)

(struct file_system_type *, int,

const char *, void *);

void (*kill_sb) (struct super_block *);

struct module *owner;

struct file_system_type * next;

struct list_head fs_supers;

};

코드 3. file_system_type 구조체

 

구조체는 register_filesystem 함수로 파일시스템을 등록할 파라미터로 사용된다. 구조체의 필드 가장 중요한 필드는 get_sb 함수 포인터이다. 함수는 파일시스템 개발

자가 커널에 있는 VFS(Virtual Filesystem Layer) hook(갈고리) 걸어 놓는 것이다. 이렇게 callback 함수를 두는 이유는 VFS general 인터페이스를 이용하되 자신에 입맛에 맞게 부분을 수정하려는 것이다. 위의 함수 get_sbsuperblock 대한 초기화를 담당하게 되는데 파일시스템별로 superblock 많은 필드들이 서로 다르다. 그러므로 커널은 위와 같은 hook 있는 인터페이스를 제공하여 파일시스템 개발자들에게 꿈과 희망을 주는 것이다.

다음으로는 alloc_vfsmnt 호출하여 아규먼트로 넘어온 name 해당하는 vfsmount 구조체를 만든다. 이때 vfsmount mnt_cache 통하여 만들어지며 여러 필드들이 초기화된다. 아규먼트로 패스된 name vfsmount 구조체필드의 mnt_devname 저장된다.

 

파일 시스템의 Specific Layer 넘어가자

다음은 get_sb 호출한다. 부분에서 우리는 최초로 VFS generic layer에서 파일 시스템의 Specific Layer로 넘어온 것이다. 필자는 filesystem specific 부분에 대한 이해를 돕기 위하여 간단한 ram file system rfks 예를 들어 설명한다. (rfks 소스 - 부록 참고). get_sb 함수는 rfks file_system_type 다음과 같이 정의되어 있다

 

static struct file_system_type rkfs = {

name: "rkfs",

get_sb: rkfs_get_sb,

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,156 명
  • 현재 강좌수 :  36,513 개
  • 현재 접속자 :  275 명