18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* AFS filesystem file handling 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/fs.h> 128c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 138c2ecf20Sopenharmony_ci#include <linux/writeback.h> 148c2ecf20Sopenharmony_ci#include <linux/gfp.h> 158c2ecf20Sopenharmony_ci#include <linux/task_io_accounting_ops.h> 168c2ecf20Sopenharmony_ci#include <linux/mm.h> 178c2ecf20Sopenharmony_ci#include "internal.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int afs_file_mmap(struct file *file, struct vm_area_struct *vma); 208c2ecf20Sopenharmony_cistatic int afs_readpage(struct file *file, struct page *page); 218c2ecf20Sopenharmony_cistatic void afs_invalidatepage(struct page *page, unsigned int offset, 228c2ecf20Sopenharmony_ci unsigned int length); 238c2ecf20Sopenharmony_cistatic int afs_releasepage(struct page *page, gfp_t gfp_flags); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int afs_readpages(struct file *filp, struct address_space *mapping, 268c2ecf20Sopenharmony_ci struct list_head *pages, unsigned nr_pages); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciconst struct file_operations afs_file_operations = { 298c2ecf20Sopenharmony_ci .open = afs_open, 308c2ecf20Sopenharmony_ci .release = afs_release, 318c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 328c2ecf20Sopenharmony_ci .read_iter = generic_file_read_iter, 338c2ecf20Sopenharmony_ci .write_iter = afs_file_write, 348c2ecf20Sopenharmony_ci .mmap = afs_file_mmap, 358c2ecf20Sopenharmony_ci .splice_read = generic_file_splice_read, 368c2ecf20Sopenharmony_ci .splice_write = iter_file_splice_write, 378c2ecf20Sopenharmony_ci .fsync = afs_fsync, 388c2ecf20Sopenharmony_ci .lock = afs_lock, 398c2ecf20Sopenharmony_ci .flock = afs_flock, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciconst struct inode_operations afs_file_inode_operations = { 438c2ecf20Sopenharmony_ci .getattr = afs_getattr, 448c2ecf20Sopenharmony_ci .setattr = afs_setattr, 458c2ecf20Sopenharmony_ci .permission = afs_permission, 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciconst struct address_space_operations afs_fs_aops = { 498c2ecf20Sopenharmony_ci .readpage = afs_readpage, 508c2ecf20Sopenharmony_ci .readpages = afs_readpages, 518c2ecf20Sopenharmony_ci .set_page_dirty = afs_set_page_dirty, 528c2ecf20Sopenharmony_ci .launder_page = afs_launder_page, 538c2ecf20Sopenharmony_ci .releasepage = afs_releasepage, 548c2ecf20Sopenharmony_ci .invalidatepage = afs_invalidatepage, 558c2ecf20Sopenharmony_ci .write_begin = afs_write_begin, 568c2ecf20Sopenharmony_ci .write_end = afs_write_end, 578c2ecf20Sopenharmony_ci .writepage = afs_writepage, 588c2ecf20Sopenharmony_ci .writepages = afs_writepages, 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct vm_operations_struct afs_vm_ops = { 628c2ecf20Sopenharmony_ci .fault = filemap_fault, 638c2ecf20Sopenharmony_ci .map_pages = filemap_map_pages, 648c2ecf20Sopenharmony_ci .page_mkwrite = afs_page_mkwrite, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * Discard a pin on a writeback key. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_civoid afs_put_wb_key(struct afs_wb_key *wbk) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci if (wbk && refcount_dec_and_test(&wbk->usage)) { 738c2ecf20Sopenharmony_ci key_put(wbk->key); 748c2ecf20Sopenharmony_ci kfree(wbk); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Cache key for writeback. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ciint afs_cache_wb_key(struct afs_vnode *vnode, struct afs_file *af) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct afs_wb_key *wbk, *p; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci wbk = kzalloc(sizeof(struct afs_wb_key), GFP_KERNEL); 868c2ecf20Sopenharmony_ci if (!wbk) 878c2ecf20Sopenharmony_ci return -ENOMEM; 888c2ecf20Sopenharmony_ci refcount_set(&wbk->usage, 2); 898c2ecf20Sopenharmony_ci wbk->key = af->key; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci spin_lock(&vnode->wb_lock); 928c2ecf20Sopenharmony_ci list_for_each_entry(p, &vnode->wb_keys, vnode_link) { 938c2ecf20Sopenharmony_ci if (p->key == wbk->key) 948c2ecf20Sopenharmony_ci goto found; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci key_get(wbk->key); 988c2ecf20Sopenharmony_ci list_add_tail(&wbk->vnode_link, &vnode->wb_keys); 998c2ecf20Sopenharmony_ci spin_unlock(&vnode->wb_lock); 1008c2ecf20Sopenharmony_ci af->wb = wbk; 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cifound: 1048c2ecf20Sopenharmony_ci refcount_inc(&p->usage); 1058c2ecf20Sopenharmony_ci spin_unlock(&vnode->wb_lock); 1068c2ecf20Sopenharmony_ci af->wb = p; 1078c2ecf20Sopenharmony_ci kfree(wbk); 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * open an AFS file or directory and attach a key to it 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ciint afs_open(struct inode *inode, struct file *file) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(inode); 1178c2ecf20Sopenharmony_ci struct afs_file *af; 1188c2ecf20Sopenharmony_ci struct key *key; 1198c2ecf20Sopenharmony_ci int ret; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci key = afs_request_key(vnode->volume->cell); 1248c2ecf20Sopenharmony_ci if (IS_ERR(key)) { 1258c2ecf20Sopenharmony_ci ret = PTR_ERR(key); 1268c2ecf20Sopenharmony_ci goto error; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci af = kzalloc(sizeof(*af), GFP_KERNEL); 1308c2ecf20Sopenharmony_ci if (!af) { 1318c2ecf20Sopenharmony_ci ret = -ENOMEM; 1328c2ecf20Sopenharmony_ci goto error_key; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci af->key = key; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci ret = afs_validate(vnode, key); 1378c2ecf20Sopenharmony_ci if (ret < 0) 1388c2ecf20Sopenharmony_ci goto error_af; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_WRITE) { 1418c2ecf20Sopenharmony_ci ret = afs_cache_wb_key(vnode, af); 1428c2ecf20Sopenharmony_ci if (ret < 0) 1438c2ecf20Sopenharmony_ci goto error_af; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (file->f_flags & O_TRUNC) 1478c2ecf20Sopenharmony_ci set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci file->private_data = af; 1508c2ecf20Sopenharmony_ci _leave(" = 0"); 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cierror_af: 1548c2ecf20Sopenharmony_ci kfree(af); 1558c2ecf20Sopenharmony_cierror_key: 1568c2ecf20Sopenharmony_ci key_put(key); 1578c2ecf20Sopenharmony_cierror: 1588c2ecf20Sopenharmony_ci _leave(" = %d", ret); 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * release an AFS file or directory and discard its key 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ciint afs_release(struct inode *inode, struct file *file) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(inode); 1688c2ecf20Sopenharmony_ci struct afs_file *af = file->private_data; 1698c2ecf20Sopenharmony_ci int ret = 0; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if ((file->f_mode & FMODE_WRITE)) 1748c2ecf20Sopenharmony_ci ret = vfs_fsync(file, 0); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci file->private_data = NULL; 1778c2ecf20Sopenharmony_ci if (af->wb) 1788c2ecf20Sopenharmony_ci afs_put_wb_key(af->wb); 1798c2ecf20Sopenharmony_ci key_put(af->key); 1808c2ecf20Sopenharmony_ci kfree(af); 1818c2ecf20Sopenharmony_ci afs_prune_wb_keys(vnode); 1828c2ecf20Sopenharmony_ci _leave(" = %d", ret); 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* 1878c2ecf20Sopenharmony_ci * Dispose of a ref to a read record. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_civoid afs_put_read(struct afs_read *req) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci int i; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&req->usage)) { 1948c2ecf20Sopenharmony_ci if (req->pages) { 1958c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_pages; i++) 1968c2ecf20Sopenharmony_ci if (req->pages[i]) 1978c2ecf20Sopenharmony_ci put_page(req->pages[i]); 1988c2ecf20Sopenharmony_ci if (req->pages != req->array) 1998c2ecf20Sopenharmony_ci kfree(req->pages); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci kfree(req); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 2068c2ecf20Sopenharmony_ci/* 2078c2ecf20Sopenharmony_ci * deal with notification that a page was read from the cache 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic void afs_file_readpage_read_complete(struct page *page, 2108c2ecf20Sopenharmony_ci void *data, 2118c2ecf20Sopenharmony_ci int error) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci _enter("%p,%p,%d", page, data, error); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* if the read completes with an error, we just unlock the page and let 2168c2ecf20Sopenharmony_ci * the VM reissue the readpage */ 2178c2ecf20Sopenharmony_ci if (!error) 2188c2ecf20Sopenharmony_ci SetPageUptodate(page); 2198c2ecf20Sopenharmony_ci unlock_page(page); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci#endif 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic void afs_fetch_data_success(struct afs_operation *op) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct afs_vnode *vnode = op->file[0].vnode; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci _enter("op=%08x", op->debug_id); 2288c2ecf20Sopenharmony_ci afs_vnode_commit_status(op, &op->file[0]); 2298c2ecf20Sopenharmony_ci afs_stat_v(vnode, n_fetches); 2308c2ecf20Sopenharmony_ci atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic void afs_fetch_data_put(struct afs_operation *op) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci afs_put_read(op->fetch.req); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic const struct afs_operation_ops afs_fetch_data_operation = { 2398c2ecf20Sopenharmony_ci .issue_afs_rpc = afs_fs_fetch_data, 2408c2ecf20Sopenharmony_ci .issue_yfs_rpc = yfs_fs_fetch_data, 2418c2ecf20Sopenharmony_ci .success = afs_fetch_data_success, 2428c2ecf20Sopenharmony_ci .aborted = afs_check_for_remote_deletion, 2438c2ecf20Sopenharmony_ci .put = afs_fetch_data_put, 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* 2478c2ecf20Sopenharmony_ci * Fetch file data from the volume. 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ciint afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *req) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct afs_operation *op; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci _enter("%s{%llx:%llu.%u},%x,,,", 2548c2ecf20Sopenharmony_ci vnode->volume->name, 2558c2ecf20Sopenharmony_ci vnode->fid.vid, 2568c2ecf20Sopenharmony_ci vnode->fid.vnode, 2578c2ecf20Sopenharmony_ci vnode->fid.unique, 2588c2ecf20Sopenharmony_ci key_serial(key)); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci op = afs_alloc_operation(key, vnode->volume); 2618c2ecf20Sopenharmony_ci if (IS_ERR(op)) 2628c2ecf20Sopenharmony_ci return PTR_ERR(op); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci afs_op_set_vnode(op, 0, vnode); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci op->fetch.req = afs_get_read(req); 2678c2ecf20Sopenharmony_ci op->ops = &afs_fetch_data_operation; 2688c2ecf20Sopenharmony_ci return afs_do_sync_operation(op); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* 2728c2ecf20Sopenharmony_ci * read page from file, directory or symlink, given a key to use 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ciint afs_page_filler(void *data, struct page *page) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 2778c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(inode); 2788c2ecf20Sopenharmony_ci struct afs_read *req; 2798c2ecf20Sopenharmony_ci struct key *key = data; 2808c2ecf20Sopenharmony_ci int ret; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci BUG_ON(!PageLocked(page)); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci ret = -ESTALE; 2878c2ecf20Sopenharmony_ci if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 2888c2ecf20Sopenharmony_ci goto error; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* is it cached? */ 2918c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 2928c2ecf20Sopenharmony_ci ret = fscache_read_or_alloc_page(vnode->cache, 2938c2ecf20Sopenharmony_ci page, 2948c2ecf20Sopenharmony_ci afs_file_readpage_read_complete, 2958c2ecf20Sopenharmony_ci NULL, 2968c2ecf20Sopenharmony_ci GFP_KERNEL); 2978c2ecf20Sopenharmony_ci#else 2988c2ecf20Sopenharmony_ci ret = -ENOBUFS; 2998c2ecf20Sopenharmony_ci#endif 3008c2ecf20Sopenharmony_ci switch (ret) { 3018c2ecf20Sopenharmony_ci /* read BIO submitted (page in cache) */ 3028c2ecf20Sopenharmony_ci case 0: 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* page not yet cached */ 3068c2ecf20Sopenharmony_ci case -ENODATA: 3078c2ecf20Sopenharmony_ci _debug("cache said ENODATA"); 3088c2ecf20Sopenharmony_ci goto go_on; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* page will not be cached */ 3118c2ecf20Sopenharmony_ci case -ENOBUFS: 3128c2ecf20Sopenharmony_ci _debug("cache said ENOBUFS"); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci fallthrough; 3158c2ecf20Sopenharmony_ci default: 3168c2ecf20Sopenharmony_ci go_on: 3178c2ecf20Sopenharmony_ci req = kzalloc(struct_size(req, array, 1), GFP_KERNEL); 3188c2ecf20Sopenharmony_ci if (!req) 3198c2ecf20Sopenharmony_ci goto enomem; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* We request a full page. If the page is a partial one at the 3228c2ecf20Sopenharmony_ci * end of the file, the server will return a short read and the 3238c2ecf20Sopenharmony_ci * unmarshalling code will clear the unfilled space. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci refcount_set(&req->usage, 1); 3268c2ecf20Sopenharmony_ci req->pos = (loff_t)page->index << PAGE_SHIFT; 3278c2ecf20Sopenharmony_ci req->len = PAGE_SIZE; 3288c2ecf20Sopenharmony_ci req->nr_pages = 1; 3298c2ecf20Sopenharmony_ci req->pages = req->array; 3308c2ecf20Sopenharmony_ci req->pages[0] = page; 3318c2ecf20Sopenharmony_ci get_page(page); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* read the contents of the file from the server into the 3348c2ecf20Sopenharmony_ci * page */ 3358c2ecf20Sopenharmony_ci ret = afs_fetch_data(vnode, key, req); 3368c2ecf20Sopenharmony_ci afs_put_read(req); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (ret < 0) { 3398c2ecf20Sopenharmony_ci if (ret == -ENOENT) { 3408c2ecf20Sopenharmony_ci _debug("got NOENT from server" 3418c2ecf20Sopenharmony_ci " - marking file deleted and stale"); 3428c2ecf20Sopenharmony_ci set_bit(AFS_VNODE_DELETED, &vnode->flags); 3438c2ecf20Sopenharmony_ci ret = -ESTALE; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 3478c2ecf20Sopenharmony_ci fscache_uncache_page(vnode->cache, page); 3488c2ecf20Sopenharmony_ci#endif 3498c2ecf20Sopenharmony_ci BUG_ON(PageFsCache(page)); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (ret == -EINTR || 3528c2ecf20Sopenharmony_ci ret == -ENOMEM || 3538c2ecf20Sopenharmony_ci ret == -ERESTARTSYS || 3548c2ecf20Sopenharmony_ci ret == -EAGAIN) 3558c2ecf20Sopenharmony_ci goto error; 3568c2ecf20Sopenharmony_ci goto io_error; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci SetPageUptodate(page); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* send the page to the cache */ 3628c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 3638c2ecf20Sopenharmony_ci if (PageFsCache(page) && 3648c2ecf20Sopenharmony_ci fscache_write_page(vnode->cache, page, vnode->status.size, 3658c2ecf20Sopenharmony_ci GFP_KERNEL) != 0) { 3668c2ecf20Sopenharmony_ci fscache_uncache_page(vnode->cache, page); 3678c2ecf20Sopenharmony_ci BUG_ON(PageFsCache(page)); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci#endif 3708c2ecf20Sopenharmony_ci unlock_page(page); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci _leave(" = 0"); 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ciio_error: 3778c2ecf20Sopenharmony_ci SetPageError(page); 3788c2ecf20Sopenharmony_ci goto error; 3798c2ecf20Sopenharmony_cienomem: 3808c2ecf20Sopenharmony_ci ret = -ENOMEM; 3818c2ecf20Sopenharmony_cierror: 3828c2ecf20Sopenharmony_ci unlock_page(page); 3838c2ecf20Sopenharmony_ci _leave(" = %d", ret); 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/* 3888c2ecf20Sopenharmony_ci * read page from file, directory or symlink, given a file to nominate the key 3898c2ecf20Sopenharmony_ci * to be used 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_cistatic int afs_readpage(struct file *file, struct page *page) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct key *key; 3948c2ecf20Sopenharmony_ci int ret; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (file) { 3978c2ecf20Sopenharmony_ci key = afs_file_key(file); 3988c2ecf20Sopenharmony_ci ASSERT(key != NULL); 3998c2ecf20Sopenharmony_ci ret = afs_page_filler(key, page); 4008c2ecf20Sopenharmony_ci } else { 4018c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 4028c2ecf20Sopenharmony_ci key = afs_request_key(AFS_FS_S(inode->i_sb)->cell); 4038c2ecf20Sopenharmony_ci if (IS_ERR(key)) { 4048c2ecf20Sopenharmony_ci ret = PTR_ERR(key); 4058c2ecf20Sopenharmony_ci } else { 4068c2ecf20Sopenharmony_ci ret = afs_page_filler(key, page); 4078c2ecf20Sopenharmony_ci key_put(key); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/* 4148c2ecf20Sopenharmony_ci * Make pages available as they're filled. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_cistatic void afs_readpages_page_done(struct afs_read *req) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 4198c2ecf20Sopenharmony_ci struct afs_vnode *vnode = req->vnode; 4208c2ecf20Sopenharmony_ci#endif 4218c2ecf20Sopenharmony_ci struct page *page = req->pages[req->index]; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci req->pages[req->index] = NULL; 4248c2ecf20Sopenharmony_ci SetPageUptodate(page); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* send the page to the cache */ 4278c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 4288c2ecf20Sopenharmony_ci if (PageFsCache(page) && 4298c2ecf20Sopenharmony_ci fscache_write_page(vnode->cache, page, vnode->status.size, 4308c2ecf20Sopenharmony_ci GFP_KERNEL) != 0) { 4318c2ecf20Sopenharmony_ci fscache_uncache_page(vnode->cache, page); 4328c2ecf20Sopenharmony_ci BUG_ON(PageFsCache(page)); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci#endif 4358c2ecf20Sopenharmony_ci unlock_page(page); 4368c2ecf20Sopenharmony_ci put_page(page); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* 4408c2ecf20Sopenharmony_ci * Read a contiguous set of pages. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_cistatic int afs_readpages_one(struct file *file, struct address_space *mapping, 4438c2ecf20Sopenharmony_ci struct list_head *pages) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(mapping->host); 4468c2ecf20Sopenharmony_ci struct afs_read *req; 4478c2ecf20Sopenharmony_ci struct list_head *p; 4488c2ecf20Sopenharmony_ci struct page *first, *page; 4498c2ecf20Sopenharmony_ci struct key *key = afs_file_key(file); 4508c2ecf20Sopenharmony_ci pgoff_t index; 4518c2ecf20Sopenharmony_ci int ret, n, i; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* Count the number of contiguous pages at the front of the list. Note 4548c2ecf20Sopenharmony_ci * that the list goes prev-wards rather than next-wards. 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci first = lru_to_page(pages); 4578c2ecf20Sopenharmony_ci index = first->index + 1; 4588c2ecf20Sopenharmony_ci n = 1; 4598c2ecf20Sopenharmony_ci for (p = first->lru.prev; p != pages; p = p->prev) { 4608c2ecf20Sopenharmony_ci page = list_entry(p, struct page, lru); 4618c2ecf20Sopenharmony_ci if (page->index != index) 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci index++; 4648c2ecf20Sopenharmony_ci n++; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci req = kzalloc(struct_size(req, array, n), GFP_NOFS); 4688c2ecf20Sopenharmony_ci if (!req) 4698c2ecf20Sopenharmony_ci return -ENOMEM; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci refcount_set(&req->usage, 1); 4728c2ecf20Sopenharmony_ci req->vnode = vnode; 4738c2ecf20Sopenharmony_ci req->page_done = afs_readpages_page_done; 4748c2ecf20Sopenharmony_ci req->pos = first->index; 4758c2ecf20Sopenharmony_ci req->pos <<= PAGE_SHIFT; 4768c2ecf20Sopenharmony_ci req->pages = req->array; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* Transfer the pages to the request. We add them in until one fails 4798c2ecf20Sopenharmony_ci * to add to the LRU and then we stop (as that'll make a hole in the 4808c2ecf20Sopenharmony_ci * contiguous run. 4818c2ecf20Sopenharmony_ci * 4828c2ecf20Sopenharmony_ci * Note that it's possible for the file size to change whilst we're 4838c2ecf20Sopenharmony_ci * doing this, but we rely on the server returning less than we asked 4848c2ecf20Sopenharmony_ci * for if the file shrank. We also rely on this to deal with a partial 4858c2ecf20Sopenharmony_ci * page at the end of the file. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci do { 4888c2ecf20Sopenharmony_ci page = lru_to_page(pages); 4898c2ecf20Sopenharmony_ci list_del(&page->lru); 4908c2ecf20Sopenharmony_ci index = page->index; 4918c2ecf20Sopenharmony_ci if (add_to_page_cache_lru(page, mapping, index, 4928c2ecf20Sopenharmony_ci readahead_gfp_mask(mapping))) { 4938c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 4948c2ecf20Sopenharmony_ci fscache_uncache_page(vnode->cache, page); 4958c2ecf20Sopenharmony_ci#endif 4968c2ecf20Sopenharmony_ci put_page(page); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci req->pages[req->nr_pages++] = page; 5018c2ecf20Sopenharmony_ci req->len += PAGE_SIZE; 5028c2ecf20Sopenharmony_ci } while (req->nr_pages < n); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (req->nr_pages == 0) { 5058c2ecf20Sopenharmony_ci kfree(req); 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci ret = afs_fetch_data(vnode, key, req); 5108c2ecf20Sopenharmony_ci if (ret < 0) 5118c2ecf20Sopenharmony_ci goto error; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci task_io_account_read(PAGE_SIZE * req->nr_pages); 5148c2ecf20Sopenharmony_ci afs_put_read(req); 5158c2ecf20Sopenharmony_ci return 0; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cierror: 5188c2ecf20Sopenharmony_ci if (ret == -ENOENT) { 5198c2ecf20Sopenharmony_ci _debug("got NOENT from server" 5208c2ecf20Sopenharmony_ci " - marking file deleted and stale"); 5218c2ecf20Sopenharmony_ci set_bit(AFS_VNODE_DELETED, &vnode->flags); 5228c2ecf20Sopenharmony_ci ret = -ESTALE; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci for (i = 0; i < req->nr_pages; i++) { 5268c2ecf20Sopenharmony_ci page = req->pages[i]; 5278c2ecf20Sopenharmony_ci if (page) { 5288c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 5298c2ecf20Sopenharmony_ci fscache_uncache_page(vnode->cache, page); 5308c2ecf20Sopenharmony_ci#endif 5318c2ecf20Sopenharmony_ci SetPageError(page); 5328c2ecf20Sopenharmony_ci unlock_page(page); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci afs_put_read(req); 5378c2ecf20Sopenharmony_ci return ret; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/* 5418c2ecf20Sopenharmony_ci * read a set of pages 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_cistatic int afs_readpages(struct file *file, struct address_space *mapping, 5448c2ecf20Sopenharmony_ci struct list_head *pages, unsigned nr_pages) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct key *key = afs_file_key(file); 5478c2ecf20Sopenharmony_ci struct afs_vnode *vnode; 5488c2ecf20Sopenharmony_ci int ret = 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci _enter("{%d},{%lu},,%d", 5518c2ecf20Sopenharmony_ci key_serial(key), mapping->host->i_ino, nr_pages); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci ASSERT(key != NULL); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci vnode = AFS_FS_I(mapping->host); 5568c2ecf20Sopenharmony_ci if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 5578c2ecf20Sopenharmony_ci _leave(" = -ESTALE"); 5588c2ecf20Sopenharmony_ci return -ESTALE; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* attempt to read as many of the pages as possible */ 5628c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 5638c2ecf20Sopenharmony_ci ret = fscache_read_or_alloc_pages(vnode->cache, 5648c2ecf20Sopenharmony_ci mapping, 5658c2ecf20Sopenharmony_ci pages, 5668c2ecf20Sopenharmony_ci &nr_pages, 5678c2ecf20Sopenharmony_ci afs_file_readpage_read_complete, 5688c2ecf20Sopenharmony_ci NULL, 5698c2ecf20Sopenharmony_ci mapping_gfp_mask(mapping)); 5708c2ecf20Sopenharmony_ci#else 5718c2ecf20Sopenharmony_ci ret = -ENOBUFS; 5728c2ecf20Sopenharmony_ci#endif 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci switch (ret) { 5758c2ecf20Sopenharmony_ci /* all pages are being read from the cache */ 5768c2ecf20Sopenharmony_ci case 0: 5778c2ecf20Sopenharmony_ci BUG_ON(!list_empty(pages)); 5788c2ecf20Sopenharmony_ci BUG_ON(nr_pages != 0); 5798c2ecf20Sopenharmony_ci _leave(" = 0 [reading all]"); 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* there were pages that couldn't be read from the cache */ 5838c2ecf20Sopenharmony_ci case -ENODATA: 5848c2ecf20Sopenharmony_ci case -ENOBUFS: 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* other error */ 5888c2ecf20Sopenharmony_ci default: 5898c2ecf20Sopenharmony_ci _leave(" = %d", ret); 5908c2ecf20Sopenharmony_ci return ret; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci while (!list_empty(pages)) { 5948c2ecf20Sopenharmony_ci ret = afs_readpages_one(file, mapping, pages); 5958c2ecf20Sopenharmony_ci if (ret < 0) 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci _leave(" = %d [netting]", ret); 6008c2ecf20Sopenharmony_ci return ret; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci/* 6048c2ecf20Sopenharmony_ci * Adjust the dirty region of the page on truncation or full invalidation, 6058c2ecf20Sopenharmony_ci * getting rid of the markers altogether if the region is entirely invalidated. 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_cistatic void afs_invalidate_dirty(struct page *page, unsigned int offset, 6088c2ecf20Sopenharmony_ci unsigned int length) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 6118c2ecf20Sopenharmony_ci unsigned long priv; 6128c2ecf20Sopenharmony_ci unsigned int f, t, end = offset + length; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci priv = page_private(page); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* we clean up only if the entire page is being invalidated */ 6178c2ecf20Sopenharmony_ci if (offset == 0 && length == thp_size(page)) 6188c2ecf20Sopenharmony_ci goto full_invalidate; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* If the page was dirtied by page_mkwrite(), the PTE stays writable 6218c2ecf20Sopenharmony_ci * and we don't get another notification to tell us to expand it 6228c2ecf20Sopenharmony_ci * again. 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_ci if (afs_is_page_dirty_mmapped(priv)) 6258c2ecf20Sopenharmony_ci return; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* We may need to shorten the dirty region */ 6288c2ecf20Sopenharmony_ci f = afs_page_dirty_from(priv); 6298c2ecf20Sopenharmony_ci t = afs_page_dirty_to(priv); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (t <= offset || f >= end) 6328c2ecf20Sopenharmony_ci return; /* Doesn't overlap */ 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (f < offset && t > end) 6358c2ecf20Sopenharmony_ci return; /* Splits the dirty region - just absorb it */ 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (f >= offset && t <= end) 6388c2ecf20Sopenharmony_ci goto undirty; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (f < offset) 6418c2ecf20Sopenharmony_ci t = offset; 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci f = end; 6448c2ecf20Sopenharmony_ci if (f == t) 6458c2ecf20Sopenharmony_ci goto undirty; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci priv = afs_page_dirty(f, t); 6488c2ecf20Sopenharmony_ci set_page_private(page, priv); 6498c2ecf20Sopenharmony_ci trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page->index, priv); 6508c2ecf20Sopenharmony_ci return; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ciundirty: 6538c2ecf20Sopenharmony_ci trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page->index, priv); 6548c2ecf20Sopenharmony_ci clear_page_dirty_for_io(page); 6558c2ecf20Sopenharmony_cifull_invalidate: 6568c2ecf20Sopenharmony_ci priv = (unsigned long)detach_page_private(page); 6578c2ecf20Sopenharmony_ci trace_afs_page_dirty(vnode, tracepoint_string("inval"), page->index, priv); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/* 6618c2ecf20Sopenharmony_ci * invalidate part or all of a page 6628c2ecf20Sopenharmony_ci * - release a page and clean up its private data if offset is 0 (indicating 6638c2ecf20Sopenharmony_ci * the entire page) 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_cistatic void afs_invalidatepage(struct page *page, unsigned int offset, 6668c2ecf20Sopenharmony_ci unsigned int length) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci _enter("{%lu},%u,%u", page->index, offset, length); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci BUG_ON(!PageLocked(page)); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 6738c2ecf20Sopenharmony_ci /* we clean up only if the entire page is being invalidated */ 6748c2ecf20Sopenharmony_ci if (offset == 0 && length == PAGE_SIZE) { 6758c2ecf20Sopenharmony_ci if (PageFsCache(page)) { 6768c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 6778c2ecf20Sopenharmony_ci fscache_wait_on_page_write(vnode->cache, page); 6788c2ecf20Sopenharmony_ci fscache_uncache_page(vnode->cache, page); 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci#endif 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (PagePrivate(page)) 6848c2ecf20Sopenharmony_ci afs_invalidate_dirty(page, offset, length); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci _leave(""); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/* 6908c2ecf20Sopenharmony_ci * release a page and clean up its private state if it's not busy 6918c2ecf20Sopenharmony_ci * - return true if the page can now be released, false if not 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_cistatic int afs_releasepage(struct page *page, gfp_t gfp_flags) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 6968c2ecf20Sopenharmony_ci unsigned long priv; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci _enter("{{%llx:%llu}[%lu],%lx},%x", 6998c2ecf20Sopenharmony_ci vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, 7008c2ecf20Sopenharmony_ci gfp_flags); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* deny if page is being written to the cache and the caller hasn't 7038c2ecf20Sopenharmony_ci * elected to wait */ 7048c2ecf20Sopenharmony_ci#ifdef CONFIG_AFS_FSCACHE 7058c2ecf20Sopenharmony_ci if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { 7068c2ecf20Sopenharmony_ci _leave(" = F [cache busy]"); 7078c2ecf20Sopenharmony_ci return 0; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci#endif 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (PagePrivate(page)) { 7128c2ecf20Sopenharmony_ci priv = (unsigned long)detach_page_private(page); 7138c2ecf20Sopenharmony_ci trace_afs_page_dirty(vnode, tracepoint_string("rel"), 7148c2ecf20Sopenharmony_ci page->index, priv); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* indicate that the page can be released */ 7188c2ecf20Sopenharmony_ci _leave(" = T"); 7198c2ecf20Sopenharmony_ci return 1; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci/* 7238c2ecf20Sopenharmony_ci * Handle setting up a memory mapping on an AFS file. 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_cistatic int afs_file_mmap(struct file *file, struct vm_area_struct *vma) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci int ret; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ret = generic_file_mmap(file, vma); 7308c2ecf20Sopenharmony_ci if (ret == 0) 7318c2ecf20Sopenharmony_ci vma->vm_ops = &afs_vm_ops; 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci} 734