6

谢谢你看这篇文章。我正在尝试修补网络块设备驱动程序。如果您需要查看它们的来源,请访问 http://code.ximeta.com。

我注意到 lock_kernel() 从 linux 2.6.37 开始似乎已被弃用。我阅读了“ioctl() 的新方法”,发现设备驱动程序现在应该在操作之前执行特定的锁定。

因此,如果可能的话,我想要一些建议来代替它。

我在块文件夹部分中找到了我认为相关的当前代码中的两个部分。

Source 
      block->io.c
           ->ctrldev.c

我把每个片段的片段供你考虑。

io.c 包含一个对 lock_kernel 的调用:

NDAS_SAL_API xbool     sal_file_get_size(sal_file file, xuint64* size)
{
    definitions and declarations etc..

lock_kernel();

#ifdef HAVE_UNLOCKED_IOCTL
    if (filp->f_op->unlocked_ioctl) {   
       some small statements

       error = filp->f_op->unlocked_ioctl(filp, BLKGETSIZE64, (unsigned long)size);

       actions if error or not etc.
   }
#endif

   unlock_kernel(); 
   return ret;
}

而 ctrldev.c 包含主要的 io 函数:

#include <linux/spinlock.h> // spinklock_t
#include <linux/semaphore.h> // struct semaphore
#include <asm/atomic.h> // atomic
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/ide.h>
#include <linux/smp_lock.h>
#include <linux/time.h>

......

int ndas_ctrldev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
  lots of operations and functions. 

  return result;
}

后来 ndas_ctrldev_ioctl 函数设置为以前的 .ioctl。

static struct file_operations ndasctrl_fops = {
    .write = ndas_ctrldev_write,
    .read = ndas_ctrldev_read,
    .open = ndas_ctrldev_open,
    .release = ndas_ctrldev_release,
    .ioctl = ndas_ctrldev_ioctl, 
};

现在我想转换它以避免使用 lock_kernel();

根据我的理解,我将对前面的部分进行如下修改:

NDAS_SAL_API xbool     sal_file_get_size(sal_file file, xuint64* size)
{
    definitions and declarations etc..

#ifndef HAVE_UNLOCKED_IOCTL
    lock_kernel();
#endif

#ifdef HAVE_UNLOCKED_IOCTL
    if (filp->f_op->unlocked_ioctl) {   
       some small statements

       error = filp->f_op->unlocked_ioctl(filp, BLKGETSIZE64, (unsigned long)size);

       actions if error or not etc.
   }
#endif

#ifndef HAVE_UNLOCKED_IOCTL
   unlock_kernel(); 
#endif
   return ret;

}

#ifdef HAVE_UNLOCKED_IOCTL
long ndas_ctrldev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
int ndas_ctrldev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
#endif
{

#ifdef HAVE_UNLOCKED_IOCTL
  ! add some sort of lock here !
#endif

  lots of operations and functions. 

#ifdef HAVE_UNLOCKED_IOCTL
  ! add unlock statement here  !
#endif
  return result;
}

static struct file_operations ndasctrl_fops = {
    .write = ndas_ctrldev_write,
    .read = ndas_ctrldev_read,
    .open = ndas_ctrldev_open,
    .release = ndas_ctrldev_release,
#ifdef HAVE_UNLOCKED_IOCTL
    .unlocked_ioctl = ndas_ctrldev_ioctl, 
#else
    .ioctl = ndas_ctrldev_ioctl, 
#endif
};

所以,我想请教以下建议。

  1. 这看起来像正确的程序吗?

  2. 我是否理解将锁移动到 io 函数中是否正确?

  3. 根据 crtrldev.c 中包含的内容,您能推荐任何您头顶上的锁吗?(我试图研究其他一些处理 filp 和 lock_kernel 的驱动程序,但我太菜鸟了,无法立即找到答案。)

4

2 回答 2

6

Big Kernel Lock (BKL) 已被弃用——从 2.6.39 开始,它不再存在。

完成转换的方式lock_kernel()是用每个驱动程序的互斥体替换它。如果驱动程序足够简单,您可以简单地为驱动程序创建一个互斥体,并用互斥体锁定/解锁调用替换所有使用lock_kernel()和。unlock_kernel()但是请注意,某些函数过去是在lock_kernel()持有 BKL(用于锁定的锁)的情况下调用的;您还必须向这些函数添加锁定/解锁调用。

如果驱动程序可以递归地获取 BKL,这将不起作用;如果是这种情况,您必须自己跟踪它以避免死锁(这是在 的转换中完成的reiserfs,这在一定程度上取决于递归 BKL 行为和它在睡眠时被丢弃的事实)。

转换为每个驱动程序互斥体后的下一步是将其更改为使用每个设备互斥体而不是每个驱动程序互斥体。

于 2011-05-16T10:10:59.940 回答
6

这是解决方案。

#if HAVE_UNLOCKED_IOCTL
    #include <linux/mutex.h>
#else
    #include <linux/smp_lock.h>
#endif

.
. 
. 

#if HAVE_UNLOCKED_IOCTL
   mutex_lock(&fs_mutex);
#else
   lock_kernel();
#endif

这仅显示替换锁定调用。其他部分正如我在上面关于 unlocked_ioctl 的问题部分所猜测的那样。感谢您的检查和帮助。

于 2011-12-29T22:05:49.227 回答