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/fs.h> 161da177e4SLinus Torvalds #include <linux/pagemap.h> 1731143d5dSDavid Howells #include <linux/writeback.h> 185a0e3ad6STejun Heo #include <linux/gfp.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); 2431143d5dSDavid Howells static int afs_launder_page(struct page *page); 251da177e4SLinus Torvalds 269b3f26c9SDavid Howells static int afs_readpages(struct file *filp, struct address_space *mapping, 279b3f26c9SDavid Howells struct list_head *pages, unsigned nr_pages); 289b3f26c9SDavid Howells 2900d3b7a4SDavid Howells const struct file_operations afs_file_operations = { 3000d3b7a4SDavid Howells .open = afs_open, 3100d3b7a4SDavid Howells .release = afs_release, 3200d3b7a4SDavid Howells .llseek = generic_file_llseek, 3300d3b7a4SDavid Howells .read = do_sync_read, 3431143d5dSDavid Howells .write = do_sync_write, 3500d3b7a4SDavid Howells .aio_read = generic_file_aio_read, 3631143d5dSDavid Howells .aio_write = afs_file_write, 3700d3b7a4SDavid Howells .mmap = generic_file_readonly_mmap, 385ffc4ef4SJens Axboe .splice_read = generic_file_splice_read, 3931143d5dSDavid Howells .fsync = afs_fsync, 40e8d6c554SDavid Howells .lock = afs_lock, 41e8d6c554SDavid Howells .flock = afs_flock, 4200d3b7a4SDavid Howells }; 4300d3b7a4SDavid Howells 44754661f1SArjan van de Ven const struct inode_operations afs_file_inode_operations = { 45416351f2SDavid Howells .getattr = afs_getattr, 4631143d5dSDavid Howells .setattr = afs_setattr, 4700d3b7a4SDavid Howells .permission = afs_permission, 481da177e4SLinus Torvalds }; 491da177e4SLinus Torvalds 50f5e54d6eSChristoph Hellwig const struct address_space_operations afs_fs_aops = { 51416351f2SDavid Howells .readpage = afs_readpage, 529b3f26c9SDavid Howells .readpages = afs_readpages, 5331143d5dSDavid Howells .set_page_dirty = afs_set_page_dirty, 5431143d5dSDavid Howells .launder_page = afs_launder_page, 55416351f2SDavid Howells .releasepage = afs_releasepage, 56416351f2SDavid Howells .invalidatepage = afs_invalidatepage, 5715b4650eSNick Piggin .write_begin = afs_write_begin, 5815b4650eSNick Piggin .write_end = afs_write_end, 5931143d5dSDavid Howells .writepage = afs_writepage, 6031143d5dSDavid Howells .writepages = afs_writepages, 611da177e4SLinus Torvalds }; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 6400d3b7a4SDavid Howells * open an AFS file or directory and attach a key to it 6500d3b7a4SDavid Howells */ 6600d3b7a4SDavid Howells int afs_open(struct inode *inode, struct file *file) 6700d3b7a4SDavid Howells { 6800d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 6900d3b7a4SDavid Howells struct key *key; 70260a9803SDavid Howells int ret; 7100d3b7a4SDavid Howells 72416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 7300d3b7a4SDavid Howells 7400d3b7a4SDavid Howells key = afs_request_key(vnode->volume->cell); 7500d3b7a4SDavid Howells if (IS_ERR(key)) { 7600d3b7a4SDavid Howells _leave(" = %ld [key]", PTR_ERR(key)); 7700d3b7a4SDavid Howells return PTR_ERR(key); 7800d3b7a4SDavid Howells } 7900d3b7a4SDavid Howells 80260a9803SDavid Howells ret = afs_validate(vnode, key); 81260a9803SDavid Howells if (ret < 0) { 82260a9803SDavid Howells _leave(" = %d [val]", ret); 83260a9803SDavid Howells return ret; 84260a9803SDavid Howells } 85260a9803SDavid Howells 8600d3b7a4SDavid Howells file->private_data = key; 8700d3b7a4SDavid Howells _leave(" = 0"); 8800d3b7a4SDavid Howells return 0; 8900d3b7a4SDavid Howells } 9000d3b7a4SDavid Howells 9100d3b7a4SDavid Howells /* 9200d3b7a4SDavid Howells * release an AFS file or directory and discard its key 9300d3b7a4SDavid Howells */ 9400d3b7a4SDavid Howells int afs_release(struct inode *inode, struct file *file) 9500d3b7a4SDavid Howells { 9600d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 9700d3b7a4SDavid Howells 98416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 9900d3b7a4SDavid Howells 10000d3b7a4SDavid Howells key_put(file->private_data); 10100d3b7a4SDavid Howells _leave(" = 0"); 10200d3b7a4SDavid Howells return 0; 10300d3b7a4SDavid Howells } 10400d3b7a4SDavid Howells 1056566abdbSMatt Kraai #ifdef CONFIG_AFS_FSCACHE 10600d3b7a4SDavid Howells /* 1071da177e4SLinus Torvalds * deal with notification that a page was read from the cache 1081da177e4SLinus Torvalds */ 1099b3f26c9SDavid Howells static void afs_file_readpage_read_complete(struct page *page, 1101da177e4SLinus Torvalds void *data, 1111da177e4SLinus Torvalds int error) 1121da177e4SLinus Torvalds { 1139b3f26c9SDavid Howells _enter("%p,%p,%d", page, data, error); 1141da177e4SLinus Torvalds 1159b3f26c9SDavid Howells /* if the read completes with an error, we just unlock the page and let 1169b3f26c9SDavid Howells * the VM reissue the readpage */ 1179b3f26c9SDavid Howells if (!error) 1181da177e4SLinus Torvalds SetPageUptodate(page); 1191da177e4SLinus Torvalds unlock_page(page); 120ec26815aSDavid Howells } 1216566abdbSMatt Kraai #endif 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds /* 124f6d335c0SAl Viro * read page from file, directory or symlink, given a key to use 1251da177e4SLinus Torvalds */ 126f6d335c0SAl Viro int afs_page_filler(void *data, struct page *page) 1271da177e4SLinus Torvalds { 128f6d335c0SAl Viro struct inode *inode = page->mapping->host; 129f6d335c0SAl Viro struct afs_vnode *vnode = AFS_FS_I(inode); 130f6d335c0SAl Viro struct key *key = data; 13108e0e7c8SDavid Howells size_t len; 13208e0e7c8SDavid Howells off_t offset; 1331da177e4SLinus Torvalds int ret; 1341da177e4SLinus Torvalds 13500d3b7a4SDavid Howells _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); 1361da177e4SLinus Torvalds 137cd7619d6SMatt Mackall BUG_ON(!PageLocked(page)); 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds ret = -ESTALE; 14008e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1411da177e4SLinus Torvalds goto error; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds /* is it cached? */ 1449b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 1459b3f26c9SDavid Howells ret = fscache_read_or_alloc_page(vnode->cache, 1461da177e4SLinus Torvalds page, 1471da177e4SLinus Torvalds afs_file_readpage_read_complete, 1481da177e4SLinus Torvalds NULL, 1491da177e4SLinus Torvalds GFP_KERNEL); 1501da177e4SLinus Torvalds #else 1511da177e4SLinus Torvalds ret = -ENOBUFS; 1521da177e4SLinus Torvalds #endif 1531da177e4SLinus Torvalds switch (ret) { 1541da177e4SLinus Torvalds /* read BIO submitted (page in cache) */ 1551da177e4SLinus Torvalds case 0: 1561da177e4SLinus Torvalds break; 1571da177e4SLinus Torvalds 1589b3f26c9SDavid Howells /* page not yet cached */ 1591da177e4SLinus Torvalds case -ENODATA: 1609b3f26c9SDavid Howells _debug("cache said ENODATA"); 1619b3f26c9SDavid Howells goto go_on; 1629b3f26c9SDavid Howells 1639b3f26c9SDavid Howells /* page will not be cached */ 1649b3f26c9SDavid Howells case -ENOBUFS: 1659b3f26c9SDavid Howells _debug("cache said ENOBUFS"); 1661da177e4SLinus Torvalds default: 1679b3f26c9SDavid Howells go_on: 16808e0e7c8SDavid Howells offset = page->index << PAGE_CACHE_SHIFT; 16908e0e7c8SDavid Howells len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds /* read the contents of the file from the server into the 1721da177e4SLinus Torvalds * page */ 17300d3b7a4SDavid Howells ret = afs_vnode_fetch_data(vnode, key, offset, len, page); 1741da177e4SLinus Torvalds if (ret < 0) { 1751da177e4SLinus Torvalds if (ret == -ENOENT) { 1761da177e4SLinus Torvalds _debug("got NOENT from server" 1771da177e4SLinus Torvalds " - marking file deleted and stale"); 17808e0e7c8SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1791da177e4SLinus Torvalds ret = -ESTALE; 1801da177e4SLinus Torvalds } 1819b3f26c9SDavid Howells 1829b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 1839b3f26c9SDavid Howells fscache_uncache_page(vnode->cache, page); 1841da177e4SLinus Torvalds #endif 1859b3f26c9SDavid Howells BUG_ON(PageFsCache(page)); 1861da177e4SLinus Torvalds goto error; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds SetPageUptodate(page); 1901da177e4SLinus Torvalds 1919b3f26c9SDavid Howells /* send the page to the cache */ 1929b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 1939b3f26c9SDavid Howells if (PageFsCache(page) && 1949b3f26c9SDavid Howells fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) { 1959b3f26c9SDavid Howells fscache_uncache_page(vnode->cache, page); 1969b3f26c9SDavid Howells BUG_ON(PageFsCache(page)); 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds #endif 1999b3f26c9SDavid Howells unlock_page(page); 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds _leave(" = 0"); 2031da177e4SLinus Torvalds return 0; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds error: 2061da177e4SLinus Torvalds SetPageError(page); 2071da177e4SLinus Torvalds unlock_page(page); 2081da177e4SLinus Torvalds _leave(" = %d", ret); 2091da177e4SLinus Torvalds return ret; 210ec26815aSDavid Howells } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* 213f6d335c0SAl Viro * read page from file, directory or symlink, given a file to nominate the key 214f6d335c0SAl Viro * to be used 215f6d335c0SAl Viro */ 216f6d335c0SAl Viro static int afs_readpage(struct file *file, struct page *page) 217f6d335c0SAl Viro { 218f6d335c0SAl Viro struct key *key; 219f6d335c0SAl Viro int ret; 220f6d335c0SAl Viro 221f6d335c0SAl Viro if (file) { 222f6d335c0SAl Viro key = file->private_data; 223f6d335c0SAl Viro ASSERT(key != NULL); 224f6d335c0SAl Viro ret = afs_page_filler(key, page); 225f6d335c0SAl Viro } else { 226f6d335c0SAl Viro struct inode *inode = page->mapping->host; 227f6d335c0SAl Viro key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell); 228f6d335c0SAl Viro if (IS_ERR(key)) { 229f6d335c0SAl Viro ret = PTR_ERR(key); 230f6d335c0SAl Viro } else { 231f6d335c0SAl Viro ret = afs_page_filler(key, page); 232f6d335c0SAl Viro key_put(key); 233f6d335c0SAl Viro } 234f6d335c0SAl Viro } 235f6d335c0SAl Viro return ret; 236f6d335c0SAl Viro } 237f6d335c0SAl Viro 238f6d335c0SAl Viro /* 2399b3f26c9SDavid Howells * read a set of pages 2401da177e4SLinus Torvalds */ 2419b3f26c9SDavid Howells static int afs_readpages(struct file *file, struct address_space *mapping, 2429b3f26c9SDavid Howells struct list_head *pages, unsigned nr_pages) 2431da177e4SLinus Torvalds { 244f6d335c0SAl Viro struct key *key = file->private_data; 2459b3f26c9SDavid Howells struct afs_vnode *vnode; 2469b3f26c9SDavid Howells int ret = 0; 2471da177e4SLinus Torvalds 248f6d335c0SAl Viro _enter("{%d},{%lu},,%d", 249f6d335c0SAl Viro key_serial(key), mapping->host->i_ino, nr_pages); 250f6d335c0SAl Viro 251f6d335c0SAl Viro ASSERT(key != NULL); 2521da177e4SLinus Torvalds 2539b3f26c9SDavid Howells vnode = AFS_FS_I(mapping->host); 254*ad2a8e60SDan Carpenter if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 2559b3f26c9SDavid Howells _leave(" = -ESTALE"); 2569b3f26c9SDavid Howells return -ESTALE; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2599b3f26c9SDavid Howells /* attempt to read as many of the pages as possible */ 2609b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 2619b3f26c9SDavid Howells ret = fscache_read_or_alloc_pages(vnode->cache, 2629b3f26c9SDavid Howells mapping, 2639b3f26c9SDavid Howells pages, 2649b3f26c9SDavid Howells &nr_pages, 2659b3f26c9SDavid Howells afs_file_readpage_read_complete, 2669b3f26c9SDavid Howells NULL, 2679b3f26c9SDavid Howells mapping_gfp_mask(mapping)); 2689b3f26c9SDavid Howells #else 2699b3f26c9SDavid Howells ret = -ENOBUFS; 2709b3f26c9SDavid Howells #endif 2719b3f26c9SDavid Howells 2729b3f26c9SDavid Howells switch (ret) { 2739b3f26c9SDavid Howells /* all pages are being read from the cache */ 2749b3f26c9SDavid Howells case 0: 2759b3f26c9SDavid Howells BUG_ON(!list_empty(pages)); 2769b3f26c9SDavid Howells BUG_ON(nr_pages != 0); 2779b3f26c9SDavid Howells _leave(" = 0 [reading all]"); 2789b3f26c9SDavid Howells return 0; 2799b3f26c9SDavid Howells 2809b3f26c9SDavid Howells /* there were pages that couldn't be read from the cache */ 2819b3f26c9SDavid Howells case -ENODATA: 2829b3f26c9SDavid Howells case -ENOBUFS: 2839b3f26c9SDavid Howells break; 2849b3f26c9SDavid Howells 2859b3f26c9SDavid Howells /* other error */ 2869b3f26c9SDavid Howells default: 2871da177e4SLinus Torvalds _leave(" = %d", ret); 2889b3f26c9SDavid Howells return ret; 2899b3f26c9SDavid Howells } 2909b3f26c9SDavid Howells 2919b3f26c9SDavid Howells /* load the missing pages from the network */ 292f6d335c0SAl Viro ret = read_cache_pages(mapping, pages, afs_page_filler, key); 2939b3f26c9SDavid Howells 2949b3f26c9SDavid Howells _leave(" = %d [netting]", ret); 2959b3f26c9SDavid Howells return ret; 296ec26815aSDavid Howells } 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds /* 29931143d5dSDavid Howells * write back a dirty page 30031143d5dSDavid Howells */ 30131143d5dSDavid Howells static int afs_launder_page(struct page *page) 30231143d5dSDavid Howells { 30331143d5dSDavid Howells _enter("{%lu}", page->index); 30431143d5dSDavid Howells 30531143d5dSDavid Howells return 0; 30631143d5dSDavid Howells } 30731143d5dSDavid Howells 30831143d5dSDavid Howells /* 3099b3f26c9SDavid Howells * invalidate part or all of a page 3109b3f26c9SDavid Howells * - release a page and clean up its private data if offset is 0 (indicating 3119b3f26c9SDavid Howells * the entire page) 3129b3f26c9SDavid Howells */ 3139b3f26c9SDavid Howells static void afs_invalidatepage(struct page *page, unsigned long offset) 3149b3f26c9SDavid Howells { 3159b3f26c9SDavid Howells struct afs_writeback *wb = (struct afs_writeback *) page_private(page); 3169b3f26c9SDavid Howells 3179b3f26c9SDavid Howells _enter("{%lu},%lu", page->index, offset); 3189b3f26c9SDavid Howells 3199b3f26c9SDavid Howells BUG_ON(!PageLocked(page)); 3209b3f26c9SDavid Howells 3219b3f26c9SDavid Howells /* we clean up only if the entire page is being invalidated */ 3229b3f26c9SDavid Howells if (offset == 0) { 3239b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 3249b3f26c9SDavid Howells if (PageFsCache(page)) { 3259b3f26c9SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 3269b3f26c9SDavid Howells fscache_wait_on_page_write(vnode->cache, page); 3279b3f26c9SDavid Howells fscache_uncache_page(vnode->cache, page); 3289b3f26c9SDavid Howells } 3299b3f26c9SDavid Howells #endif 3309b3f26c9SDavid Howells 3319b3f26c9SDavid Howells if (PagePrivate(page)) { 3329b3f26c9SDavid Howells if (wb && !PageWriteback(page)) { 3339b3f26c9SDavid Howells set_page_private(page, 0); 3349b3f26c9SDavid Howells afs_put_writeback(wb); 3359b3f26c9SDavid Howells } 3369b3f26c9SDavid Howells 3379b3f26c9SDavid Howells if (!page_private(page)) 3389b3f26c9SDavid Howells ClearPagePrivate(page); 3399b3f26c9SDavid Howells } 3409b3f26c9SDavid Howells } 3419b3f26c9SDavid Howells 3429b3f26c9SDavid Howells _leave(""); 3439b3f26c9SDavid Howells } 3449b3f26c9SDavid Howells 3459b3f26c9SDavid Howells /* 3469b3f26c9SDavid Howells * release a page and clean up its private state if it's not busy 3479b3f26c9SDavid Howells * - return true if the page can now be released, false if not 3481da177e4SLinus Torvalds */ 349416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags) 3501da177e4SLinus Torvalds { 3519b3f26c9SDavid Howells struct afs_writeback *wb = (struct afs_writeback *) page_private(page); 352416351f2SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 3531da177e4SLinus Torvalds 354416351f2SDavid Howells _enter("{{%x:%u}[%lu],%lx},%x", 355416351f2SDavid Howells vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, 356416351f2SDavid Howells gfp_flags); 3571da177e4SLinus Torvalds 3589b3f26c9SDavid Howells /* deny if page is being written to the cache and the caller hasn't 3599b3f26c9SDavid Howells * elected to wait */ 3609b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 361201a1542SDavid Howells if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { 3629b3f26c9SDavid Howells _leave(" = F [cache busy]"); 3639b3f26c9SDavid Howells return 0; 3649b3f26c9SDavid Howells } 3659b3f26c9SDavid Howells #endif 3669b3f26c9SDavid Howells 3679b3f26c9SDavid Howells if (PagePrivate(page)) { 3689b3f26c9SDavid Howells if (wb) { 3699b3f26c9SDavid Howells set_page_private(page, 0); 3709b3f26c9SDavid Howells afs_put_writeback(wb); 3719b3f26c9SDavid Howells } 3729b3f26c9SDavid Howells ClearPagePrivate(page); 3739b3f26c9SDavid Howells } 3749b3f26c9SDavid Howells 3759b3f26c9SDavid Howells /* indicate that the page can be released */ 3769b3f26c9SDavid Howells _leave(" = T"); 3779b3f26c9SDavid Howells return 1; 378ec26815aSDavid Howells } 379