X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzpl_file.c;h=fc2b8132943405130286037dfd6bb18fda77471c;hb=5c03efc379693f992ebe39c6a00c7297c4a304ea;hp=de66ff4b49200f6bf6d997bdfde8f9ced671cb9f;hpb=3117dd0b9005eb76e483b9772c493883b82998bb;p=zfs.git diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index de66ff4..fc2b813 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,6 +260,60 @@ 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 @@ -267,33 +327,34 @@ static int zpl_readpage(struct file *filp, struct page *pp) { struct inode *ip; - loff_t off, i_size; - size_t len, wrote; - cred_t *cr = CRED(); - void *pb; + struct page *pl[1]; int error = 0; ASSERT(PageLocked(pp)); ip = pp->mapping->host; - off = page_offset(pp); - i_size = i_size_read(ip); - ASSERT3S(off, <, i_size); + pl[0] = pp; - crhold(cr); - len = MIN(PAGE_CACHE_SIZE, i_size - off); + error = -zfs_getpage(ip, pl, 1); - pb = kmap(pp); + if (error) { + SetPageError(pp); + ClearPageUptodate(pp); + } else { + ClearPageError(pp); + SetPageUptodate(pp); + flush_dcache_page(pp); + } - /* O_DIRECT is passed to bypass the page cache and avoid deadlock. */ - wrote = zpl_read_common(ip, pb, len, off, UIO_SYSSPACE, O_DIRECT, cr); - if (wrote != len) - error = -EIO; + unlock_page(pp); + return error; +} - if (!error && (len < PAGE_CACHE_SIZE)) - memset(pb + len, 0, PAGE_CACHE_SIZE - len); +int +zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data) +{ + int error; - kunmap(pp); - crfree(cr); + error = -zfs_putpage(pp, wbc, data); if (error) { SetPageError(pp); @@ -305,8 +366,13 @@ zpl_readpage(struct file *filp, struct page *pp) } unlock_page(pp); + return error; +} - return (error); +static int +zpl_writepages(struct address_space *mapping, struct writeback_control *wbc) +{ + return write_cache_pages(mapping, wbc, zpl_putpage, mapping); } /* @@ -314,55 +380,18 @@ zpl_readpage(struct file *filp, struct page *pp) * support mmap(2). Mapped pages may be dirtied by memory operations * which never call .write(). These dirty pages are kept in sync with * the ARC buffers via this hook. - * - * Currently this function relies on zpl_write_common() and the O_DIRECT - * flag to push out the page. This works but the more correct way is - * to update zfs_putapage() to be Linux friendly and use that interface. */ static int zpl_writepage(struct page *pp, struct writeback_control *wbc) { - struct inode *ip; - loff_t off, i_size; - size_t len, read; - cred_t *cr = CRED(); - void *pb; - int error = 0; - - ASSERT(PageLocked(pp)); - ip = pp->mapping->host; - off = page_offset(pp); - i_size = i_size_read(ip); - - crhold(cr); - len = MIN(PAGE_CACHE_SIZE, i_size - off); - - pb = kmap(pp); - - /* O_DIRECT is passed to bypass the page cache and avoid deadlock. */ - read = zpl_write_common(ip, pb, len, off, UIO_SYSSPACE, O_DIRECT, cr); - if (read != len) - error = -EIO; - - kunmap(pp); - crfree(cr); - - if (error) { - SetPageError(pp); - ClearPageUptodate(pp); - } else { - ClearPageError(pp); - SetPageUptodate(pp); - } - - unlock_page(pp); - - return (error); + return zpl_putpage(pp, wbc, pp->mapping); } const struct address_space_operations zpl_address_space_operations = { + .readpages = zpl_readpages, .readpage = zpl_readpage, .writepage = zpl_writepage, + .writepages = zpl_writepages, }; const struct file_operations zpl_file_operations = {