2011-07-31 3 views
2

다음 코드 (read char 드라이버 구현)에서 access_ok이 성공하더라도 __put_user이 예외를 발생 시키도록 wait_event_interruptible 동안 MMU TLB 항목을 변경할 수 있습니까?리눅스 커널, userspace 버퍼, 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); 
} 

독점 공개 코드 : 당신이 개최 mm_sem 세마포어가 없다면

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

그런데 세마포로 운전자를 보호하고 싶을 수 있습니다. 두 프로세스가 단일 읽기로 경쟁한다면 어떻게됩니까? 그것은 그들이 하나의 장치 쪽 인터럽트가 비활성화 된 상태에서 잠자는 방식으로 경쟁 할 수있는 것처럼 보입니다. – bdonlan

+0

@bdonlan : 이것은 임베디드 시스템입니다 : 하나의 프로세서, 하나의 하드웨어 스레드. 그리고 장치의 단 하나의 인스턴스가 있습니다 (열 때 시행, 편집 참조). 나는 여전히'fork' 또는 쓰레드를 사용하여 동시 요청을하는 것이 가능할 것이지만, 사용자 모드 애플리케이션은 다중 쓰레드가 아니다. 어쨌든 threadsafe를 만들어야합니다. –

+0

아, 배타적으로 열리면 문제가되지 않습니다. – bdonlan

답변

3

는, 페이지 테이블이 다른 프로세서에서 페이지를 매핑 해제 동일한 프로세스의 다른 스레드 (언제든지 변경, 또는으로 할 수 있습니다 페이지 회수 프로세스에서의 퇴거). 너는 잠잘 필요가 없다. TLB shootdown 인터럽트가 발생할 수있는 한 선매가 사용 중지 된 경우에도 문제가 발생할 수 있습니다. 심지어 인터럽트가 비활성화 된 경우에도 SMP 시스템이있는 경우에도 예외적 인 TLB 플러시없이 페이지 테이블 업데이트가 반영되는 경우가 있습니다.

access_ok()은 주소 범위가 does not overlap with kernel space 인 지 확인합니다. 따라서 페이지 테이블 항목이 액세스를 허용하는지 여부는 알려주지 않지만 차단하더라도 결과는 변경되지 않습니다. 액세스가 거부되면 __put_user()-EFAULT을 반환하며 이는 사용자 공간으로 전달되어야합니다 (즉, -EFAULT으로 오류가 발생 함).

put_user()__put_user() 사이의 유일한 차이는 put_user()access_ok() 검사를 수행한다는 것입니다. 따라서 루프에서 사용하는 경우 access_ok()을 미리 수행하고 __put_user()을 사용하는 것이 좋습니다.