2008년 08월 22일
램디스크 이미지 만들기
출처 : http://cafe.naver.com/devctrl.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=722
일반 PC와 마찬가지로 임베디드 시스템에서도전원 공급이 끊겼을 때 자료가 지속될 수 있는 저장 장치가 필요하다. 특히 리눅스에서는 '/'로 표기되는 디렉토리에 저장 장치를마운트해야 부팅이 끝난다. 램디스크는 임베디드 시스템에서 사용할 저장 매체의 대안 중 하나이다.
하드 디스크가 없는 임베디드 시스템에서는 SDRAM과 FLASH ROM에 쉘과 응용 프로그램을 담아 놓을 파일 시스템을 만들어 놓게 된다.
임베디드 시스템에서 일반적으로 사용되고 있는, 램디스크를 이용한 파일 시스템에 대해 알아본다.
램디스크란
램디스크는 RAM의 일부를 블럭 디바이스처럼사용하는 기술로 부팅 디스크에 주로 사용된다. 부팅 디스크의 역활은 여러 가지가 있다. 시스템 복구 디스크 용도로 주로사용되며, 과거에 CD-ROM 부팅이 보편화되지 않았을 때는 설치 디스크의 용도로도 쓰였다. 이런 용도의 디스켓에는1.44MB라는 적은 용량에 많은 유틸리티를 담아내야 하므로, 램디스크에 유틸리티를 저장한 후, 압축해 플로피 디스켓에 담는방식을 사용한다.
최근의 리눅스 배포판은 CD-ROM 부팅을주로 사용하는데, 이 때도 램디스크를 사용한다. 하지만 과거의 플로피 디스크로 부팅하는 경우와는 달리 부족한 용량을 이유로램디스크를 사용하는 것은 아니다. 이 때는 다음과 같은 필요에 의해 램디스크를 사용한다. 커널은 컴파일시에 내장된 최소 집합의드라이버와 함께 올라오고, 추가 장치 모듈은 램디스크에서 읽히는 것이다.
mkdir -p
no error if existing, make parent directories as needed
ex) # mkdir -p /games/adventure/demo
'/' 아래에 있는 "games" 폴더부터 "demo" 폴더에 이르기 까지 모든 폴더를 생성한다.
dd if=<input-file> of=<output-file> bs=<BYTES> count=<BLOCKS>
copy a file, converting and formatting according to the options.
ex) dd if=/boot/vmlinuz of=/dev/fd0 bs=8k
리눅스 부트 플로피를 만드는 명령어이다. /boot/vmlinuz가 바로 리눅스 커널이다. 이것을 플로피 디스크로 복사하는것이다. "bs=", "count=" 옵션으로 램디스크의 크기를 정해 줄 수 있다. (블럭의 크기 X 블럭의 개수 = 램디스크의크기)
위 명령어를 풀어서 쓰면, "/boot/vmlinuz와 /dev/fd0이 존재한다면 /boot/vmlinuz를 8192(8k) 바이트 단위로 읽어들여서 /dev/fd0으로 복사하라"이다.
losetup loop_device file
losetup -d loop_device
set up and control loop device.
used to associate devices with regular files or block devices, to detach loop devices and to query the status of a loop devie.
/dev/loop0, /dev/loop1,... loop devices(major=7)
-d detach the file or device associated with the specified loop device.
mkfs [-V] [-t fstype] [fs-options] device [size]
build a Linux file system (make filesystem)
-t Specifies the type of file system to built. if not specified, the default file system type(currently ext2) is used.
ex) # mkfs -t ext2 /dev/fd0 1440
플로피 디스크를 리눅스용으로 포맷하라는 명령어이다. 리눅스의 기본 파일시스템인 ext2로 포맷한다. /dev/fd0은 디바이스 중 플로피 디스크를 가리킨다.
mke2fs [OPTIONS] device [blocks-count]
create an ext2/3 filesystem
-b block-size, Specify the size of blocks in bytes. Valid block size values are 1024, 2048, 4096 bytes per block.
-q Quiet excution. Useful if mke2fs is run in a script.
-F Force mke2fs to run, even if the specified device is not a block special device, or appears to be mounted.
[1]# dd if=/dev/zero of=rdi bs=1k count=4k
0으로 채워진 rdi라는 파일을 dd 유틸리티를 사용해 만든다. 4096k(1k X 4k) 크기로 만든다.
[2]# losetup /dev/loop0 rdi
파일을 루프백 디바이스에 연결해주는 역활을 한다.
루프백 디바이스를 사용해 파일을 블럭 디바이스처럼 취급 할 수 있도록 하는 과정이다. 여기서 루프백 디바이스란 파일을 하드 디스크처럼 인식시켜 주는 장치이다.
[3]# mke2fs /dev/loop0
[2]번의 과정을 거쳐 블럭 디바이스로 인식된 rdi 파일을 ext2 파일 시스템으로 포맷하는 과정이다.
[4]# mount -t ext2 /dev/loop0 /mnt/ramdisk
먼저 "mkdir -p /mnt/ramdisk"로 마운트할 디렉토리를 생성해주고 플로피나 CD-ROM을 마운트 하듯 램디스크를 마운트한다.
[5]# cd /mnt/ramdisk
ls를 실행해보면 lost+found디렉토리가 보일 것이다. 램디스크에 필요한 디렉토리를 만들고 응용 프로그램들을 복사하여 구성한다(mkdir -p, cp -a).리눅스의 루트 파일 시스템은 일반적으로 최소한 /bin, /proc, /etc, /dev, /lib, /mnt, /usr디렉토리가 요구된다.
ex) mknod /mnt/ramdisk/dev/uart c 240 0
임시 터미널 디바이스로 사용하는 UART 디바이스 파일을 만드는 과정이다.
[6]# umount /mnt/ramdisk
램디스크를 언마운트한다.
[7]# losetup -d /dev/loop0
rdi 파일을 루프백 디바이스로부터 떼어낸다.
플로피가 없는 환경에서 램디스크를 위한 initrd
커널에게 램디스크가 어디에 있는지 알려주는 과정이 필요하다.
커널 내에는 램디스크 워드라는 것이 있는데, 커널이 램디스크를 플로피 디스켓의 어느 위치에서 읽어 들일지를 나타낸다.
플로피 디스켓을 사용하는 것이 아니라면 다른방식이 필요하다. 그 대안이 바로 initrd이다. 이것이 initrd의 실제 목적은 아니지만, 우리는 initrd를사용함으로써 루프 파일 시스템을 쉽게 마운트할 수 있다. initrd는 Initial ramdisk의 약자로 일반 램디스크와는로딩 방식이 다를 뿐이다. 일반 램디스크는 플로피 디스켓의 옵션에서 읽는 반면 initrd는 RAM 또는 ROM의 특정주소로부터 읽는 것이 가능하다. 부트 디스크에서 initrd는 LILO나 LOADER 같은 로더에 의해 메모리에 복사되면 커널이부팅 과정에서 initrd를 메모리로부터 읽어들여 램디스크로 변환한다.
램디스크(initrd)의 위치 지정
부팅 디스켓에서 램디스크 워드는 rdev라는유틸리티를 사용해 지정한다. 이 유틸리티는 커널 이미지 파일을 직접 열어 특정 위치에 원하는 값을 써넣는다. 이것을 사용해커널로 하여금 루트 디바이스가 무엇이고 어디에 위치하는지 알게 한다.
initrd를 사용할 경우 부트로더에게 부트 파라미터를 입력함으로써 위치를 지정해줄 수 있다.
램디스크 다운로드
보드의 모니터링 프로그램을 통해 커널과 램디스크를 RAM의 원하는 위치에 올린 후 커널을 시작할 수 있다. 램디스크를 initrd_start 변수 값에 해당하는 위치에 다운로드하면 된다.
램디스크 적재와 루트로 마운트 하기
이제 커널 코드를 수행하면 쉘까지 수행될 수 있는 상태가 됐다. 부팅할 때 램디스크가 어떤 과정을 겪게 되는지 살펴보자.
먼저, device_setup() 함수 내의 initrd_load()라는 함수(안에 있는 rd-load_image()라는 함수)를 수행함으로써 비로소 램디스크가 커널에 등록된다. 함수의 대략적인 내용은 다음과 같다.
[1]infile, outfile이라는 두 file 구조체를 할당하고, 구조체 내의 inode를 조작해 infile에는 initrd 장치를, outfile에는 램디스크 장치를 연결한다(유닉스 계열에서는 장치를 파일처럼 취급한다).
[2]두 장치 파일을 연다(blkdev_open() 함수)
[3]RAM에 적재된 initrd가 올바른 램디스크 이미지가 맞는지 조사한다.(identify_ramdisk_image() 함수)
[4]램디스크가 압축됐으면 압축을 푼 후 1번에서 새롭게 할당된 램디스크로 복사하는 crd_load()함수를 호출한다.
[5]올바른 램디스크 이미지일 경우 infile에서 1024KB 단위(블럭 크기)로 읽어 outfile에 쓰는 작업을 수행한다.
앞의 함수는 램디스크 디바이스를 새로할당하고 initrd를 복사해 커널이 사용할 수 있도록 램디스크로 변환하는 역활을 한다. [5]번에서 두 장치에서 블럭 단위로램디스크를 읽고 쓰는 것이 보인다. initrd 장치는 램디스크를 좀 더 쉽게 적재하기 위한 예비 장치이므로 다음의 read()함수만을 제공한다.
static int initrd_read(struct inode *inode, struct file *file, char *buf, int count)
{
int left;
left = initrd_end - initrd_start - file->f_pos;
if (count > left) count = left;
if (count <= 0) return 0;
memcpy_tofs(buf, (char *) initrd_start + file->f_pos, count);
file->f_pos += count;
return count;
}
setup_initrd에서 설정했던 변수인initrd_start와 initrd_end 변수를 앞의 함수에서 사용하는 것을 볼 수 있다. initrd_start부터 주어진크기 만큼의 내용을 buf에 복사하는 것을 볼 수 있는데, 실제로 initrd_start부터 initrd_end까지 한 블럭씩읽게 되는 것이다. 반면, outfile에 연결된 램디스크 장치는 플로피나 하드 디스크 장치 드라이버가 사용하는 함수인blkdev_write()와 blkdev_read()를 사용한다. 커널의 입장에서 램디스크가 플로피나 하드 디스크와 다름없다는것을 알 수 있다.
이제, sys_setup 함수의 마지막에서mount_root() 함수를 수행하면 된다. 이 함수에서는 램디스크의 수퍼블럭을 읽어들인 후 inode 번호가 2번인 '/'의inode를 얻어와 수퍼블럭 구조체의 s_mounted 포인터 변수에 할당한다. 이 inode의 포인터를current->fs->pwd와 current->fs->root에 할당하면 비로소 램디스크가 루트로마운트된 것이다(current는 현재 프로세를 나타내는 변수로 여기에서는 pid 1번인 init를 나타낸다). 부트디스크에서 initrd를 사용할 때에는 이 과정 이후로 /linuxrc를 실행해, 기타 필요한 작업을 수행한 후 진짜 루트 파일시스템(하드 디스크)을 재마운트하는 과정을 수행한다. 그러나, 램디스크를 루트로서 사용하면 /linuxrc를 수행할 이유는없다. init/main.c에 있는 init() 함수에 /linuxrc를 수행하는 부분이 있는데, 과감히 주석 처리하면 된다.
램디스크 만들기 1
0. 새로운 램디스크 이미지 만들기
# dd if=/dev/zero of=rdi bs=1024 count=4096
방법 1.
# losetup /dev/loop0 rdi
# mke2fs /dev/loop0
방법 2.
# mke2fs -F rdi
1. 압축 풀기 - 이미 만들어진 압축된 램디스크 이미지가 있다면
2. 마운트
방법 1.
# losetup /dev/loop0 rdi - 이미 만들어진 압축된 램디스크 이미지가 있다면
# mount /dev/loop0 mnt
방법 2.
# mount -o loop rdi mnt
3. 디렉토리 메이크 및 파일 삭제
4. 언마운트
방법 1.
# umount mnt
# losetup -d /dev/loop0
방법 2.
# umount mnt
5. 다시 압축
램디스크 만들기 2 - script
dd if=/dev/zero of=rootfs bs=1k count=8192
mke2fs -q -F rootfs
mkdir tempd
mount -o loop rootfs tempd
cp -a initrd/* tempd/
umount tempd
dd if=rootfs bs=1k | gzip -v9 > rootfs.gz
cp rootfs.gz /tftpboot/
rmdir tempd
램디스크 만들기 3
- 램디스크를 포맷하고 디렉토리를 마운트 시켜준다.
- 사용하고 있는 램디스크를 모두 알아보기 위해 "ls -al /dev/ram*" 명령을 실행한다.
이 명령은 여러분이 연결하여 사용할 수 있도록 미리 설정된 정보를 보여준다. 이러한 램디스크는 실제로 몇가지 작업(예를들어 포맷)을 해주지 않으면 실제 메모리 공간을 차지하고 있지 않는다.
# mkdir -p /tmp/ramdisk0
# mkfs -t ext2 /dev/ram0
# mount /dev/ram0 /tmp/ramdisk0
이세줄의 명령은 먼저 mount 할 디렉토리를 생성하고 램디스크 영역을 디스크로 만들기 위해 포맷을 한다. 그 다음(기본적으로4메가로) 램디스크를 "/tmp/ramdisk0"디렉토리로 마운트시킨다. 이제 여러분은 마치 한 파티션에 있는 디렉토리처럼사용하면 된다.
여러분의 컴퓨터가 재부팅되면 모든 것이사라진다. 커널 이미지 같은 파일은 램디스크에 둘 수 없다. 따라서 중요한 데이터라든지 다른곳에 복사되어 있지 않은 데이터를램디스크에 두어서는 안된다. 만약 디렉토리에 변화가 생겼는데 그 변화를 저장하고 싶다면 반드시 백업을 해 주어야 한다.
- 요약 -
Ramdisk란?
- 메모리의 일부를 디스크로 인식시킨 것.
- 배포판 설치, 복구용 디스켓에서 사용
- /dev/ram0, /dev/ram1으로 접근
- Kernel Configuration에서 설정
Block devices --->
<*> RAM disk support
(8192) Default RAM disk size
[*] Initial RAM disk (initrd) support
Ramdisk 생성
# dd if=/dev/zero of=ramdisk_img bs=1k count=8192
# mke2fs ramdisk_img
# losetup /dev/loop0 ramdisk_img
# mkdir ramdisk
# mount /dev/loop0 ramdisk
# cd ramdisk
Loopback device
/dev/loop0, /dev/loop1…..
가상의 디바이스 - 실제 디바이스와 똑같이 취급
Ramdisk 수정
# gzip –d ramdisk_img.gz
# losetup /dev/loop0 ramdisk_img
# mkdir ramdisk
# mount /dev/loop0 ramdisk
# cd ramdisk
-- 사용자 작업--
# umount ramdisk
# losetup –d /dev/loop0
# gzip ramdisk_img
Busybox
Embedded package
Many common utilities into a single small executable
Fileutils, shellutils, findutils, textutils, grep, gzip, tar, etc…
응용프로그램이 스트립(strip)되어있지 않은 상태라면 스트립을 하여 크기를 확실히 줄여준다.
커널 설정에서 램디스크 크기가 충분히 큰지 확인해보고 이것이 작으면 커널 설정을 다시 하거나 커널을 부팅할 때 rd_size= 옵션을 주어서 램디스크 크기를 키운다. 램디스크 압축전에 파일시스템의 크기를 얼마로 잡았는지 확인한다.
참고: 송영택 eduarmy@korea.com(비트교육센터 141기)
# by | 2008/08/22 16:36 | embedded Linux | 트랙백




