轉自:https://blog.csdn.net/pan0755/article/details/53085800
The ioctl() system call has long been out of favor among the kernel developers, who see it as a completely uncontrolled entry point into the kernel. Given the vast number of applications which expect ioctl() to be present, however, it will not go away anytime soon. So it is worth the trouble to ensure that ioctl()calls are performed quickly and correctly - and that they do not unnecessarily impact the rest of the system.
ioctl() is one of the remaining parts of the kernel which runs under the Big Kernel Lock (BKL). In the past, the usage of the BKL has made it possible for long-running ioctl() methods to create long latencies for unrelated processes. Recent changes, which have made BKL-covered code preemptible, have mitigated that problem somewhat. Even so, the desire to eventually get rid of the BKL altogether suggests that ioctl() should move out from under its protection.
Simply removing the lock_kernel() call before calling ioctl() methods is not an option, however. Each one of those methods must first be audited to see what other locking may be necessary for it to run safely outside of the BKL. That is a huge job, one which would be hard to do in a single "flag day" operation. So a migration path must be provided. As of 2.6.11, that path will exist.
The patch (by Michael s. Tsirkin) adds a new member to the file_operations structure:
long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
If a driver or filesystem provides an unlocked_ioctl() method, it will be called in preference to the older ioctl(). The differences are that the inode argument is not provided (it's available as filp->f_dentry->d_inode) and the BKL is not taken prior to the call. All new code should be written with its own locking, and should use unlocked_ioctl(). Old code should be converted as time allows. For code which must run on multiple kernels, there is a new HAVE_UNLOCKED_IOCTL macro which can be tested to see if the newer method is available or not.
Michael's patch adds one other operation:
long (*compat_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
If this method exists, it will be called (without the BKL) whenever a 32-bit process calls ioctl() on a 64-bit system. It should then do whatever is required to convert the argument to native data types and carry out the request. If compat_ioctl() is not provided, the older conversion mechanism will be used, as before. The HAVE_COMPAT_IOCTL macro can be tested to see if this mechanism is available on any given kernel.
The compat_ioctl() method will probably filter down into a few subsystems. Andi Kleen has posted patches adding new compat_ioctl() methods to the block_device_operations and scsi_host_template structures, for example, though those patches have not been merged as of this writing.
原文翻譯:
長期以來,ioctl()系統調用一直不受內核開發人員的青睞,他們認為這是一個完全不受控制的內核入口點。鑒於大量應用程序期望ioctl()存在,但它不會很快消失。因此,確保快速正確地執行ioctl()調用並確保它們不會對系統的其余部分造成不必要的影響是值得的。
ioctl()是在大內核鎖(BKL)下運行的內核的其余部分之一。過去,BKL的使用使得長時間運行的ioctl()方法可以為不相關的進程創建長延遲。最近的變化使得BKL覆蓋的代碼可以搶占,這在一定程度上緩解了這個問題。即便如此,最終完全擺脫BKL的願望也表明ioctl()應該從它的保護下撤出。
但是,在調用ioctl()方法之前,只需刪除lock_kernel()調用就不是一種選擇。必須首先審核這些方法中的每一種,以查看在BKL之外安全運行可能需要的其他鎖定。這是一項艱巨的工作,在單一的“旗幟日”行動中很難做到。因此必須提供遷移路徑。從2.6.11開始,該路徑將存在。
補丁(Michael s.Tsirkin)在file_operations結構中添加了一個新成員:
long(* unlocked_ioctl)(struct file * filp,unsigned int cmd,
unsigned long arg);
如果驅動程序或文件系統提供unlocked_ioctl()方法,則將優先於較舊的ioctl()調用它。不同之處在於未提供inode參數(它可用作filp-> f_dentry-> d_inode),並且在調用之前不會使用BKL。所有新代碼都應該使用自己的鎖定編寫,並且應該使用unlocked_ioctl()。舊代碼應在時間允許的情況下進行轉換。對於必須在多個內核上運行的代碼,有一個新的HAVE_UNLOCKED_IOCTL宏可以進行測試,以查看更新的方法是否可用。
Michael的補丁添加了另一個操作:
long(* compat_ioctl)(struct file * filp,unsigned int cmd,
unsigned long arg);
如果存在此方法,則只要32位進程在64位系統上調用ioctl(),就會調用它(沒有BKL)。然后,它應該執行將參數轉換為本機數據類型並執行請求所需的任何操作。如果未提供compat_ioctl(),則將使用舊的轉換機制,如前所述。可以測試HAVE_COMPAT_IOCTL宏以查看此機制是否在任何給定內核上可用。
compat_ioctl()方法可能會過濾到幾個子系統。例如,Andi Kleen發布了補丁,為block_device_operations和scsi_host_template結構添加了新的compat_ioctl()方法,盡管這些補丁在撰寫本文時尚未合並。
轉自:https://blog.csdn.net/luckywang1103/article/details/80437064
1、compat_ioctl:支持64bit的driver必須要實現的ioctl,當有32bit的userspace application call 64bit kernel的IOCTL的時候,這個callback會被調用到。如果沒有實現compat_ioctl,那么32位的用戶程序在64位的kernel上執行ioctl時會返回錯誤:Not a typewriter 。
2、如果是64位的用戶程序運行在64位的kernel上,調用的是unlocked_ioctl,如果是32位的APP運行在32位的kernel上,調用的也是unlocked_ioctl。