강좌 & 팁
글 수 2,412
2011.07.03 01:24:50 (*.138.143.120)
46951
커널 2.6.36에서는 file_operations 에서 ioctl 이 제거되었고
대신에 unlocked_ioctl 과 compat_ioctl 이 사용되게 되었다.
unlocked_ioctl 과 compat_ioctl 은 2.6.11 에서 처음 추가되었는데 그 이유는 BKL 이슈에 대한 것때문이다.
BKL 은 Big Kernel Lock 의 약자인데 커널에서 락을 이용하지 않게 하려는 시도가 꾸준히 있어왔다.
그 이유는 커널에서 특히 SMP 구조에서 락에 들어가는 비용이 너무 많기 때문이며, 효율적으로 사용하기 위해서다.
그런 이유로 도입된 것이 RCU(read copy update) 이다.
어쨋든 ioctl 이 호출되면 커널 락이 수행되고 자동적으로 SMP 구조에서는 비효율을 가져오고 있었다.
그래서 사용되는 것이 unlocked_ioctl 이다.
쉽게 얘기해서 모든 CPU에 대해서 lock 을 걸던것을 개별적인 lock 을 걸수 있게끔 바꾼것이다.
간단히 어떻게 해야 하는지 확인하자.
static int extio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int param_size;
unsigned int value;
if(_IOC_TYPE(cmd) != IOCTL_FN_ALARM) return -EINVAL;
if(_IOC_NR(cmd) >= ALARM_FN_MAXNR) return -EINVAL;
param_size = _IOC_SIZE(cmd);
if(param_size) {
if(_IOC_DIR(cmd) & _IOC_READ) {
if (unlikely(!access_ok(VERIFY_WRITE, (void *)arg, param_size)))
return -EFAULT;
}
if(_IOC_DIR(cmd) & _IOC_WRITE) {
if (unlikely(!access_ok(VERIFY_READ, (void *)arg, param_size)))
return -EFAULT;
}
}
switch (cmd)
{
caseFN_IOCTL_GET:
{
copy_to_user((unsigned int *)arg, &value, sizeof(unsigned int));
return 0;
}
caseFN_IOCTL_PUT:
{
copy_from_user(&value, (unsigned int *)arg, sizeof(unsigned int));
return 0;
}
}
return -ENOTTY;
}
이것이 전통적인 방식의 ioctl 이다.
이제는 여기서 이렇게 바꾸어야 한다.
static DEFINE_MUTEX(extio_mutex);
static int extio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int param_size;
unsigned int value;
if(_IOC_TYPE(cmd) != IOCTL_FN_ALARM) return -EINVAL;
if(_IOC_NR(cmd) >= ALARM_FN_MAXNR) return -EINVAL;
param_size = _IOC_SIZE(cmd);
if(param_size) {
if(_IOC_DIR(cmd) & _IOC_READ) {
if (unlikely(!access_ok(VERIFY_WRITE, (void *)arg, param_size)))
return -EFAULT;
}
if(_IOC_DIR(cmd) & _IOC_WRITE) {
if (unlikely(!access_ok(VERIFY_READ, (void *)arg, param_size)))
return -EFAULT;
}
}
mutex_lock(&extio_mutex)
switch (cmd)
{
caseFN_IOCTL_GET:
{
copy_to_user((unsigned int *)arg, &value, sizeof(unsigned int));
mutex_unlock(&extio_mutex);
return 0;
}
caseFN_IOCTL_PUT:
{
copy_from_user(&value, (unsigned int *)arg, sizeof(unsigned int));
mutex_unlock(&extio_mutex);
return 0;
}
}
mutel_unlock(&extio_lock);
return -ENOTTY;
}
세가지가 추가되었다.
static DEFINE_MUTEX(extio_mutex);
mutex_lock(&extio_mutex);
mutex_unlock(&extio_mutex);
이제 동일한 ioctl 에 접근하는게 아니라면 SMP 구조에서도 mutex 로 보호되는 상태만 아니면
동시에 ioctl 에 접근할수 있게 되었다.
또 하나 있는게 compat_ioctl 인데 이것은 32bit 와 64bit 간의 호환성을 갖도록 설계된 ioctl 이다.
자세한 것은 다음에 다시 설명하도록 합니다.
좋은 자료 입니다. 감사합니다 ^^