디바이스를 사용하기 위해 open()을 호출하고, 사용을 마친 후에는 close()를 호출해서 사용을 끝낸다. 만약, 여러 사람이 동시에 open()을 호출해서 사용하고 있을 때, 누군가가 close()를 호출해서 사용을 끝낸 경우에는 어떻게 될까? 디바이스를 사용하던 다른 사람들은 이상한 문제를 겪게 될 것이다. 디바이스를 얼마나 많이 사용하는지 알 수 있는 방법으로 디바이스를 사용할 때 카운트를 증가 시키고, 디바이스 사용을 끝낼 때 카운트를 감소시키는 것이다. 이것을 참조 계수기(reference counter)라고 한다.

2.4 커널에서는 open()이 호출될 때, 디바이스 드라이버에서 MOD_INC_USE_COUNT를 호출해서 카운트를 증가시켜야 하고, close()가 호출될 때는 MOD_DEC_USE_COUNT를 호출해서 카운터를 감소시켜야 한다.

2.4 커널에서 카운트는 커널 내부에서 유지하며, 카운트의 증가/감소만 MOD_INC_USE_COUNT, MOD_DEC_USE_COUNT 매크로를 사용하여 변경할 수 있다.

이 방법의 문제점은 모듈을 제거하려 할 때, 오류가 발생해서 MOD_DEC_USE_COUNT가 수행되지 못한 경우에 해당 모듈을 제거할 수 없다. 디바이스 드라이버는 이미 제거되었는데, 카운트가 유지되고 있기 때문에 시스템을 다시 시작할 때까지 카운트를 초기화시킬 방법이 없기 때문이다.

2.6 커널에서는 MOD_INC_USE_COUNT, MOD_DEC_USE_COUNT 등을 사용하지 않고, 모듈의 참조 계수를 내부적으로 관리하며, 모듈을 강제로 제거할 수 있는 기능도 제공한다. 그러나 일부 디바이스 드라이버를 작성할 때 사용 횟수를 직접 관리해야 하는 경우도 있기 때문에 사용 횟수 증가를 위한 try_module_get()과 사용 횟수 감소를 위한 module_put() 함수를 제공한다.

 // 2.4
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define NAME  "bsp"
#define MAJOR  240

int bsp_open(struct inode *inode, struct file *filp)
{
  MOD_INC_USE_COUNT;
  return 0;
}

ssize_t bsp_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
  return 1;
}

ssize_t bsp_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
  return 2;
}

int bsp_release(struct inode *inode, struct file *filp)
{
  MOD_DEC_USE_COUNT;
  return 0;
}

struct file_operations bsp_fops =
{
  read  : bsp_read,
  write  : bsp_write,
  open  : bsp_open,
  release  : bsp_release,
};

int init_module(void)
{
  int result;
  result = register_chrdev(MAJOR, NAME, &bsp_fops);
  if(result <0)
    return result;

  return 0;
}

void cleanup_module(void)
{
  unregister_chrdev(MAJOR, NAME);
}

MODULE_LICENSE("GPL");

 // 2.6
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/slab.h>

#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/io.h>

#define NAME  "bsp"
#define MAJOR  240

int bsp_open(struct inode *inode, struct file *filp)
{
  try_module_get(THIS_MODULE);
  printk("open module\n");
  return 0;
}

ssize_t bsp_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
  printk("read call\n");
  return 1;
}

ssize_t bsp_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
  printk("write call\n");
  return 2;
}

int bsp_release(struct inode *inode, struct file *filp)
{
  module_put(THIS_MODULE);
  printk("release module\n");
  return 0;
}

struct file_operations bsp_fops =
{
  .owner = THIS_MODULE,
  .read = bsp_read,
  .write = bsp_write,
  .open = bsp_open,
  .release = bsp_release,
};

int init_test(void)
{
  int result;
  result = register_chrdev(MAJOR, NAME, &bsp_fops);
  if(result < 0)
    return result;
  return 0;
}

void exit_module(void)
{
  unregister_chrdev(MAJOR, NAME);
}

module_init(init_test);
module_exit(exit_module);
MODULE_LICENSE("GPL");




+ Recent posts