12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 208e0e7c8SDavid Howells /* AFS filesystem file handling 31da177e4SLinus Torvalds * 408e0e7c8SDavid Howells * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. 51da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/kernel.h> 91da177e4SLinus Torvalds #include <linux/module.h> 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/fs.h> 121da177e4SLinus Torvalds #include <linux/pagemap.h> 1331143d5dSDavid Howells #include <linux/writeback.h> 145a0e3ad6STejun Heo #include <linux/gfp.h> 1591b467e0SDavid Howells #include <linux/task_io_accounting_ops.h> 16f86196eaSNikolay Borisov #include <linux/mm.h> 175cbf0398SDavid Howells #include <linux/netfs.h> 181da177e4SLinus Torvalds #include "internal.h" 191da177e4SLinus Torvalds 201cf7a151SDavid Howells static int afs_file_mmap(struct file *file, struct vm_area_struct *vma); 21416351f2SDavid Howells static int afs_readpage(struct file *file, struct page *page); 22d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset, 23d47992f8SLukas Czerner unsigned int length); 24416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags); 251da177e4SLinus Torvalds 265cbf0398SDavid Howells static void afs_readahead(struct readahead_control *ractl); 279b3f26c9SDavid Howells 2800d3b7a4SDavid Howells const struct file_operations afs_file_operations = { 2900d3b7a4SDavid Howells .open = afs_open, 3000d3b7a4SDavid Howells .release = afs_release, 3100d3b7a4SDavid Howells .llseek = generic_file_llseek, 32aad4f8bbSAl Viro .read_iter = generic_file_read_iter, 3350b5551dSAl Viro .write_iter = afs_file_write, 341cf7a151SDavid Howells .mmap = afs_file_mmap, 355ffc4ef4SJens Axboe .splice_read = generic_file_splice_read, 3606a17bbeSDavid Howells .splice_write = iter_file_splice_write, 3731143d5dSDavid Howells .fsync = afs_fsync, 38e8d6c554SDavid Howells .lock = afs_lock, 39e8d6c554SDavid Howells .flock = afs_flock, 4000d3b7a4SDavid Howells }; 4100d3b7a4SDavid Howells 42754661f1SArjan van de Ven const struct inode_operations afs_file_inode_operations = { 43416351f2SDavid Howells .getattr = afs_getattr, 4431143d5dSDavid Howells .setattr = afs_setattr, 4500d3b7a4SDavid Howells .permission = afs_permission, 461da177e4SLinus Torvalds }; 471da177e4SLinus Torvalds 48f5e54d6eSChristoph Hellwig const struct address_space_operations afs_fs_aops = { 49416351f2SDavid Howells .readpage = afs_readpage, 505cbf0398SDavid Howells .readahead = afs_readahead, 5131143d5dSDavid Howells .set_page_dirty = afs_set_page_dirty, 5231143d5dSDavid Howells .launder_page = afs_launder_page, 53416351f2SDavid Howells .releasepage = afs_releasepage, 54416351f2SDavid Howells .invalidatepage = afs_invalidatepage, 5515b4650eSNick Piggin .write_begin = afs_write_begin, 5615b4650eSNick Piggin .write_end = afs_write_end, 5731143d5dSDavid Howells .writepage = afs_writepage, 5831143d5dSDavid Howells .writepages = afs_writepages, 591da177e4SLinus Torvalds }; 601da177e4SLinus Torvalds 611cf7a151SDavid Howells static const struct vm_operations_struct afs_vm_ops = { 621cf7a151SDavid Howells .fault = filemap_fault, 631cf7a151SDavid Howells .map_pages = filemap_map_pages, 641cf7a151SDavid Howells .page_mkwrite = afs_page_mkwrite, 651cf7a151SDavid Howells }; 661cf7a151SDavid Howells 671da177e4SLinus Torvalds /* 684343d008SDavid Howells * Discard a pin on a writeback key. 694343d008SDavid Howells */ 704343d008SDavid Howells void afs_put_wb_key(struct afs_wb_key *wbk) 714343d008SDavid Howells { 72e49c7b2fSDavid Howells if (wbk && refcount_dec_and_test(&wbk->usage)) { 734343d008SDavid Howells key_put(wbk->key); 744343d008SDavid Howells kfree(wbk); 754343d008SDavid Howells } 764343d008SDavid Howells } 774343d008SDavid Howells 784343d008SDavid Howells /* 794343d008SDavid Howells * Cache key for writeback. 804343d008SDavid Howells */ 814343d008SDavid Howells int afs_cache_wb_key(struct afs_vnode *vnode, struct afs_file *af) 824343d008SDavid Howells { 834343d008SDavid Howells struct afs_wb_key *wbk, *p; 844343d008SDavid Howells 854343d008SDavid Howells wbk = kzalloc(sizeof(struct afs_wb_key), GFP_KERNEL); 864343d008SDavid Howells if (!wbk) 874343d008SDavid Howells return -ENOMEM; 884343d008SDavid Howells refcount_set(&wbk->usage, 2); 894343d008SDavid Howells wbk->key = af->key; 904343d008SDavid Howells 914343d008SDavid Howells spin_lock(&vnode->wb_lock); 924343d008SDavid Howells list_for_each_entry(p, &vnode->wb_keys, vnode_link) { 934343d008SDavid Howells if (p->key == wbk->key) 944343d008SDavid Howells goto found; 954343d008SDavid Howells } 964343d008SDavid Howells 974343d008SDavid Howells key_get(wbk->key); 984343d008SDavid Howells list_add_tail(&wbk->vnode_link, &vnode->wb_keys); 994343d008SDavid Howells spin_unlock(&vnode->wb_lock); 1004343d008SDavid Howells af->wb = wbk; 1014343d008SDavid Howells return 0; 1024343d008SDavid Howells 1034343d008SDavid Howells found: 1044343d008SDavid Howells refcount_inc(&p->usage); 1054343d008SDavid Howells spin_unlock(&vnode->wb_lock); 1064343d008SDavid Howells af->wb = p; 1074343d008SDavid Howells kfree(wbk); 1084343d008SDavid Howells return 0; 1094343d008SDavid Howells } 1104343d008SDavid Howells 1114343d008SDavid Howells /* 11200d3b7a4SDavid Howells * open an AFS file or directory and attach a key to it 11300d3b7a4SDavid Howells */ 11400d3b7a4SDavid Howells int afs_open(struct inode *inode, struct file *file) 11500d3b7a4SDavid Howells { 11600d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 117215804a9SDavid Howells struct afs_file *af; 11800d3b7a4SDavid Howells struct key *key; 119260a9803SDavid Howells int ret; 12000d3b7a4SDavid Howells 1213b6492dfSDavid Howells _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); 12200d3b7a4SDavid Howells 12300d3b7a4SDavid Howells key = afs_request_key(vnode->volume->cell); 12400d3b7a4SDavid Howells if (IS_ERR(key)) { 125215804a9SDavid Howells ret = PTR_ERR(key); 126215804a9SDavid Howells goto error; 127215804a9SDavid Howells } 128215804a9SDavid Howells 129215804a9SDavid Howells af = kzalloc(sizeof(*af), GFP_KERNEL); 130215804a9SDavid Howells if (!af) { 131215804a9SDavid Howells ret = -ENOMEM; 132215804a9SDavid Howells goto error_key; 13300d3b7a4SDavid Howells } 1344343d008SDavid Howells af->key = key; 13500d3b7a4SDavid Howells 136260a9803SDavid Howells ret = afs_validate(vnode, key); 137215804a9SDavid Howells if (ret < 0) 138215804a9SDavid Howells goto error_af; 139260a9803SDavid Howells 1404343d008SDavid Howells if (file->f_mode & FMODE_WRITE) { 1414343d008SDavid Howells ret = afs_cache_wb_key(vnode, af); 1424343d008SDavid Howells if (ret < 0) 1434343d008SDavid Howells goto error_af; 1444343d008SDavid Howells } 1454343d008SDavid Howells 1465a813276SDavid Howells if (file->f_flags & O_TRUNC) 1475a813276SDavid Howells set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 1485a813276SDavid Howells 149215804a9SDavid Howells file->private_data = af; 15000d3b7a4SDavid Howells _leave(" = 0"); 15100d3b7a4SDavid Howells return 0; 152215804a9SDavid Howells 153215804a9SDavid Howells error_af: 154215804a9SDavid Howells kfree(af); 155215804a9SDavid Howells error_key: 156215804a9SDavid Howells key_put(key); 157215804a9SDavid Howells error: 158215804a9SDavid Howells _leave(" = %d", ret); 159215804a9SDavid Howells return ret; 16000d3b7a4SDavid Howells } 16100d3b7a4SDavid Howells 16200d3b7a4SDavid Howells /* 16300d3b7a4SDavid Howells * release an AFS file or directory and discard its key 16400d3b7a4SDavid Howells */ 16500d3b7a4SDavid Howells int afs_release(struct inode *inode, struct file *file) 16600d3b7a4SDavid Howells { 16700d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 168215804a9SDavid Howells struct afs_file *af = file->private_data; 169a1b879eeSDavid Howells int ret = 0; 17000d3b7a4SDavid Howells 1713b6492dfSDavid Howells _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); 17200d3b7a4SDavid Howells 1735a813276SDavid Howells if ((file->f_mode & FMODE_WRITE)) 174a1b879eeSDavid Howells ret = vfs_fsync(file, 0); 1755a813276SDavid Howells 176215804a9SDavid Howells file->private_data = NULL; 1774343d008SDavid Howells if (af->wb) 1784343d008SDavid Howells afs_put_wb_key(af->wb); 179215804a9SDavid Howells key_put(af->key); 180215804a9SDavid Howells kfree(af); 1814343d008SDavid Howells afs_prune_wb_keys(vnode); 182a1b879eeSDavid Howells _leave(" = %d", ret); 183a1b879eeSDavid Howells return ret; 18400d3b7a4SDavid Howells } 18500d3b7a4SDavid Howells 186196ee9cdSDavid Howells /* 1875cbf0398SDavid Howells * Allocate a new read record. 188c4508464SDavid Howells */ 1895cbf0398SDavid Howells struct afs_read *afs_alloc_read(gfp_t gfp) 190c4508464SDavid Howells { 1915cbf0398SDavid Howells struct afs_read *req; 192c4508464SDavid Howells 1935cbf0398SDavid Howells req = kzalloc(sizeof(struct afs_read), gfp); 1945cbf0398SDavid Howells if (req) 1955cbf0398SDavid Howells refcount_set(&req->usage, 1); 196c4508464SDavid Howells 1975cbf0398SDavid Howells return req; 198c4508464SDavid Howells } 199c4508464SDavid Howells 200c4508464SDavid Howells /* 201196ee9cdSDavid Howells * Dispose of a ref to a read record. 202196ee9cdSDavid Howells */ 203196ee9cdSDavid Howells void afs_put_read(struct afs_read *req) 204196ee9cdSDavid Howells { 205f3ddee8dSDavid Howells if (refcount_dec_and_test(&req->usage)) { 206c4508464SDavid Howells if (req->cleanup) 207c4508464SDavid Howells req->cleanup(req); 208c69bf479SDavid Howells key_put(req->key); 209196ee9cdSDavid Howells kfree(req); 210196ee9cdSDavid Howells } 211196ee9cdSDavid Howells } 212196ee9cdSDavid Howells 213dc419184SDavid Howells static void afs_fetch_data_notify(struct afs_operation *op) 214dc419184SDavid Howells { 215dc419184SDavid Howells struct afs_read *req = op->fetch.req; 2165cbf0398SDavid Howells struct netfs_read_subrequest *subreq = req->subreq; 217dc419184SDavid Howells int error = op->error; 218dc419184SDavid Howells 219dc419184SDavid Howells if (error == -ECONNABORTED) 220dc419184SDavid Howells error = afs_abort_to_error(op->ac.abort_code); 221dc419184SDavid Howells req->error = error; 222dc419184SDavid Howells 2235cbf0398SDavid Howells if (subreq) { 2245cbf0398SDavid Howells __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); 2255cbf0398SDavid Howells netfs_subreq_terminated(subreq, error ?: req->actual_len, false); 2265cbf0398SDavid Howells req->subreq = NULL; 2275cbf0398SDavid Howells } else if (req->done) { 228dc419184SDavid Howells req->done(req); 229dc419184SDavid Howells } 2305cbf0398SDavid Howells } 231dc419184SDavid Howells 232e49c7b2fSDavid Howells static void afs_fetch_data_success(struct afs_operation *op) 233e49c7b2fSDavid Howells { 234e49c7b2fSDavid Howells struct afs_vnode *vnode = op->file[0].vnode; 235e49c7b2fSDavid Howells 236e49c7b2fSDavid Howells _enter("op=%08x", op->debug_id); 237e49c7b2fSDavid Howells afs_vnode_commit_status(op, &op->file[0]); 238e49c7b2fSDavid Howells afs_stat_v(vnode, n_fetches); 239e49c7b2fSDavid Howells atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes); 240dc419184SDavid Howells afs_fetch_data_notify(op); 241e49c7b2fSDavid Howells } 242e49c7b2fSDavid Howells 243e49c7b2fSDavid Howells static void afs_fetch_data_put(struct afs_operation *op) 244e49c7b2fSDavid Howells { 245c4508464SDavid Howells op->fetch.req->error = op->error; 246e49c7b2fSDavid Howells afs_put_read(op->fetch.req); 247e49c7b2fSDavid Howells } 248e49c7b2fSDavid Howells 249e49c7b2fSDavid Howells static const struct afs_operation_ops afs_fetch_data_operation = { 250e49c7b2fSDavid Howells .issue_afs_rpc = afs_fs_fetch_data, 251e49c7b2fSDavid Howells .issue_yfs_rpc = yfs_fs_fetch_data, 252e49c7b2fSDavid Howells .success = afs_fetch_data_success, 253728279a5SDavid Howells .aborted = afs_check_for_remote_deletion, 254dc419184SDavid Howells .failed = afs_fetch_data_notify, 255e49c7b2fSDavid Howells .put = afs_fetch_data_put, 256e49c7b2fSDavid Howells }; 257e49c7b2fSDavid Howells 2581da177e4SLinus Torvalds /* 259d2ddc776SDavid Howells * Fetch file data from the volume. 260d2ddc776SDavid Howells */ 261c69bf479SDavid Howells int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req) 262d2ddc776SDavid Howells { 263e49c7b2fSDavid Howells struct afs_operation *op; 264d2ddc776SDavid Howells 2653b6492dfSDavid Howells _enter("%s{%llx:%llu.%u},%x,,,", 266d2ddc776SDavid Howells vnode->volume->name, 267d2ddc776SDavid Howells vnode->fid.vid, 268d2ddc776SDavid Howells vnode->fid.vnode, 269d2ddc776SDavid Howells vnode->fid.unique, 270c69bf479SDavid Howells key_serial(req->key)); 271d2ddc776SDavid Howells 272c69bf479SDavid Howells op = afs_alloc_operation(req->key, vnode->volume); 2735cbf0398SDavid Howells if (IS_ERR(op)) { 2745cbf0398SDavid Howells if (req->subreq) 2755cbf0398SDavid Howells netfs_subreq_terminated(req->subreq, PTR_ERR(op), false); 276e49c7b2fSDavid Howells return PTR_ERR(op); 2775cbf0398SDavid Howells } 278a58823acSDavid Howells 279e49c7b2fSDavid Howells afs_op_set_vnode(op, 0, vnode); 280a58823acSDavid Howells 281e49c7b2fSDavid Howells op->fetch.req = afs_get_read(req); 282e49c7b2fSDavid Howells op->ops = &afs_fetch_data_operation; 283e49c7b2fSDavid Howells return afs_do_sync_operation(op); 284d2ddc776SDavid Howells } 285d2ddc776SDavid Howells 2865cbf0398SDavid Howells static void afs_req_issue_op(struct netfs_read_subrequest *subreq) 2871da177e4SLinus Torvalds { 2885cbf0398SDavid Howells struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode); 2895cbf0398SDavid Howells struct afs_read *fsreq; 2905cbf0398SDavid Howells 2915cbf0398SDavid Howells fsreq = afs_alloc_read(GFP_NOFS); 2925cbf0398SDavid Howells if (!fsreq) 2935cbf0398SDavid Howells return netfs_subreq_terminated(subreq, -ENOMEM, false); 2945cbf0398SDavid Howells 2955cbf0398SDavid Howells fsreq->subreq = subreq; 2965cbf0398SDavid Howells fsreq->pos = subreq->start + subreq->transferred; 2975cbf0398SDavid Howells fsreq->len = subreq->len - subreq->transferred; 298*345e1ae0SDavid Howells fsreq->key = key_get(subreq->rreq->netfs_priv); 2995cbf0398SDavid Howells fsreq->vnode = vnode; 3005cbf0398SDavid Howells fsreq->iter = &fsreq->def_iter; 3015cbf0398SDavid Howells 3025cbf0398SDavid Howells iov_iter_xarray(&fsreq->def_iter, READ, 3035cbf0398SDavid Howells &fsreq->vnode->vfs_inode.i_mapping->i_pages, 3045cbf0398SDavid Howells fsreq->pos, fsreq->len); 3055cbf0398SDavid Howells 3065cbf0398SDavid Howells afs_fetch_data(fsreq->vnode, fsreq); 307*345e1ae0SDavid Howells afs_put_read(fsreq); 3085cbf0398SDavid Howells } 3095cbf0398SDavid Howells 3105cbf0398SDavid Howells static int afs_symlink_readpage(struct page *page) 3115cbf0398SDavid Howells { 3125cbf0398SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 3135cbf0398SDavid Howells struct afs_read *fsreq; 3141da177e4SLinus Torvalds int ret; 3151da177e4SLinus Torvalds 3165cbf0398SDavid Howells fsreq = afs_alloc_read(GFP_NOFS); 3175cbf0398SDavid Howells if (!fsreq) 31891b467e0SDavid Howells return -ENOMEM; 31991b467e0SDavid Howells 3205cbf0398SDavid Howells fsreq->pos = page->index * PAGE_SIZE; 3215cbf0398SDavid Howells fsreq->len = PAGE_SIZE; 3225cbf0398SDavid Howells fsreq->vnode = vnode; 3235cbf0398SDavid Howells fsreq->iter = &fsreq->def_iter; 3245cbf0398SDavid Howells iov_iter_xarray(&fsreq->def_iter, READ, &page->mapping->i_pages, 3255cbf0398SDavid Howells fsreq->pos, fsreq->len); 32691b467e0SDavid Howells 3275cbf0398SDavid Howells ret = afs_fetch_data(fsreq->vnode, fsreq); 3285cbf0398SDavid Howells page_endio(page, false, ret); 32991b467e0SDavid Howells return ret; 33091b467e0SDavid Howells } 33191b467e0SDavid Howells 3325cbf0398SDavid Howells static void afs_init_rreq(struct netfs_read_request *rreq, struct file *file) 3331da177e4SLinus Torvalds { 3345cbf0398SDavid Howells rreq->netfs_priv = key_get(afs_file_key(file)); 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3373003bbd0SDavid Howells static bool afs_is_cache_enabled(struct inode *inode) 3383003bbd0SDavid Howells { 3393003bbd0SDavid Howells struct fscache_cookie *cookie = afs_vnode_cache(AFS_FS_I(inode)); 3403003bbd0SDavid Howells 3413003bbd0SDavid Howells return fscache_cookie_enabled(cookie) && !hlist_empty(&cookie->backing_objects); 3423003bbd0SDavid Howells } 3433003bbd0SDavid Howells 3445cbf0398SDavid Howells static int afs_begin_cache_operation(struct netfs_read_request *rreq) 3455cbf0398SDavid Howells { 3465cbf0398SDavid Howells struct afs_vnode *vnode = AFS_FS_I(rreq->inode); 3475cbf0398SDavid Howells 3485cbf0398SDavid Howells return fscache_begin_read_operation(rreq, afs_vnode_cache(vnode)); 34991b467e0SDavid Howells } 3509b3f26c9SDavid Howells 3513003bbd0SDavid Howells static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len, 3523003bbd0SDavid Howells struct page *page, void **_fsdata) 3533003bbd0SDavid Howells { 3543003bbd0SDavid Howells struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); 3553003bbd0SDavid Howells 3563003bbd0SDavid Howells return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? -ESTALE : 0; 3573003bbd0SDavid Howells } 3583003bbd0SDavid Howells 3595cbf0398SDavid Howells static void afs_priv_cleanup(struct address_space *mapping, void *netfs_priv) 3605cbf0398SDavid Howells { 3615cbf0398SDavid Howells key_put(netfs_priv); 3625cbf0398SDavid Howells } 3635cbf0398SDavid Howells 3643003bbd0SDavid Howells const struct netfs_read_request_ops afs_req_ops = { 3655cbf0398SDavid Howells .init_rreq = afs_init_rreq, 3663003bbd0SDavid Howells .is_cache_enabled = afs_is_cache_enabled, 3675cbf0398SDavid Howells .begin_cache_operation = afs_begin_cache_operation, 3683003bbd0SDavid Howells .check_write_begin = afs_check_write_begin, 3695cbf0398SDavid Howells .issue_op = afs_req_issue_op, 3705cbf0398SDavid Howells .cleanup = afs_priv_cleanup, 3715cbf0398SDavid Howells }; 3725cbf0398SDavid Howells 3735cbf0398SDavid Howells static int afs_readpage(struct file *file, struct page *page) 3745cbf0398SDavid Howells { 3755cbf0398SDavid Howells if (!file) 3765cbf0398SDavid Howells return afs_symlink_readpage(page); 3775cbf0398SDavid Howells 3785cbf0398SDavid Howells return netfs_readpage(file, page, &afs_req_ops, NULL); 3795cbf0398SDavid Howells } 3805cbf0398SDavid Howells 3815cbf0398SDavid Howells static void afs_readahead(struct readahead_control *ractl) 3825cbf0398SDavid Howells { 3835cbf0398SDavid Howells netfs_readahead(ractl, &afs_req_ops, NULL); 384ec26815aSDavid Howells } 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds /* 387f86726a6SDavid Howells * Adjust the dirty region of the page on truncation or full invalidation, 388f86726a6SDavid Howells * getting rid of the markers altogether if the region is entirely invalidated. 389f86726a6SDavid Howells */ 390f86726a6SDavid Howells static void afs_invalidate_dirty(struct page *page, unsigned int offset, 391f86726a6SDavid Howells unsigned int length) 392f86726a6SDavid Howells { 393f86726a6SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 394f86726a6SDavid Howells unsigned long priv; 395f86726a6SDavid Howells unsigned int f, t, end = offset + length; 396f86726a6SDavid Howells 397f86726a6SDavid Howells priv = page_private(page); 398f86726a6SDavid Howells 399f86726a6SDavid Howells /* we clean up only if the entire page is being invalidated */ 400f86726a6SDavid Howells if (offset == 0 && length == thp_size(page)) 401f86726a6SDavid Howells goto full_invalidate; 402f86726a6SDavid Howells 403f86726a6SDavid Howells /* If the page was dirtied by page_mkwrite(), the PTE stays writable 404f86726a6SDavid Howells * and we don't get another notification to tell us to expand it 405f86726a6SDavid Howells * again. 406f86726a6SDavid Howells */ 407f86726a6SDavid Howells if (afs_is_page_dirty_mmapped(priv)) 408f86726a6SDavid Howells return; 409f86726a6SDavid Howells 410f86726a6SDavid Howells /* We may need to shorten the dirty region */ 41167d78a6fSDavid Howells f = afs_page_dirty_from(page, priv); 41267d78a6fSDavid Howells t = afs_page_dirty_to(page, priv); 413f86726a6SDavid Howells 414f86726a6SDavid Howells if (t <= offset || f >= end) 415f86726a6SDavid Howells return; /* Doesn't overlap */ 416f86726a6SDavid Howells 417f86726a6SDavid Howells if (f < offset && t > end) 418f86726a6SDavid Howells return; /* Splits the dirty region - just absorb it */ 419f86726a6SDavid Howells 420f86726a6SDavid Howells if (f >= offset && t <= end) 421f86726a6SDavid Howells goto undirty; 422f86726a6SDavid Howells 423f86726a6SDavid Howells if (f < offset) 424f86726a6SDavid Howells t = offset; 425f86726a6SDavid Howells else 426f86726a6SDavid Howells f = end; 427f86726a6SDavid Howells if (f == t) 428f86726a6SDavid Howells goto undirty; 429f86726a6SDavid Howells 43067d78a6fSDavid Howells priv = afs_page_dirty(page, f, t); 431f86726a6SDavid Howells set_page_private(page, priv); 43267d78a6fSDavid Howells trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page); 433f86726a6SDavid Howells return; 434f86726a6SDavid Howells 435f86726a6SDavid Howells undirty: 43667d78a6fSDavid Howells trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page); 437f86726a6SDavid Howells clear_page_dirty_for_io(page); 438f86726a6SDavid Howells full_invalidate: 43967d78a6fSDavid Howells trace_afs_page_dirty(vnode, tracepoint_string("inval"), page); 440e87b03f5SDavid Howells detach_page_private(page); 441f86726a6SDavid Howells } 442f86726a6SDavid Howells 443f86726a6SDavid Howells /* 4449b3f26c9SDavid Howells * invalidate part or all of a page 4459b3f26c9SDavid Howells * - release a page and clean up its private data if offset is 0 (indicating 4469b3f26c9SDavid Howells * the entire page) 4479b3f26c9SDavid Howells */ 448d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset, 449d47992f8SLukas Czerner unsigned int length) 4509b3f26c9SDavid Howells { 451d47992f8SLukas Czerner _enter("{%lu},%u,%u", page->index, offset, length); 4529b3f26c9SDavid Howells 4539b3f26c9SDavid Howells BUG_ON(!PageLocked(page)); 4549b3f26c9SDavid Howells 455f86726a6SDavid Howells if (PagePrivate(page)) 456f86726a6SDavid Howells afs_invalidate_dirty(page, offset, length); 4579b3f26c9SDavid Howells 458630f5ddaSDavid Howells wait_on_page_fscache(page); 4599b3f26c9SDavid Howells _leave(""); 4609b3f26c9SDavid Howells } 4619b3f26c9SDavid Howells 4629b3f26c9SDavid Howells /* 4639b3f26c9SDavid Howells * release a page and clean up its private state if it's not busy 4649b3f26c9SDavid Howells * - return true if the page can now be released, false if not 4651da177e4SLinus Torvalds */ 466416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags) 4671da177e4SLinus Torvalds { 468416351f2SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 4691da177e4SLinus Torvalds 4703b6492dfSDavid Howells _enter("{{%llx:%llu}[%lu],%lx},%x", 471416351f2SDavid Howells vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, 472416351f2SDavid Howells gfp_flags); 4731da177e4SLinus Torvalds 4749b3f26c9SDavid Howells /* deny if page is being written to the cache and the caller hasn't 4759b3f26c9SDavid Howells * elected to wait */ 476630f5ddaSDavid Howells #ifdef CONFIG_AFS_FSCACHE 477630f5ddaSDavid Howells if (PageFsCache(page)) { 478630f5ddaSDavid Howells if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS)) 479630f5ddaSDavid Howells return false; 480630f5ddaSDavid Howells wait_on_page_fscache(page); 481630f5ddaSDavid Howells } 482630f5ddaSDavid Howells #endif 483630f5ddaSDavid Howells 4849b3f26c9SDavid Howells if (PagePrivate(page)) { 48567d78a6fSDavid Howells trace_afs_page_dirty(vnode, tracepoint_string("rel"), page); 486e87b03f5SDavid Howells detach_page_private(page); 4879b3f26c9SDavid Howells } 4889b3f26c9SDavid Howells 4899b3f26c9SDavid Howells /* indicate that the page can be released */ 4909b3f26c9SDavid Howells _leave(" = T"); 4919b3f26c9SDavid Howells return 1; 492ec26815aSDavid Howells } 4931cf7a151SDavid Howells 4941cf7a151SDavid Howells /* 4951cf7a151SDavid Howells * Handle setting up a memory mapping on an AFS file. 4961cf7a151SDavid Howells */ 4971cf7a151SDavid Howells static int afs_file_mmap(struct file *file, struct vm_area_struct *vma) 4981cf7a151SDavid Howells { 4991cf7a151SDavid Howells int ret; 5001cf7a151SDavid Howells 5011cf7a151SDavid Howells ret = generic_file_mmap(file, vma); 5021cf7a151SDavid Howells if (ret == 0) 5031cf7a151SDavid Howells vma->vm_ops = &afs_vm_ops; 5041cf7a151SDavid Howells return ret; 5051cf7a151SDavid Howells } 506