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

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

작성자 정보

  • 웹관리자 작성
  • 작성일

컨텐츠 정보

본문

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

파일시스템마운트

 

이번 강좌는 지난 강좌에 이어 파일시스템 마운트 과정의 나머지 부분에 대해 알아보기로 한다. 내용 일부는 지난 호와

관련되기 때문에 지난 호와 같이 봐야 이해가 것이라 생각한다.

 

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

 

연재 순서

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

모듈 구현하기

리눅스 커널의 메모리 관리

커널의 동기화에 관하여

파일 시스템 마운트 1

파일 시스템 마운트 2

 

 

alloc_inode 함수로 inode 할당

alloc_inode 함수를 자세히 살펴보자. 함수는 리눅스커널에서 아주 중요한 역할을 하는 구조체 하나인 inode를 할당하는 함수이다. inode 많은 필드를 가지고 있으며 초기화 과정 또한 그리 만만치 않다. inode 중요한 몇몇 필드(address_space,backing_dev_info, host, i_mapping)만을 alloc_inode 함수를 살펴보며 같이 보기로 하자.

 

 

struct inode {

struct hlist_node i_hash;

struct list_head i_list;

struct list_head i_sb_list;

struct list_head i_dentry;

unsigned long i_ino;

...

uid_t i_uid;

gid_t i_gid;

dev_t i_rdev;

...

unsigned int i_blkbits;

unsigned long i_blksize;

unsigned long i_version;

unsigned long i_blocks;

unsigned short i_bytes;

unsigned char i_sock;

...

struct inode_operations *i_op;

struct file_operations *i_fop; /* former i_opdefault_file_ops */

struct super_block *i_sb;

struct file_lock *i_flock;

struct address_space *i_mapping;

struct address_space i_data;

...

/* These three should probably be a union */

struct list_head i_devices;

struct pipe_inode_info *i_pipe;

struct block_device *i_bdev;

struct cdev *i_cdev;

...

unsigned long i_state;

unsigned long dirtied_when; /* jiffies of first dirtying*/

unsigned int i_flags;

atomic_t i_writecount;

void *i_security;

union {

void *generic_ip;

} u;

};

코드 1. inode 구조체

 

 

alloc_inode 함수는, 인수로 받은 superblock alloc_inode함수 포인터가 정의돼 있다면 정의된 함수를 호출해 inode를 할당받는다(이것 또한 hook이다. 커널의 VFS 구조는 파일시

스템의 많은 유연성을 제공하기 위해 많은 hook 제공한다).

하지만 rkfs에는 해당함수가 정의돼 있지 않기 때문에 커널은 inode_cachep 통해 inode 할당받는다.

 

static struct inode *alloc_inode(struct super_block *sb)

{

static struct address_space_operations empty_aops;

static struct inode_operations empty_iops;

static struct file_operations empty_fops;

struct inode *inode;

if (sb s_op alloc_inode)

inode = sb s_op alloc_inode(sb);

else

inode = (struct inode *)kmem_cache_alloc(inode_cachep, SLAB_KERNEL);

 

if (inode) {

struct address_space * const mapping =

&inode i_data;

inode i_sb = sb;

inode i_blkbits = sb->s_blocksize_bits;

inode i_flags = 0;

atomic_set(&inode i_count, 1);

inode i_sock = 0;

inode i_op = &empty_iops;

inode i_fop = &empty_fops;

inode i_nlink = 1;

atomic_set(&inodei_writecount, 0);

inode i_size = 0;

inode i_blocks = 0;

inode i_bytes = 0;

inode i_generation = 0;

#ifdef CONFIG_QUOTA

memset(&inodei_dquot, 0, sizeof(inodei_dquot));

#endif

inode i_pipe = NULL;

inode i_bdev = NULL;

inode i_cdev = NULL;

inode i_rdev = 0;

inode i_security = NULL;

inode dirtied_when = 0;

 

if (security_inode_alloc(inode)) {

if (inode i_sb s_op destroy_inode)

inode i_sb s_op destroy_inode(inode);

else

kmem_cache_free(inode_cachep, (inode));

return NULL;

}

mapping a_ops = &empty_aops;

mapping a_ops = &empty_aops;

mapping host = inode;

mapping flags = 0;

mapping_set_gfp_mask(mapping,GFP_HIGHUSER);

mapping assoc_mapping = NULL;

mapping backing_dev_info = &default_backing_dev_info;

/*

* If the block_device provides a backing_dev_info for client

* inodes then use that. Otherwise the inode share the bdev's * backing_dev_info.

*/

if (sb s_bdev) {

struct backing_dev_info *bdi;

bdi = sb s_bdevbd_inode_backing_dev_info;

if (!bdi)

bdi = sb s_bdev bd_inod i_mapping backing_dev_info;

mapping backing_dev_info = bdi;

}

memset(&inode u, 0, sizeof(inode u));

inode i_mapping = mapping;

}

return inode;

}

코드 2. alloc_inde 함수

 

위의 함수에서 address_space page cache 구현하는, 아주 중요한 역할을 하는 구조체이다.

또한 실제로 파일시스템에서 블록을 읽기 위한 기능을 구현하 는 address_space_operations 구조체를 포함하기도 한다. 파일을 읽기 위한 함수 테이블 필드로는 inode_operations 구조

체인 i_op file_operations 구조체인 i_fop 있다. inode_operations 구조체는 파일과 관련된 inode 만들고 삭제하는 등의 역할을 하는 inode 관련 함수들의 모음이다.

반면, file_operations 구조체는 응용 프로그래머들이 일반적으로 사용하는 open, read, write, close, ioctl, mmap 등과 연관되는 함수이다.

일반적으로 file_operations 함수들은 최종적으로 address_space_operations 함수들을 호출해 실제적으로 block device에서 페이지들을 읽게 된다.

 

 

read-ahead 메커니즘 활용

다음으로 backing_dev_info 필드는 read-ahead 관련된 정보를 저장하는 필드이다.

리눅스는 disk-based filesystem 일반적으로 사용해왔다. 지금처럼 nand memory 저장 장치로 사용하는 임베디드 리눅스가 보편화되기 전까지만 해도 그랬다. 따라서 리눅스 커널은 read-ahead 메커니즘을 사용해 파일시스템 성능을 개선했다.

disk-based 저장 장치는 특정 섹터를 찾기 위해 헤더와 실린 더를 이동해야하고, 따라서 속도가 섹터를 읽거나 쓰는 것에 비해 현저히 느리다. 때문에 섹터를 읽을 인접한 섹터들을 미리 읽어둬 페이지 캐시에 저장해 놓는 기술 , readahead 기술을 활용했다.

이는 특정 프로그램이 특정 섹터를 필요로 한다면 조만간 인접한 다른 섹터도 필요로 확률이 높을 것이라는 낙관론적 방법에서 시작됐다. 하지만 nand 같이 seek time 거의

들지 않는 저장장치를 사용할 read-ahead 주는 장점은 많이 줄어들며 심지어는 부팅타임에 시간을 잡아먹는 요소로 작용하기도 한다.

read-ahead 관련된 작업은 inode 처음 할당할 시작 된다. 먼저 default_backing_dev_info

관련자료

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

공지사항


뉴스광장


  • 현재 회원수 :  60,035 명
  • 현재 강좌수 :  35,801 개
  • 현재 접속자 :  176 명