108e0e7c8SDavid Howells /* AFS filesystem file handling 21da177e4SLinus Torvalds * 308e0e7c8SDavid Howells * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/module.h> 141da177e4SLinus Torvalds #include <linux/init.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 161da177e4SLinus Torvalds #include <linux/fs.h> 171da177e4SLinus Torvalds #include <linux/pagemap.h> 181da177e4SLinus Torvalds #include "internal.h" 191da177e4SLinus Torvalds 20*416351f2SDavid Howells static int afs_readpage(struct file *file, struct page *page); 21*416351f2SDavid Howells static void afs_invalidatepage(struct page *page, unsigned long offset); 22*416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags); 231da177e4SLinus Torvalds 2400d3b7a4SDavid Howells const struct file_operations afs_file_operations = { 2500d3b7a4SDavid Howells .open = afs_open, 2600d3b7a4SDavid Howells .release = afs_release, 2700d3b7a4SDavid Howells .llseek = generic_file_llseek, 2800d3b7a4SDavid Howells .read = do_sync_read, 2900d3b7a4SDavid Howells .aio_read = generic_file_aio_read, 3000d3b7a4SDavid Howells .mmap = generic_file_readonly_mmap, 3100d3b7a4SDavid Howells .sendfile = generic_file_sendfile, 3200d3b7a4SDavid Howells }; 3300d3b7a4SDavid Howells 34754661f1SArjan van de Ven const struct inode_operations afs_file_inode_operations = { 35*416351f2SDavid Howells .getattr = afs_getattr, 3600d3b7a4SDavid Howells .permission = afs_permission, 371da177e4SLinus Torvalds }; 381da177e4SLinus Torvalds 39f5e54d6eSChristoph Hellwig const struct address_space_operations afs_fs_aops = { 40*416351f2SDavid Howells .readpage = afs_readpage, 411da177e4SLinus Torvalds .set_page_dirty = __set_page_dirty_nobuffers, 42*416351f2SDavid Howells .releasepage = afs_releasepage, 43*416351f2SDavid Howells .invalidatepage = afs_invalidatepage, 441da177e4SLinus Torvalds }; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds /* 4700d3b7a4SDavid Howells * open an AFS file or directory and attach a key to it 4800d3b7a4SDavid Howells */ 4900d3b7a4SDavid Howells int afs_open(struct inode *inode, struct file *file) 5000d3b7a4SDavid Howells { 5100d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 5200d3b7a4SDavid Howells struct key *key; 53260a9803SDavid Howells int ret; 5400d3b7a4SDavid Howells 55*416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 5600d3b7a4SDavid Howells 5700d3b7a4SDavid Howells key = afs_request_key(vnode->volume->cell); 5800d3b7a4SDavid Howells if (IS_ERR(key)) { 5900d3b7a4SDavid Howells _leave(" = %ld [key]", PTR_ERR(key)); 6000d3b7a4SDavid Howells return PTR_ERR(key); 6100d3b7a4SDavid Howells } 6200d3b7a4SDavid Howells 63260a9803SDavid Howells ret = afs_validate(vnode, key); 64260a9803SDavid Howells if (ret < 0) { 65260a9803SDavid Howells _leave(" = %d [val]", ret); 66260a9803SDavid Howells return ret; 67260a9803SDavid Howells } 68260a9803SDavid Howells 6900d3b7a4SDavid Howells file->private_data = key; 7000d3b7a4SDavid Howells _leave(" = 0"); 7100d3b7a4SDavid Howells return 0; 7200d3b7a4SDavid Howells } 7300d3b7a4SDavid Howells 7400d3b7a4SDavid Howells /* 7500d3b7a4SDavid Howells * release an AFS file or directory and discard its key 7600d3b7a4SDavid Howells */ 7700d3b7a4SDavid Howells int afs_release(struct inode *inode, struct file *file) 7800d3b7a4SDavid Howells { 7900d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 8000d3b7a4SDavid Howells 81*416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 8200d3b7a4SDavid Howells 8300d3b7a4SDavid Howells key_put(file->private_data); 8400d3b7a4SDavid Howells _leave(" = 0"); 8500d3b7a4SDavid Howells return 0; 8600d3b7a4SDavid Howells } 8700d3b7a4SDavid Howells 8800d3b7a4SDavid Howells /* 891da177e4SLinus Torvalds * deal with notification that a page was read from the cache 901da177e4SLinus Torvalds */ 911da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 92*416351f2SDavid Howells static void afs_readpage_read_complete(void *cookie_data, 931da177e4SLinus Torvalds struct page *page, 941da177e4SLinus Torvalds void *data, 951da177e4SLinus Torvalds int error) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds _enter("%p,%p,%p,%d", cookie_data, page, data, error); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds if (error) 1001da177e4SLinus Torvalds SetPageError(page); 1011da177e4SLinus Torvalds else 1021da177e4SLinus Torvalds SetPageUptodate(page); 1031da177e4SLinus Torvalds unlock_page(page); 1041da177e4SLinus Torvalds 105ec26815aSDavid Howells } 1061da177e4SLinus Torvalds #endif 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* 1091da177e4SLinus Torvalds * deal with notification that a page was written to the cache 1101da177e4SLinus Torvalds */ 1111da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 112*416351f2SDavid Howells static void afs_readpage_write_complete(void *cookie_data, 1131da177e4SLinus Torvalds struct page *page, 1141da177e4SLinus Torvalds void *data, 1151da177e4SLinus Torvalds int error) 1161da177e4SLinus Torvalds { 1171da177e4SLinus Torvalds _enter("%p,%p,%p,%d", cookie_data, page, data, error); 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds unlock_page(page); 120ec26815aSDavid Howells } 1211da177e4SLinus Torvalds #endif 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds /* 124*416351f2SDavid Howells * AFS read page from file, directory or symlink 1251da177e4SLinus Torvalds */ 126*416351f2SDavid Howells static int afs_readpage(struct file *file, struct page *page) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds struct afs_vnode *vnode; 1291da177e4SLinus Torvalds struct inode *inode; 13000d3b7a4SDavid Howells struct key *key; 13108e0e7c8SDavid Howells size_t len; 13208e0e7c8SDavid Howells off_t offset; 1331da177e4SLinus Torvalds int ret; 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds inode = page->mapping->host; 1361da177e4SLinus Torvalds 13700d3b7a4SDavid Howells ASSERT(file != NULL); 13800d3b7a4SDavid Howells key = file->private_data; 13900d3b7a4SDavid Howells ASSERT(key != NULL); 14000d3b7a4SDavid Howells 14100d3b7a4SDavid Howells _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds vnode = AFS_FS_I(inode); 1441da177e4SLinus Torvalds 145cd7619d6SMatt Mackall BUG_ON(!PageLocked(page)); 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds ret = -ESTALE; 14808e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1491da177e4SLinus Torvalds goto error; 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 1521da177e4SLinus Torvalds /* is it cached? */ 1531da177e4SLinus Torvalds ret = cachefs_read_or_alloc_page(vnode->cache, 1541da177e4SLinus Torvalds page, 1551da177e4SLinus Torvalds afs_file_readpage_read_complete, 1561da177e4SLinus Torvalds NULL, 1571da177e4SLinus Torvalds GFP_KERNEL); 1581da177e4SLinus Torvalds #else 1591da177e4SLinus Torvalds ret = -ENOBUFS; 1601da177e4SLinus Torvalds #endif 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds switch (ret) { 1631da177e4SLinus Torvalds /* read BIO submitted and wb-journal entry found */ 1641da177e4SLinus Torvalds case 1: 1651da177e4SLinus Torvalds BUG(); // TODO - handle wb-journal match 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* read BIO submitted (page in cache) */ 1681da177e4SLinus Torvalds case 0: 1691da177e4SLinus Torvalds break; 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* no page available in cache */ 1721da177e4SLinus Torvalds case -ENOBUFS: 1731da177e4SLinus Torvalds case -ENODATA: 1741da177e4SLinus Torvalds default: 17508e0e7c8SDavid Howells offset = page->index << PAGE_CACHE_SHIFT; 17608e0e7c8SDavid Howells len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds /* read the contents of the file from the server into the 1791da177e4SLinus Torvalds * page */ 18000d3b7a4SDavid Howells ret = afs_vnode_fetch_data(vnode, key, offset, len, page); 1811da177e4SLinus Torvalds if (ret < 0) { 1821da177e4SLinus Torvalds if (ret == -ENOENT) { 1831da177e4SLinus Torvalds _debug("got NOENT from server" 1841da177e4SLinus Torvalds " - marking file deleted and stale"); 18508e0e7c8SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1861da177e4SLinus Torvalds ret = -ESTALE; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 1891da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache, page); 1901da177e4SLinus Torvalds #endif 1911da177e4SLinus Torvalds goto error; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds SetPageUptodate(page); 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 1971da177e4SLinus Torvalds if (cachefs_write_page(vnode->cache, 1981da177e4SLinus Torvalds page, 1991da177e4SLinus Torvalds afs_file_readpage_write_complete, 2001da177e4SLinus Torvalds NULL, 2011da177e4SLinus Torvalds GFP_KERNEL) != 0 2021da177e4SLinus Torvalds ) { 2031da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache, page); 2041da177e4SLinus Torvalds unlock_page(page); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds #else 2071da177e4SLinus Torvalds unlock_page(page); 2081da177e4SLinus Torvalds #endif 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds _leave(" = 0"); 2121da177e4SLinus Torvalds return 0; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds error: 2151da177e4SLinus Torvalds SetPageError(page); 2161da177e4SLinus Torvalds unlock_page(page); 2171da177e4SLinus Torvalds _leave(" = %d", ret); 2181da177e4SLinus Torvalds return ret; 219ec26815aSDavid Howells } 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /* 2221da177e4SLinus Torvalds * invalidate part or all of a page 2231da177e4SLinus Torvalds */ 224*416351f2SDavid Howells static void afs_invalidatepage(struct page *page, unsigned long offset) 2251da177e4SLinus Torvalds { 2261da177e4SLinus Torvalds int ret = 1; 2271da177e4SLinus Torvalds 228*416351f2SDavid Howells kenter("{%lu},%lu", page->index, offset); 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds BUG_ON(!PageLocked(page)); 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds if (PagePrivate(page)) { 2331da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 2341da177e4SLinus Torvalds struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 2351da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache,page); 2361da177e4SLinus Torvalds #endif 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds /* We release buffers only if the entire page is being 2391da177e4SLinus Torvalds * invalidated. 2401da177e4SLinus Torvalds * The get_block cached value has been unconditionally 2411da177e4SLinus Torvalds * invalidated, so real IO is not possible anymore. 2421da177e4SLinus Torvalds */ 2431da177e4SLinus Torvalds if (offset == 0) { 2441da177e4SLinus Torvalds BUG_ON(!PageLocked(page)); 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds ret = 0; 2471da177e4SLinus Torvalds if (!PageWriteback(page)) 2481da177e4SLinus Torvalds ret = page->mapping->a_ops->releasepage(page, 2491da177e4SLinus Torvalds 0); 2502ff28e22SNeilBrown /* possibly should BUG_ON(!ret); - neilb */ 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds _leave(" = %d", ret); 255ec26815aSDavid Howells } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /* 2581da177e4SLinus Torvalds * release a page and cleanup its private data 2591da177e4SLinus Torvalds */ 260*416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags) 2611da177e4SLinus Torvalds { 262*416351f2SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 2631da177e4SLinus Torvalds 264*416351f2SDavid Howells _enter("{{%x:%u}[%lu],%lx},%x", 265*416351f2SDavid Howells vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, 266*416351f2SDavid Howells gfp_flags); 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds if (PagePrivate(page)) { 2694c21e2f2SHugh Dickins set_page_private(page, 0); 2701da177e4SLinus Torvalds ClearPagePrivate(page); 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds _leave(" = 0"); 2741da177e4SLinus Torvalds return 0; 275ec26815aSDavid Howells } 276