no access to user-memory after interruptible_sleep_on in ioctl handler

Lee Nichols (leenichols@my-Deja.com)
Tue, 17 Aug 1999 08:34:24 -0700


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/