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> 18*31143d5dSDavid Howells #include <linux/writeback.h> 191da177e4SLinus Torvalds #include "internal.h" 201da177e4SLinus Torvalds 21416351f2SDavid Howells static int afs_readpage(struct file *file, struct page *page); 22416351f2SDavid Howells static void afs_invalidatepage(struct page *page, unsigned long offset); 23416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags); 24*31143d5dSDavid Howells static int afs_launder_page(struct page *page); 251da177e4SLinus Torvalds 2600d3b7a4SDavid Howells const struct file_operations afs_file_operations = { 2700d3b7a4SDavid Howells .open = afs_open, 2800d3b7a4SDavid Howells .release = afs_release, 2900d3b7a4SDavid Howells .llseek = generic_file_llseek, 3000d3b7a4SDavid Howells .read = do_sync_read, 31*31143d5dSDavid Howells .write = do_sync_write, 3200d3b7a4SDavid Howells .aio_read = generic_file_aio_read, 33*31143d5dSDavid Howells .aio_write = afs_file_write, 3400d3b7a4SDavid Howells .mmap = generic_file_readonly_mmap, 3500d3b7a4SDavid Howells .sendfile = generic_file_sendfile, 36*31143d5dSDavid Howells .fsync = afs_fsync, 3700d3b7a4SDavid Howells }; 3800d3b7a4SDavid Howells 39754661f1SArjan van de Ven const struct inode_operations afs_file_inode_operations = { 40416351f2SDavid Howells .getattr = afs_getattr, 41*31143d5dSDavid Howells .setattr = afs_setattr, 4200d3b7a4SDavid Howells .permission = afs_permission, 431da177e4SLinus Torvalds }; 441da177e4SLinus Torvalds 45f5e54d6eSChristoph Hellwig const struct address_space_operations afs_fs_aops = { 46416351f2SDavid Howells .readpage = afs_readpage, 47*31143d5dSDavid Howells .set_page_dirty = afs_set_page_dirty, 48*31143d5dSDavid Howells .launder_page = afs_launder_page, 49416351f2SDavid Howells .releasepage = afs_releasepage, 50416351f2SDavid Howells .invalidatepage = afs_invalidatepage, 51*31143d5dSDavid Howells .prepare_write = afs_prepare_write, 52*31143d5dSDavid Howells .commit_write = afs_commit_write, 53*31143d5dSDavid Howells .writepage = afs_writepage, 54*31143d5dSDavid Howells .writepages = afs_writepages, 551da177e4SLinus Torvalds }; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 5800d3b7a4SDavid Howells * open an AFS file or directory and attach a key to it 5900d3b7a4SDavid Howells */ 6000d3b7a4SDavid Howells int afs_open(struct inode *inode, struct file *file) 6100d3b7a4SDavid Howells { 6200d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 6300d3b7a4SDavid Howells struct key *key; 64260a9803SDavid Howells int ret; 6500d3b7a4SDavid Howells 66416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 6700d3b7a4SDavid Howells 6800d3b7a4SDavid Howells key = afs_request_key(vnode->volume->cell); 6900d3b7a4SDavid Howells if (IS_ERR(key)) { 7000d3b7a4SDavid Howells _leave(" = %ld [key]", PTR_ERR(key)); 7100d3b7a4SDavid Howells return PTR_ERR(key); 7200d3b7a4SDavid Howells } 7300d3b7a4SDavid Howells 74260a9803SDavid Howells ret = afs_validate(vnode, key); 75260a9803SDavid Howells if (ret < 0) { 76260a9803SDavid Howells _leave(" = %d [val]", ret); 77260a9803SDavid Howells return ret; 78260a9803SDavid Howells } 79260a9803SDavid Howells 8000d3b7a4SDavid Howells file->private_data = key; 8100d3b7a4SDavid Howells _leave(" = 0"); 8200d3b7a4SDavid Howells return 0; 8300d3b7a4SDavid Howells } 8400d3b7a4SDavid Howells 8500d3b7a4SDavid Howells /* 8600d3b7a4SDavid Howells * release an AFS file or directory and discard its key 8700d3b7a4SDavid Howells */ 8800d3b7a4SDavid Howells int afs_release(struct inode *inode, struct file *file) 8900d3b7a4SDavid Howells { 9000d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 9100d3b7a4SDavid Howells 92416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 9300d3b7a4SDavid Howells 9400d3b7a4SDavid Howells key_put(file->private_data); 9500d3b7a4SDavid Howells _leave(" = 0"); 9600d3b7a4SDavid Howells return 0; 9700d3b7a4SDavid Howells } 9800d3b7a4SDavid Howells 9900d3b7a4SDavid Howells /* 1001da177e4SLinus Torvalds * deal with notification that a page was read from the cache 1011da177e4SLinus Torvalds */ 1021da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 103416351f2SDavid Howells static void afs_readpage_read_complete(void *cookie_data, 1041da177e4SLinus Torvalds struct page *page, 1051da177e4SLinus Torvalds void *data, 1061da177e4SLinus Torvalds int error) 1071da177e4SLinus Torvalds { 1081da177e4SLinus Torvalds _enter("%p,%p,%p,%d", cookie_data, page, data, error); 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds if (error) 1111da177e4SLinus Torvalds SetPageError(page); 1121da177e4SLinus Torvalds else 1131da177e4SLinus Torvalds SetPageUptodate(page); 1141da177e4SLinus Torvalds unlock_page(page); 1151da177e4SLinus Torvalds 116ec26815aSDavid Howells } 1171da177e4SLinus Torvalds #endif 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /* 1201da177e4SLinus Torvalds * deal with notification that a page was written to the cache 1211da177e4SLinus Torvalds */ 1221da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 123416351f2SDavid Howells static void afs_readpage_write_complete(void *cookie_data, 1241da177e4SLinus Torvalds struct page *page, 1251da177e4SLinus Torvalds void *data, 1261da177e4SLinus Torvalds int error) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds _enter("%p,%p,%p,%d", cookie_data, page, data, error); 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds unlock_page(page); 131ec26815aSDavid Howells } 1321da177e4SLinus Torvalds #endif 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds /* 135416351f2SDavid Howells * AFS read page from file, directory or symlink 1361da177e4SLinus Torvalds */ 137416351f2SDavid Howells static int afs_readpage(struct file *file, struct page *page) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds struct afs_vnode *vnode; 1401da177e4SLinus Torvalds struct inode *inode; 14100d3b7a4SDavid Howells struct key *key; 14208e0e7c8SDavid Howells size_t len; 14308e0e7c8SDavid Howells off_t offset; 1441da177e4SLinus Torvalds int ret; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds inode = page->mapping->host; 1471da177e4SLinus Torvalds 14800d3b7a4SDavid Howells ASSERT(file != NULL); 14900d3b7a4SDavid Howells key = file->private_data; 15000d3b7a4SDavid Howells ASSERT(key != NULL); 15100d3b7a4SDavid Howells 15200d3b7a4SDavid Howells _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds vnode = AFS_FS_I(inode); 1551da177e4SLinus Torvalds 156cd7619d6SMatt Mackall BUG_ON(!PageLocked(page)); 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds ret = -ESTALE; 15908e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1601da177e4SLinus Torvalds goto error; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 1631da177e4SLinus Torvalds /* is it cached? */ 1641da177e4SLinus Torvalds ret = cachefs_read_or_alloc_page(vnode->cache, 1651da177e4SLinus Torvalds page, 1661da177e4SLinus Torvalds afs_file_readpage_read_complete, 1671da177e4SLinus Torvalds NULL, 1681da177e4SLinus Torvalds GFP_KERNEL); 1691da177e4SLinus Torvalds #else 1701da177e4SLinus Torvalds ret = -ENOBUFS; 1711da177e4SLinus Torvalds #endif 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds switch (ret) { 1741da177e4SLinus Torvalds /* read BIO submitted and wb-journal entry found */ 1751da177e4SLinus Torvalds case 1: 1761da177e4SLinus Torvalds BUG(); // TODO - handle wb-journal match 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds /* read BIO submitted (page in cache) */ 1791da177e4SLinus Torvalds case 0: 1801da177e4SLinus Torvalds break; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds /* no page available in cache */ 1831da177e4SLinus Torvalds case -ENOBUFS: 1841da177e4SLinus Torvalds case -ENODATA: 1851da177e4SLinus Torvalds default: 18608e0e7c8SDavid Howells offset = page->index << PAGE_CACHE_SHIFT; 18708e0e7c8SDavid Howells len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds /* read the contents of the file from the server into the 1901da177e4SLinus Torvalds * page */ 19100d3b7a4SDavid Howells ret = afs_vnode_fetch_data(vnode, key, offset, len, page); 1921da177e4SLinus Torvalds if (ret < 0) { 1931da177e4SLinus Torvalds if (ret == -ENOENT) { 1941da177e4SLinus Torvalds _debug("got NOENT from server" 1951da177e4SLinus Torvalds " - marking file deleted and stale"); 19608e0e7c8SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1971da177e4SLinus Torvalds ret = -ESTALE; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 2001da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache, page); 2011da177e4SLinus Torvalds #endif 2021da177e4SLinus Torvalds goto error; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds SetPageUptodate(page); 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 2081da177e4SLinus Torvalds if (cachefs_write_page(vnode->cache, 2091da177e4SLinus Torvalds page, 2101da177e4SLinus Torvalds afs_file_readpage_write_complete, 2111da177e4SLinus Torvalds NULL, 2121da177e4SLinus Torvalds GFP_KERNEL) != 0 2131da177e4SLinus Torvalds ) { 2141da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache, page); 2151da177e4SLinus Torvalds unlock_page(page); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds #else 2181da177e4SLinus Torvalds unlock_page(page); 2191da177e4SLinus Torvalds #endif 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds _leave(" = 0"); 2231da177e4SLinus Torvalds return 0; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds error: 2261da177e4SLinus Torvalds SetPageError(page); 2271da177e4SLinus Torvalds unlock_page(page); 2281da177e4SLinus Torvalds _leave(" = %d", ret); 2291da177e4SLinus Torvalds return ret; 230ec26815aSDavid Howells } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds /* 2331da177e4SLinus Torvalds * invalidate part or all of a page 2341da177e4SLinus Torvalds */ 235416351f2SDavid Howells static void afs_invalidatepage(struct page *page, unsigned long offset) 2361da177e4SLinus Torvalds { 2371da177e4SLinus Torvalds int ret = 1; 2381da177e4SLinus Torvalds 239416351f2SDavid Howells kenter("{%lu},%lu", page->index, offset); 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds BUG_ON(!PageLocked(page)); 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds if (PagePrivate(page)) { 2441da177e4SLinus Torvalds /* We release buffers only if the entire page is being 2451da177e4SLinus Torvalds * invalidated. 2461da177e4SLinus Torvalds * The get_block cached value has been unconditionally 2471da177e4SLinus Torvalds * invalidated, so real IO is not possible anymore. 2481da177e4SLinus Torvalds */ 2491da177e4SLinus Torvalds if (offset == 0) { 2501da177e4SLinus Torvalds BUG_ON(!PageLocked(page)); 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds ret = 0; 2531da177e4SLinus Torvalds if (!PageWriteback(page)) 2541da177e4SLinus Torvalds ret = page->mapping->a_ops->releasepage(page, 2551da177e4SLinus Torvalds 0); 2562ff28e22SNeilBrown /* possibly should BUG_ON(!ret); - neilb */ 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds _leave(" = %d", ret); 261ec26815aSDavid Howells } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds /* 264*31143d5dSDavid Howells * write back a dirty page 265*31143d5dSDavid Howells */ 266*31143d5dSDavid Howells static int afs_launder_page(struct page *page) 267*31143d5dSDavid Howells { 268*31143d5dSDavid Howells _enter("{%lu}", page->index); 269*31143d5dSDavid Howells 270*31143d5dSDavid Howells return 0; 271*31143d5dSDavid Howells } 272*31143d5dSDavid Howells 273*31143d5dSDavid Howells /* 2741da177e4SLinus Torvalds * release a page and cleanup its private data 2751da177e4SLinus Torvalds */ 276416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags) 2771da177e4SLinus Torvalds { 278416351f2SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 279*31143d5dSDavid Howells struct afs_writeback *wb; 2801da177e4SLinus Torvalds 281416351f2SDavid Howells _enter("{{%x:%u}[%lu],%lx},%x", 282416351f2SDavid Howells vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, 283416351f2SDavid Howells gfp_flags); 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds if (PagePrivate(page)) { 286*31143d5dSDavid Howells wb = (struct afs_writeback *) page_private(page); 287*31143d5dSDavid Howells ASSERT(wb != NULL); 2884c21e2f2SHugh Dickins set_page_private(page, 0); 2891da177e4SLinus Torvalds ClearPagePrivate(page); 290*31143d5dSDavid Howells afs_put_writeback(wb); 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds _leave(" = 0"); 2941da177e4SLinus Torvalds return 0; 295ec26815aSDavid Howells } 296