X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzpl_file.c;h=af46afddfbbcf0ffcc255d4b40c2ad4fa2b89424;hb=9c4f40b894dd5b5c2ef18546d23d7e91095ac509;hp=0e90b78036ca05961be3c1f6e5cc05d25ae22bd7;hpb=dde471ef5a07bd569deeadd3e9a88655db3e10ab;p=zfs.git diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index 0e90b78..af46afd 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -240,9 +240,15 @@ zpl_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) static int zpl_mmap(struct file *filp, struct vm_area_struct *vma) { - znode_t *zp = ITOZ(filp->f_mapping->host); + struct inode *ip = filp->f_mapping->host; + znode_t *zp = ITOZ(ip); int error; + error = -zfs_map(ip, vma->vm_pgoff, (caddr_t *)vma->vm_start, + (size_t)(vma->vm_end - vma->vm_start), vma->vm_flags); + if (error) + return (error); + error = generic_file_mmap(filp, vma); if (error) return (error); @@ -254,60 +260,6 @@ zpl_mmap(struct file *filp, struct vm_area_struct *vma) return (error); } -static struct page ** -pages_vector_from_list(struct list_head *pages, unsigned nr_pages) -{ - struct page **pl; - struct page *t; - unsigned page_idx; - - pl = kmalloc(sizeof(*pl) * nr_pages, GFP_NOFS); - if (!pl) - return ERR_PTR(-ENOMEM); - - page_idx = 0; - list_for_each_entry_reverse(t, pages, lru) { - pl[page_idx] = t; - page_idx++; - } - - return pl; -} - -static int -zpl_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - struct inode *ip; - struct page **pl; - struct page *p, *n; - int error; - - ip = mapping->host; - - pl = pages_vector_from_list(pages, nr_pages); - if (IS_ERR(pl)) - return PTR_ERR(pl); - - error = -zfs_getpage(ip, pl, nr_pages); - if (error) - goto error; - - list_for_each_entry_safe_reverse(p, n, pages, lru) { - - list_del(&p->lru); - - flush_dcache_page(p); - SetPageUptodate(p); - unlock_page(p); - page_cache_release(p); - } - -error: - kfree(pl); - return error; -} - /* * Populate a page with data for the Linux page cache. This function is * only used to support mmap(2). There will be an identical copy of the @@ -343,24 +295,40 @@ zpl_readpage(struct file *filp, struct page *pp) return error; } +/* + * Populate a set of pages with data for the Linux page cache. This + * function will only be called for read ahead and never for demand + * paging. For simplicity, the code relies on read_cache_pages() to + * correctly lock each page for IO and call zpl_readpage(). + */ +static int +zpl_readpages(struct file *filp, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + return (read_cache_pages(mapping, pages, + (filler_t *)zpl_readpage, filp)); +} + int zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data) { - int error; - - error = -zfs_putpage(pp, wbc, data); - - if (error) { - SetPageError(pp); - ClearPageUptodate(pp); - } else { - ClearPageError(pp); - SetPageUptodate(pp); - flush_dcache_page(pp); - } + struct address_space *mapping = data; - unlock_page(pp); - return error; + ASSERT(PageLocked(pp)); + ASSERT(!PageWriteback(pp)); + + /* + * Disable the normal reclaim path for zpl_putpage(). This + * ensures that all memory allocations under this call path + * will never enter direct reclaim. If this were to happen + * the VM might try to write out additional pages by calling + * zpl_putpage() again resulting in a deadlock. + */ + current->flags |= PF_MEMALLOC; + (void) zfs_putpage(mapping->host, pp, wbc); + current->flags &= ~PF_MEMALLOC; + + return (0); } static int