设备文件的访问控制:独享设备,限制每次只有一个用户访问(单用户访问),阻塞型用户访问,打开时复制设备。
独享设备主要是让驱动程序维护一个atomic_t变量,该变量初始化为1,表明可用,在open时会减小并测试scull_s_available,并在其他进程打开该设备时拒绝打开该设备。代码示例:
static atomic_t scull_s_available = ATOMIC_INIT(1);
static int scull_s_open(struct inode *inode,struct file *filp)
{
struct scull_dev *dev = &scull_device;
if(!atomic_dec_and_test(&scull_s_availeable)){
atomic_inc(&scull_s_available);
return -EBUSY;
}
….
}
static int scull_s_release(struct inode *inode,struct file *filp)
{
atomic_inc(&scull_s_available); //释放设备
return 0;
}
单用户访问:open 调用在第一次打开记住了设备拥有者,此用户可多次打开设备,并协调多个进程对设备并发操作。同时,没有其他用户可打开它,避免了外部干扰。此时需要两个数据项一个打开计数和设备属主的UID。一般建议将这两个数据项放入到设备的数据结构中。示例代码:
static int singleUID_count; /* initialized to 0 by default */
static uid_t singleUID_owner; /* initialized to 0 by default */
static spinlock_t singleUID_lock = SPIN_LOCK_UNLOCKED;
static int singleUID_open(struct inode *inode,struct file *filp)
{
spin_lock(&singleUID_lock);
if(singleUID_count && //如果singleUID_count为一说明已经打开了
singleUID_owner != current->uid &&
singleUID_owner != current->euid && //如果权限不对,不允许打开
!capable(CAP_DAC_OVERRIDE){//capable用于描述用户空间可能拥有的权能操作。
spin_unlock(&singleUID_lock);
return -EBUSY;
}
if(singleUID_count == 0){
singleUID_OWNER = current->uid;
}
singleUID_count++;
spin_unlock(&singleUID_lock);
return 0;
}
static int singleUID_release(struct inode *inode,struct file *filp)
{
spin_lock(&singleUID_lock);
singleUID_count–;
spin_unlock(&singleUID_lock);
return 0;
}
上边看出在对singleUID_count,singleUID_owner等结构进行操作时都用锁保护起来。
代替EBUSY的阻塞型open:当设备不可访问时,并不直接返回EBUSY,而是用阻塞型I/O实现。
示例代码:
static int singleUID_count ;
static uid_t singleUID_owner;
static spinlock_t singleUID_lock = UNLOCKED;
static spinlock_t singleUID_lcok = UNLOCKED;
static inline int singleUID_available(void)
{
return singleUID_count == 0||singleUID_owner == current->uid||
singleUID_owner == current->euid || capable(CAP_DAC_OVERRIDE);
}
static int singleUID_open(struct inode *inode,struct file *filp)
{
spin_lock(&singleUID_lock);
while(!singleUID_available()){
spin_unlock(&singleUID_lock);
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
if(wait_event_interruptible(singleUID_wait,singleUID_available()))
return -ERESTARTTSYS;
spin_lock(&singleUID_lock);
}
if(singleUID_count == 0)
singleUID_owner = current->uid;
singleUID_count ++;
spin_unlock(&singleUID_lock);
return 0;
}
static int singleUID_release(struct inode *inode,strct file *filp)
{
spin_lock(&singleUID_lock);
singleUID_count–;
spin_unlock(&singleUID_lock);
if(singleUID_count == 0)
wake_up_interruptible(&singleUID_wait);
return 0;
}
open时复制设备:如果复制的设备是由软件驱动程序创建的,我们称为“虚拟设备”——就像所有的虚拟终端都是用同一个物理设备一样。
没有什么可留恋,只有抑制不住的梦想,