vm_ops.page_mkwrite() fails with vmalloc on 2.6.23
Hi,
i have a problem with vmalloc() and vm_ops.page_mkwrite().
ReadOnly access works, but on a write access the VM will endless invoke the vm_ops.page_mkwrite() handler.
I tracked down the problem to the
struct page.mapping pointer,
which is NULL.
The problem original occurs with the fb_defio driver (driver/video/fb_defio.c). This driver use the vm_ops.page_mkwrite() handler for tracking the modified pages, which will be in an extra thread handled, to perform the IO and clean and write protect all pages with page_clean().
I am not sure if the is a feature of the new rmap code or a bug.
Is there an way to get a similar functionality? Currently, i have no idea
how to get the ptep from a page alloced with vmalloc().
Greetings,
Stefani
Here is a small sample driver:
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#define DEVICE_NAME "mydrv"
#define DEVICE_MAJOR 240
static u8 *mydrv_memory;
static const u_long mydrv_memory_size=1024*1024; // 1 Megabyte
#ifdef MODULE
static u_long vmas=0;
#endif
static void mydrv_vma_open(struct vm_area_struct *vma) {
#ifdef MODULE if (vmas++==0) try_module_get(THIS_MODULE);
#endif
}
static void mydrv_vma_close(struct vm_area_struct *vma) {
#ifdef MODULE if (--vmas==0) module_put(THIS_MODULE);
#endif
}
struct page *mydrv_vma_nopage(struct vm_area_struct *vma,unsigned long address,int *type)
{
unsigned long offset;
struct page *page;
offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
printk("--> mydrv_vma_nopage:%lu(%08lx)\n",offset,offset);
if (offset >= mydrv_memory_size)
return NOPAGE_SIGBUS;
page = vmalloc_to_page(mydrv_memory + offset);
if (!page)
return NOPAGE_OOM;
get_page(page);
if (type)
*type = VM_FAULT_MINOR;
return page;
}int mydrv_mkwrite(struct vm_area_struct *vma,struct page *page)
{
printk("--> mydrv_mkwrite:%p\n",page->mapping);
return 0;
}struct vm_operations_struct mydrv_vm_ops = {
.open = mydrv_vma_open,
.close = mydrv_vma_close,
.nopage = mydrv_vma_nopage,
.page_mkwrite = mydrv_mkwrite,
};
static int mydrv_mmap(struct file *file, struct vm_area_struct *vma)
{
vma->vm_ops = &mydrv_vm_ops;
vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND );
vma->vm_private_data = 0;
mydrv_vma_open(vma);
return 0;
}int mydrv_open(struct inode *inode, struct file *file)
{
int minor;
minor=MINOR(file->f_dentry->d_inode->i_rdev);
printk("--> mydrv_open called for minor: %d\n", minor);
if (minor>0) {
printk("--> mydrv_open minor %d failed\n",minor);
return -ENODEV;
}
printk("--> mydrv_open o.K.\n");
return 0;
}int mydrv_close(struct inode *inode, struct file *file)
{
int minor;
minor=MINOR(file->f_dentry->d_inode->i_rdev);
printk("--> mydrv_close for minor: %d\n", minor);
return 0;
}struct file_operations mydrv_fops = {
.owner=THIS_MODULE,
.mmap=mydrv_mmap,
.open=mydrv_open,
.release=mydrv_close,
};
int init_module(void)
{
printk("--> init_module called\n");
if (!(mydrv_memory = vmalloc(mydrv_memory_size)))
return -ENOMEM;
if (register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &mydrv_fops) < 0) {
printk("--> Error registering driver.\n");
return -ENODEV;
}
memset(mydrv_memory, 0, mydrv_memory_size);
printk("--> init_module done\n");
return 0;
}void cleanup_module(void)
{
printk("--> cleanup_module called\n");
unregister_chrdev(DEVICE_MAJOR,DEVICE_NAME);
vfree(mydrv_memory);
printk("--> cleanup_module done\n");
}MODULE_LICENSE("GPL");MODULE_AUTHOR("Stefan Seibold <[email protected]>"); MODULE_DESCRIPTION("Test Driver");
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines · Stefani Seibold
i have a problem with
vmalloc()andvm_ops.page_mkwrite().ReadOnly access works, but on a write access the VM will endless invoke the
vm_ops.page_mkwrite()handler.
Quoted 8 lines
I tracked down the problem to the
struct page.mapping pointer,
which is NULL.The problem original occurs with the
fb_defiodriver (driver/video/fb_defio.c). This driver use thevm_ops.page_mkwrite()handler for tracking the modified pages, which will be in an extra thread handled, to perform the IO and clean and write protect all pages withpage_clean().
Interesting. You need to ask Jaya (CC'ed) since he's the one who put that code into fb_defio.c, exported page_mkclean, and should have tested it.
Quoted 2 lines
I am not sure if the is a feature of the new rmap code or a bug.
page_mkclean was written in the belief that it was being used on pagecache pages. I'm not sure how deeply engrained that belief is.
If it can easily and safely be used on something else, that may be
nice: though there's a danger we'll keep breaking and re-breaking it if there's only one driver using it in an unusual way. CC'ed Peter since he's the one who most needs to be aware of this.
Quoted 4 lines
Is there an way to get a similar functionality? Currently, i have no idea
how to get the ptep from a page alloced withvmalloc().
A pagecache page would have page->mapping initialized to point to the struct address_space of the vma, and page->index to the offset (in PAGE_SIZE units): see mm/filemap.c:add_to_page_cache. Without page->mapping set, page_mkclean_file won't be able to find the vmas in which the page might appear; and without page->index set, it won't be able to find where the page should be in those vmas.
If such a driver does not put its pages into the page cache (the safer course? I'm unsure), then it needs to set page->mapping and page->index appropriately (and reset page->mapping to NULL before freeing).
Hugh
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 4 lines · Hugh Dickins
Interesting. You need to ask Jaya (CC'ed) since he's the one who put that code into
fb_defio.c, exportedpage_mkclean, and should have tested it.
Thanks Hugh.
Yes, hecubafb uses fb_defio (which is infrastructure code) which uses mkwrite/mkclean. This was tested and it worked great on x86 with 2.6.21 when I posted the patches.
I will be trying in the next few weeks to finish up a driver for the current E-Ink Vizplex+controller working on arm with 2.6.22. So since page_mkclean has changed, I will try to work on a update for fb_defio at that time.
Quoted 11 lines
Quoted 3 lines
I am not sure if the is a feature of the new rmap code or a bug.
page_mkcleanwas written in the belief that it was being used on pagecache pages. I'm not sure how deeply engrained that belief is.If it can easily and safely be used on something else, that may be
nice: though there's a danger we'll keep breaking and re-breaking it if there's only one driver using it in an unusual way. CC'ed Peter since he's the one who most needs to be aware of this.
Yes, right now, only hecubafb uses deferred IO and thus page_mkclean. But I believe that usage will increase. I hope together we can get it fixed up and keep it working long term. I think deferred IO gives linux a nice advantage when interfacing with high latency displays (of which one will increasingly see more of).
Thanks,
jaya
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Stefani Seibold
Hi,
i have a problem with
vmalloc()andvm_ops.page_mkwrite().ReadOnly access works, but on a write access the VM will endless invoke the
vm_ops.page_mkwrite()handler.I tracked down the problem to the
struct page.mapping pointer,
which is NULL.
Where?
would this happen to be in set_page_dirty_balance(, .page_mkwrite=1) ?
I indeed over-looked the fb_defio driver when I grepped the tree for ->page_mkwrite() usage :-/
The proper fix is to revert this set_page_dirty_balance() hack and make the filesystem ->page_mkwrite() implementations call balance_dirty_pages_ratelimited()
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 14 lines · Peter Zijlstra
Quoted 10 lines · Stefani Seibold
Hi,
i have a problem with
vmalloc()andvm_ops.page_mkwrite().ReadOnly access works, but on a write access the VM will endless invoke the
vm_ops.page_mkwrite()handler.I tracked down the problem to the
struct page.mapping pointer,
which is NULL.Where?
Quoted 8 lines
would this happen to be in
set_page_dirty_balance(, .page_mkwrite=1)?I indeed over-looked the
fb_defiodriver when I grepped the tree for ->page_mkwrite() usage :-/The proper fix is to revert this
set_page_dirty_balance()hack and make the filesystem ->page_mkwrite() implementations callbalance_dirty_pages_ratelimited()
Hmm, that should all work out when page->mapping is NULL.
/me goes look again..
Aaah, the truncate fixlet, yes that will mess one up.. /me goes ponder what to do about that..
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>