Messages in this thread | | | Date | Tue, 17 Aug 1999 08:34:24 -0700 | From | "Lee Nichols" <> | Subject | no access to user-memory after interruptible_sleep_on in ioctl handler |
| |
During writing a device driver that calls a sleep function inside an ioctl call, I came across VERY strange behavior!
I noticed that after a call to interruptible_sleep_on() in an ioctl I can't pass back data to the user mode.
I am verifying that the data can be written (using verify_area()) and I also verified that I am writing to the same physical address that I am using in the user mode, still I don't get the value I sent.
A few checks that I did: 1) current->pid stays the after interruptible_sleep_on(). 2) the problem also sometimes happens after down_interruptible() used to wait on a semaphore. This leads me to assume that this can happen after the scheduler is invoked. 3) I translated the user-mode virtual address to physical address (using uvirt_to_phys() from bttv.c driver in the kernel). The physical address did not change. 4) using the physical address from #3, I read directly from the physical address to make sure the data was actually written to the physical memory. It was.
It seems like after interruptible_sleep_on() there are two physical copies of the page, and when it returns to user mode, it copies back the page from before interruptible_sleep_on().
ANY IDEAS???
Lee Nichols leenicholes at my-deja dot com
The following code shows my problem:
extern wait_queue ** interrupt_event; /* this event is signaled from the interrupt handler */
int mydrv_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int data; if (cmd==IOCTL_TEST) { /* check received the correct data from user-mode */ verify_area(VERIFY_READ, arg, sizeof(data)); copy_from_user(&data, arg, sizeof (data)); printk ("data from user mode %d\n", data); /* prints 1 */
/* write data 2 to user-mode */ verify_area(VERIFY_WRITE, arg, sizeof(data)); data = 2; copy_to_user(arg, &data, sizeof (data));
/* this causes the problem. removing this - everything is fine */ interruptible_sleep_on(interrupt_event); /* check that data 2 is still where we expect it to be */ verify_area(VERIFY_READ, arg, sizeof(data)); data = 0; copy_from_user(&data, arg, sizeof(data)); printk("data after interruptible_sleep_on %d\n",data); /* prints 2 */
/* write data 3 to user-mode */ verify_area(VERIFY_WRITE, arg, sizeof(data)); data = 3; copy_to_user(arg, &data, sizeof (data));
/* check that data 3 is still where we expect it to be */ verify_area(VERIFY_READ, arg, sizeof(data)); data = 0; copy_from_user(&data, arg, sizeof(data)); printk("data after interruptible_sleep_on %d\n",data); /* prints 3 */
return 0; } return -1; }
from user mode: int main(int argc, char *argv[]) { int fd; int data;
fd = open("/dev/mydrvr", O_RDWR); data = 1; ioctl(fd, IOCTL_TEST, &data); printf ("data from kernel mode %d\n", data); /* ERROR!!! prints 2, not 3 */ close(fd); }
--== Sent via Deja.com http://www.deja.com/ ==-- Share what you know. Learn what you don't.
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |