Commit 88a3b490 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Use kmap_atomic() for generic_file_read()

This patch allows the kernel to hold atomic kmaps in file_read_actor().

We try to fault in the page, then take an atomic kmap.  If the atomic
copy_to_user() then faults, drop a printk and fall back to kmap().
parent 4b19c940
......@@ -1036,7 +1036,37 @@ void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t *
UPDATE_ATIME(inode);
}
int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
/*
* Fault a userspace page into pagetables. Return non-zero on a fault.
*
* FIXME: this assumes that two userspace pages are always sufficient. That's
* not true if PAGE_CACHE_SIZE > PAGE_SIZE.
*/
static inline int fault_in_pages_writeable(char *uaddr, int size)
{
int ret;
/*
* Writing zeroes into userspace here is OK, because we know that if
* the zero gets there, we'll be overwriting it.
*/
ret = __put_user(0, uaddr);
if (ret == 0) {
char *end = uaddr + size - 1;
/*
* If the page was already mapped, this will get a cache miss
* for sure, so try to avoid doing it.
*/
if (((unsigned long)uaddr & PAGE_MASK) !=
((unsigned long)end & PAGE_MASK))
ret = __put_user(0, end);
}
return ret;
}
int file_read_actor(read_descriptor_t *desc, struct page *page,
unsigned long offset, unsigned long size)
{
char *kaddr;
unsigned long left, count = desc->count;
......@@ -1044,14 +1074,28 @@ int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long o
if (size > count)
size = count;
/*
* Faults on the destination of a read are common, so do it before
* taking the kmap.
*/
if (!fault_in_pages_writeable(desc->buf, size)) {
kaddr = kmap_atomic(page, KM_USER0);
left = __copy_to_user(desc->buf, kaddr + offset, size);
kunmap_atomic(kaddr, KM_USER0);
if (left == 0)
goto success;
}
/* Do it the slow way */
kaddr = kmap(page);
left = __copy_to_user(desc->buf, kaddr + offset, size);
kunmap(page);
if (left) {
size -= left;
desc->error = -EFAULT;
}
success:
desc->count = count - size;
desc->written += size;
desc->buf += size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment