在下面的代码(read实现了字符设备驱动程序),有可能是MMU的TLB项中wait_event_interruptible改变,从而导致__put_user即使access_ok成功例外吗?linux内核,用户空间缓冲区,做access_ok并等待创建竞态条件?
是否可以锁定用户缓冲区,使其在请求期间保持有效?
会重复access_ok检查wait_event_interruptible退货是否安全?
ssize_t mydriver_pkt_read(struct file* filp, char __user* const buff, size_t count, loff_t* offp)
{
struct mydriver_pkt_private* priv;
volatile unsigned short* iobase;
unsigned next;
char __user* p = buff;
if (count <= 0) return -EINVAL;
if (!access_ok(VERIFY_WRITE, buff, count)) return -EFAULT;
priv = (struct mydriver_pkt_private*)filp->private_data;
iobase = priv->iobase;
next = priv->retained;
if ((next & PKTBUF_FLAG_NOTEMPTY) == 0) {
next = ioread16(iobase);
if ((next & PKTBUF_FLAG_NOTEMPTY) == 0) { // no data, start blocking read
iowrite16(1, iobase); // enable interrupts
if (wait_event_interruptible(priv->wait_for_ringbuffer, (priv->retained & PKTBUF_FLAG_NOTEMPTY)))
return -ERESTARTSYS;
next = priv->retained;
}
}
while (count > 0) {
__put_user((char)next, p);
p++;
count--;
next = ioread16(iobase);
if ((next & PKTBUF_FLAG_STARTPKT) || !(next & PKTBUF_FLAG_NOTEMPTY)) {
priv->retained = next;
return (p - buff);
}
}
/* discard remainder of packet */
do {
next = ioread16(iobase);
} while ((next & PKTBUF_FLAG_NOTEMPTY) && !(next & PKTBUF_FLAG_STARTPKT));
priv->retained = next;
return (p - buff);
}
独家开放代码:
int mydriver_pkt_open(struct inode* inode, struct file* filp)
{
struct mydriver_pkt_private* priv;
priv = container_of(inode->i_cdev, struct mydriver_pkt_private, cdevnode);
if (atomic_cmpxchg(&priv->inuse, 0, 1))
return -EBUSY;
nonseekable_open(inode, filp);
filp->private_data = priv;
return 0;
}
+0
顺便说一下,你可能想用信号来保护你的驱动程序。如果两个进程在一次读取中竞争会发生什么?在我看来,他们可以以这样的方式竞争:一个人在设备端中断被禁用时仍处于睡眠状态...... –
+0
@bdonlan:这是一个嵌入式系统:一个处理器,一个硬件线程。并且只有一个设备实例(在打开时执行,请参阅编辑)。我想仍然可以使用'fork'或者线程同时获得请求,但是用户模式应用程序不是多线程的。无论如何,我可能应该使其线程安全。 –
+0
啊,如果它是独家开放的,我想这不会是一个问题。 –