커널레벨에서 물리적 블록디바이스에 직접 데이터 I/O 작업하기.

jw8704의 이미지

파일시스템 코드를 분석하거나, 커널레벨에서 물리적 블록디바이스에 직접 데이터 I/O 작업을 하려할때 파일시스템 코드를 분석하다보면 실제로 디바이

스에 I/O 작업을 하는데 필요한 코드만을 추출하기가 좀 번거롭고 한것같아서 따로 정리해봤습니다.

ll_rw_block 를 이용해서 어떻게 I/O 작업을 하는지 정리한 문서입니다.

보시고 부족한점이나 고칠점에 대해서 많은 피드백 부탁드립니다.

조악하지만 , 여기서 배운것에 약간이나마 보답하고자하는 마음에서 올립니다.

연말 잘 보내십시오.

Url: http://203.250.148.120/in_kernel_level-write_to_physical_device_using_ll_rw_block.hwp

---------------------------------------------------------------------------------------
서버사정으로 코드만 먼저 올리겠습니다.
---------------------------------------------------------------------------------------
-------------------------------------------------------------------------
1.물리적 장치로부터 데이터 읽기 : __getblk() 또는 __bread() 함수를 사용.
-------------------------------------------------------------------------
#include
#include
#include
#include
#include

int my_init_module(void)
{
struct buffer_head * bh;
struct block_device *bdev;
int k;
const char *devname="/dev/sda7";
fmode_t mode=FMODE_READ;

printk("[myModule] ----------------> \n");

bdev = open_bdev_excl(devname,mode,NULL);
if(IS_ERR(bdev))
{
printk("[myModule] open_bdev_excl fail\n");
return 0;
}
printk("major = %d , minor %d\n",MAJOR(bdev->bd_dev),MINOR(bdev->bd_dev));
bh = __getblk(bdev,0,512); 또는 bh = __bread(bdev,0,512); 으로 해도됨.

for(k=0; k {
printk("b_data[%d] %x\n",k,bh->b_data[k]);
}
printk(" return 0;
}
void my_cleanup_module(void)
{
printk("[myModule] goodbye!\n");
}
module_init(my_init_module);
module_exit(my_cleanup_module);
MODULE_LICENSE("GPL");

--------------------------------------------------------------------
2.물리적 장치로 데이터 기록 : ll_rw_block() 함수 사용.
--------------------------------------------------------------------
#include
#include
#include
#include
#include

int my_init_module(void)
{
struct buffer_head * bh;
struct block_device *bdev;
int k;
const char *devname="/dev/sda7";
fmode_t mode=FMODE_READ;

printk("[myModule] ----------------> \n");
bdev = open_bdev_excl(devname,mode,NULL);
if(IS_ERR(bdev)) {
printk("[myModule] open_bdev_excl fail\n");
return 0; }

printk("major = %d , minor %d\n",MAJOR(bdev->bd_dev),MINOR(bdev->bd_dev));
bh = __getblk(bdev,0,512); 또는 bh = __bread(bdev,0,512); 으로 해도됨.

bh->b_data[0]='Z'; // 'Z' 를 설정. : 뒤에나오는 스크린샷에서는 0-6 까지 A에서G 로 채운 예가나옴.
ll_rw_block(WRITE,0,&bh); // 기록함.

for(k=0; k printk("b_data[%d] %x\n",k,bh->b_data[k]); }
printk(" return 0;
}
void my_cleanup_module(void)
{
printk("[myModule] goodbye!\n");
}
module_init(my_init_module);
module_exit(my_cleanup_module);
MODULE_LICENSE("GPL");

----------------------
Makefile
----------------------
obj-m += mod1.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

-----------------------
설명
-----------------------
파일시스템 구현 및 학습을 위한 첫 시작점으로 적당할것같음.
커널에서 이미 구현된 디바이스 드라이버 인터페이스를 사용하여 물리적 블록디바이스장치에 읽기/쓰기 작업.

기존에 학습 문서들이 파일시스템의 알고리즘적 내용이나 , 디바이스 드라이버의 이론적 내용 그리고 디바이스 드라이버를 구현하는 법 ,
그리고 예제는 실제 물리적 장치가아닌 RAM 디스크가 대부분이어서 실제로 자신이 USB 나 물리적 블록장치에 무엇인가를 직접 읽기/쓰기
작업을 하기위한 지식을 얻는데 힘들었음.

이문서는 이러한 기존의 부족한 점들과 위의 목적을 위하여 만들어졌음.
이문서는 디바이스 드라이버를 제작하는 법에 대해서는 다루지 않음.

/dev/파일이름 으로 장치가 표시되고 echo "test" > /dev/파일이름 , od -t x /dev/파일이름 으로 확인했을 때
자신이 기록한 test 가 기록되어 있는 것이 확인되면 해당 장치에 대한 디바이스드라이버는 이미 작성되어서 커널에서 돌아가고 있음을 나타냄.

이것을 이용하는 방법으로는 userlevel 에서 이용하는 방법과 kernel 레벨에서 이용하는 방법이 있음.

userlevel에서 이용하는 방법이란 open ,write, read, lseek 등의 함수를 이용하는 것을 말함.
커널에서 이용하는 방법은 이 문서에서 지금부터 다룰 것임.

파일시스템을 크게 2부분으로 나누자면 커널레벨에서 디바이스드라이버에서 제공하는 인터페이스를 사용해
물리적 장치에 읽고/쓰기 작업을 하는데 , 파일관리를 위해 알고리즘이 도입된 것임.

디바이스드라이버만 구현되어있다면 , 파일시스템의 유무는 물리적 장치에 읽고/쓰기 작업을 하는데 아무 상관이 없음.
전혀 다른 차원의 내용임.

**이러한 디바이스 인터페이스를 만드는 내용은 또 다른 내용으로써 디바이스 드라이버 제작법과 이론을 공부해야함.
------------
코드설명
------------
3.1 읽기에 대한 설명.
읽는 부분에서는 일단 Userlevel 에서와 읽기를 요청하는 단위및 방법이 다르다.

Userlevel 에서는 open 함수로 디바이스 파일을 열어 파일시스템과 별개로 직접 디바이스에 기록을 할 수 있으나 ,
이때는 디바이스를 파일처럼 생각하고 파일 포인터를 이동해가면서 작성을 하게 된다.
그리고 현재 파일 포인트로 부터 몇 바이트 를 읽을 것인가 를 기준으로 처리된다.

지금 Kernel level 에서는 sector 단위로 처리하고 있다.
몇 번째 섹터에서 읽을 것인가 그리고 섹터의 크기는 얼마인가
(하드디스크 의 물리적 특성으로 제조사, 모델마다 다르나 보통 512바이트로 구성되어있는 경우가 많음) 를 기준으로 처리하고 있다.

이 부분에서 아 , 내가 로우레벨에서 작업하고 있구나 하는것 을 한번 느껴 봐도 된다.

많이 들어봤겠지만 block 단위로 처리 된다 그래서 1byte 만 읽거나 할순 없다. 섹터 크기 단위로 읽게 된다.

*물론 이런 함수를 사용하지 않고 outb 뭐 이런 함수를 사용한다면 바이트단위로도 가능 할것 같다. 그런 예제를 나중에 또 올리겠다.
하지만 파일시스템 수준에서는 위수준정도의 인터페이스를 이용해서 디바이스와 작업한다.

3.2 쓰기에 대한 설명.
쓰기를 보면 쓰기작업을 하는데 먼저 읽어오고 쓰는 작업을 하는 것에 있어서 뭔가 좀 이상하다고 느꼈을 수도 있다.
버퍼를 만들어서 내용을 채우고 원하는 지점에 기록하면 될것 같은데 왜 읽어 온 다음 변경하고 기록 하는가 ? 하는 것이다.

일단 코딩차원에서 얘기하자면 ll_rw_block 함수가 buffer_head 자료형을 3번째 매개변수로 요청하는데 이걸 그냥 주면 안 된다.
적절히 채워서 줘야하는데 그러한 것을 위해서 먼저 자신이 기록할 부분이 담긴 섹터를 읽어오는 것이다.
그러면 buffer_head 자료 형이 채워진다. 물론 당연한 얘기지만 , 수동으로 직접 채워도 된다.
시도해봤는데 그건 아직 성공 못했다.

*부가설명
코드에 보면 /dev/sda7 을 이름으로 준 후에 major 번호와 minor 번호를 추출하여 출력하는 부분이 있는데
이것을 ls -al /dev/sda7 했을때 나오는 major, minor 번호와 비교하여 같은지 보는 것이다.
그러므로 인해서 아 제대로 block_device 자료형이 채워졌구나 하고 생각해볼수있겠다.
그리고 buffer_head 를 채우기 위해서 선행 작업중에 block_device 를 채워야 하는 것도 주목 해서 봐야한다.

----------
실험환경
----------
위의 코드는 centos 5.5(final) , kernel = 2.6.18-194.el5에서 실험되었음.
설치하고 바로 사용했으며 make 를 위해 kernel-devel-2.6.18-194.el5 를 깔았음.

---------------------------------------------------------------------------------
맺음말
---------------------------------------------------------------------------------
위내용을 기반으로 학습하는데 도움이 되시기를 바랍니다.

앞서 좋은 문서를 만들어주신 많은 분들께 항상 감사드립니다.

틀린점이있으면 알려주시면 감사하겠습니다.

글을 올린지는 꽤되었는데 서버도 닫아버리고 , 이제야 이렇게 다시 올립니다. 죄송합니다.

새해복 많이받으시고 건강하세요~

Forums: 
snowall의 이미지

안열립니다...

피할 수 있을때 즐겨라! http://melotopia.net/b

익명 사용자의 이미지

익명 사용자의 이미지

안정적인 대형 오픈 소스 호스팅 같은데, 아니면 여기 강좌 게시판에 붙여다 주시면 감사하겠습니다.

개인 사이트라면 이렇게 열심히 한 결과인데도 불구하고 공개도 못하고 사장되는 경우를 너무 많이 봐왔습니다.

bushi의 이미지

ll_rw_block 는 deprecated 로 마크되어 있기도하고, 게다가 링크는 깨져 있기까지 하니...

꿩 대신 닭이라고,
최근 커널의 kernel/power/ 에서 block_io.c 와 swap.c 를 보시면 간단한 예제가 있습니다.
이 두 파일은 suspend-to-disk 때 ram 의 내용을 swap 파티션으로 백업하는 기능을 구현하고 있습니다.
submit_xx 계열의 다른 함수들에 대한 예제는 커널 소스들을 뒤져보시면 되겠고요.

익명 사용자의 이미지

게시물 갱신되었습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.