컨텐츠 바로가기

linux seq file All in one

http://iloveriver.egloos.com/6192450

  ... 현재 작성중 ...
 리눅스의 seq_file 인터페이스는  리눅스의 proc file system을 위해 제공 되었습니다.
 지금은 debug file system에서도 쓰이지만 말입니다.

 파일 시스템에서  read() system call을 작성하는 작업은 만만한 작업이 아닙니다.
 이런 귀찮은 작업을 개발자의 몫에서 제거하기 위해 seq file 인터페이스가 탄생했습니다.

 /proc 파일 시스템은 , 시스템상의 중요 정보를 사용자에게 제공하기 위해 존재하는데,
 예를 들면 , 마더보드에 장착된 cpu의 정보들은 /proc/cpuinfo 파일을 통해 사용자에게
 노출 시킵니다.

 사용자는 이 
/proc/cpuinfo 파일을
  
   char buf[10];
   int fd = open("/proc/cpuinfo" ,O_RDONLY);
   if(  read(fd,buf,sizeof(buf) ) >0 )
      printf(buf);

 식으로 화면에 출력할 수 있습니다.

 커널상에서 드라이버를 작성할 때 , 드라이버의 정보를 사용자에게 제공하기 위한 인터페이스로
 proc file system을 사용하는데,  드라이버를 작성할 때 struct file_operations 구조체를 제공하는 것과
 마찬가지로  /proc 파일 시스템을 이용하기 위해서는
 
  static const struct file_operations generic_ops = {
     .owner      = THIS_MODULE,
     .open       = generic_open,
     .read       = seq_read,
     .llseek     = seq_lseek,
     .release    = seq_release,
 
  };
 라는 구조체를
 proc_create("genericproc",0,NULL,&generic_ops); 라는
 함수를 사용해 등록합니다.  ( 여기서는 proc file system은 다른 자료를 통해 익숙하다고 가정합니다.
                                         왜냐하면 , seq_file에 관한 글이기 때문입니다)

 그러면 /proc 밑에 genericproc라는 파일이 생성됩니다.
 

 여기까지는 proc file system을 사용하기 위한 과정과 동일합니다.
 그리고 .read 나 .llseek등의 함수를 개발자가  직접 작성하지 않고 , 커널의 seq_file에서 제공되는
 seq_read , seq_llseek등으로 구조체를 채워 줍니다.
 
 
여기서 유의할 함수가
generic_open 인데 이는 seq_file을 사용하려는 개발자가 seq file을 사용하겠다고
 등록을 해주는 부분을 작성해 주어야 하는 함수입니다.

 구체적으로 살펴보면
  static int generic_open(struct inode *inode, struct file *file)
 {
   return seq_open(file, &generic_sec_operations);
 }
 
 로  seq_open이라는 함수를 사용해서 seq_file interface를 위한  구조체를 등록합니다.


 그리고 그 구조체는

  struct seq_operations generic_sec_operations = {
 
      .start = generic_start,
 
      .stop = generic_stop,
 
      .next = generic_next,
 
     .show = generic_show,
 
     };
   의 형태인데,
   

   struct seq_operations 구조체의  start ,stop , next ,show의 멤버함수를 개발자가 작성해 등록하면
   linux seq_file 을 사용할 수 있습니다.
 

  요약해보면,
   /proc상에서  proc file system의 read()를 직접 구현하지 않고  seq_file 인터페이스를 사용하기 위해서는
  
proc_create()를 통해 등록하는  file_operations->open() 함수에서
   seq_open()을 호출해 seq_file을 위한

   struct seq_operations   구조체를 등록하는 과정을 거쳐야 합니다.

  

 

   char buf[10];
   int fd = open("/proc/cpuinfo" ,O_RDONLY);     ---1
   if(  read(fd,buf,sizeof(buf) ) >0 )                      ---2
      printf(buf);

   위의 user code  1에서    open()이 호출되면

   --->

           struct file_operations generic_ops   의 generic_open() 이 호출되고
              --->
seq_open() 이 호출 되게 됩니다.
 
  그리고 user code 2에서 read()가 호출되면
            --->seq_read()가 호출됩니다.

  그리고  seq_read()는 아래의 순서도로 동작합니다.
  seq_open()에서 등록한 구조체의 member 함수 start() , next(),show() ,stop()등이 차례로
  호출 됩니다.


  여기서 seq file 설계의 구조에 대해 말씀드리겠습니다.

  드라이버가 proc file system을 통해 외부에 제공하는 정보가 있습니다.
  그런데 , 이 정보는 단일한 정보가 아니라 , 여러 정보의 뭉치들인 경우가 많습니다.
  예를 들면 , cpu의 정보는 single 이 아닌 multi-core가 대부분이고,  시스템에 기동중인 process도 한 개가 아닌
  다수인 경우가 대부분입니다.

  그래서 seq_file은 어떤  아이템의 리스트나 배열이 사용자에게 전달 된다고 가정합니다.
 
  사용자가 read()를 호출하면 ,  seq_read()는  먼저 driver에게  첫번때 아이템이 있는지를  next()함수를 통해 요청합니다.
  그리고 show()를 호출해  첫번째 아이템의 data를  read() 상의 버퍼에 복사해줍니다.
  그리고 start()를 호출해서  드라이버의 정보 아이템이 다 소진 되었는지를 검사해서 그렇다면 종료하고
  그렇지 않으면 next()를 호출하는 과정을 반복합니다.







덧글|덧글 쓰기|신고