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); 22*d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset, 23*d47992f8SLukas Czerner unsigned int length); 24416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags); 2531143d5dSDavid Howells static int afs_launder_page(struct page *page); 261da177e4SLinus Torvalds 279b3f26c9SDavid Howells static int afs_readpages(struct file *filp, struct address_space *mapping, 289b3f26c9SDavid Howells struct list_head *pages, unsigned nr_pages); 299b3f26c9SDavid Howells 3000d3b7a4SDavid Howells const struct file_operations afs_file_operations = { 3100d3b7a4SDavid Howells .open = afs_open, 3200d3b7a4SDavid Howells .release = afs_release, 3300d3b7a4SDavid Howells .llseek = generic_file_llseek, 3400d3b7a4SDavid Howells .read = do_sync_read, 3531143d5dSDavid Howells .write = do_sync_write, 3600d3b7a4SDavid Howells .aio_read = generic_file_aio_read, 3731143d5dSDavid Howells .aio_write = afs_file_write, 3800d3b7a4SDavid Howells .mmap = generic_file_readonly_mmap, 395ffc4ef4SJens Axboe .splice_read = generic_file_splice_read, 4031143d5dSDavid Howells .fsync = afs_fsync, 41e8d6c554SDavid Howells .lock = afs_lock, 42e8d6c554SDavid Howells .flock = afs_flock, 4300d3b7a4SDavid Howells }; 4400d3b7a4SDavid Howells 45754661f1SArjan van de Ven const struct inode_operations afs_file_inode_operations = { 46416351f2SDavid Howells .getattr = afs_getattr, 4731143d5dSDavid Howells .setattr = afs_setattr, 4800d3b7a4SDavid Howells .permission = afs_permission, 491da177e4SLinus Torvalds }; 501da177e4SLinus Torvalds 51f5e54d6eSChristoph Hellwig const struct address_space_operations afs_fs_aops = { 52416351f2SDavid Howells .readpage = afs_readpage, 539b3f26c9SDavid Howells .readpages = afs_readpages, 5431143d5dSDavid Howells .set_page_dirty = afs_set_page_dirty, 5531143d5dSDavid Howells .launder_page = afs_launder_page, 56416351f2SDavid Howells .releasepage = afs_releasepage, 57416351f2SDavid Howells .invalidatepage = afs_invalidatepage, 5815b4650eSNick Piggin .write_begin = afs_write_begin, 5915b4650eSNick Piggin .write_end = afs_write_end, 6031143d5dSDavid Howells .writepage = afs_writepage, 6131143d5dSDavid Howells .writepages = afs_writepages, 621da177e4SLinus Torvalds }; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /* 6500d3b7a4SDavid Howells * open an AFS file or directory and attach a key to it 6600d3b7a4SDavid Howells */ 6700d3b7a4SDavid Howells int afs_open(struct inode *inode, struct file *file) 6800d3b7a4SDavid Howells { 6900d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 7000d3b7a4SDavid Howells struct key *key; 71260a9803SDavid Howells int ret; 7200d3b7a4SDavid Howells 73416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 7400d3b7a4SDavid Howells 7500d3b7a4SDavid Howells key = afs_request_key(vnode->volume->cell); 7600d3b7a4SDavid Howells if (IS_ERR(key)) { 7700d3b7a4SDavid Howells _leave(" = %ld [key]", PTR_ERR(key)); 7800d3b7a4SDavid Howells return PTR_ERR(key); 7900d3b7a4SDavid Howells } 8000d3b7a4SDavid Howells 81260a9803SDavid Howells ret = afs_validate(vnode, key); 82260a9803SDavid Howells if (ret < 0) { 83260a9803SDavid Howells _leave(" = %d [val]", ret); 84260a9803SDavid Howells return ret; 85260a9803SDavid Howells } 86260a9803SDavid Howells 8700d3b7a4SDavid Howells file->private_data = key; 8800d3b7a4SDavid Howells _leave(" = 0"); 8900d3b7a4SDavid Howells return 0; 9000d3b7a4SDavid Howells } 9100d3b7a4SDavid Howells 9200d3b7a4SDavid Howells /* 9300d3b7a4SDavid Howells * release an AFS file or directory and discard its key 9400d3b7a4SDavid Howells */ 9500d3b7a4SDavid Howells int afs_release(struct inode *inode, struct file *file) 9600d3b7a4SDavid Howells { 9700d3b7a4SDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 9800d3b7a4SDavid Howells 99416351f2SDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 10000d3b7a4SDavid Howells 10100d3b7a4SDavid Howells key_put(file->private_data); 10200d3b7a4SDavid Howells _leave(" = 0"); 10300d3b7a4SDavid Howells return 0; 10400d3b7a4SDavid Howells } 10500d3b7a4SDavid Howells 1066566abdbSMatt Kraai #ifdef CONFIG_AFS_FSCACHE 10700d3b7a4SDavid Howells /* 1081da177e4SLinus Torvalds * deal with notification that a page was read from the cache 1091da177e4SLinus Torvalds */ 1109b3f26c9SDavid Howells static void afs_file_readpage_read_complete(struct page *page, 1111da177e4SLinus Torvalds void *data, 1121da177e4SLinus Torvalds int error) 1131da177e4SLinus Torvalds { 1149b3f26c9SDavid Howells _enter("%p,%p,%d", page, data, error); 1151da177e4SLinus Torvalds 1169b3f26c9SDavid Howells /* if the read completes with an error, we just unlock the page and let 1179b3f26c9SDavid Howells * the VM reissue the readpage */ 1189b3f26c9SDavid Howells if (!error) 1191da177e4SLinus Torvalds SetPageUptodate(page); 1201da177e4SLinus Torvalds unlock_page(page); 121ec26815aSDavid Howells } 1226566abdbSMatt Kraai #endif 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds /* 125f6d335c0SAl Viro * read page from file, directory or symlink, given a key to use 1261da177e4SLinus Torvalds */ 127f6d335c0SAl Viro int afs_page_filler(void *data, struct page *page) 1281da177e4SLinus Torvalds { 129f6d335c0SAl Viro struct inode *inode = page->mapping->host; 130f6d335c0SAl Viro struct afs_vnode *vnode = AFS_FS_I(inode); 131f6d335c0SAl Viro struct key *key = data; 13208e0e7c8SDavid Howells size_t len; 13308e0e7c8SDavid Howells off_t offset; 1341da177e4SLinus Torvalds int ret; 1351da177e4SLinus Torvalds 13600d3b7a4SDavid Howells _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); 1371da177e4SLinus Torvalds 138cd7619d6SMatt Mackall BUG_ON(!PageLocked(page)); 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds ret = -ESTALE; 14108e0e7c8SDavid Howells if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1421da177e4SLinus Torvalds goto error; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* is it cached? */ 1459b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 1469b3f26c9SDavid Howells ret = fscache_read_or_alloc_page(vnode->cache, 1471da177e4SLinus Torvalds page, 1481da177e4SLinus Torvalds afs_file_readpage_read_complete, 1491da177e4SLinus Torvalds NULL, 1501da177e4SLinus Torvalds GFP_KERNEL); 1511da177e4SLinus Torvalds #else 1521da177e4SLinus Torvalds ret = -ENOBUFS; 1531da177e4SLinus Torvalds #endif 1541da177e4SLinus Torvalds switch (ret) { 1551da177e4SLinus Torvalds /* read BIO submitted (page in cache) */ 1561da177e4SLinus Torvalds case 0: 1571da177e4SLinus Torvalds break; 1581da177e4SLinus Torvalds 1599b3f26c9SDavid Howells /* page not yet cached */ 1601da177e4SLinus Torvalds case -ENODATA: 1619b3f26c9SDavid Howells _debug("cache said ENODATA"); 1629b3f26c9SDavid Howells goto go_on; 1639b3f26c9SDavid Howells 1649b3f26c9SDavid Howells /* page will not be cached */ 1659b3f26c9SDavid Howells case -ENOBUFS: 1669b3f26c9SDavid Howells _debug("cache said ENOBUFS"); 1671da177e4SLinus Torvalds default: 1689b3f26c9SDavid Howells go_on: 16908e0e7c8SDavid Howells offset = page->index << PAGE_CACHE_SHIFT; 17008e0e7c8SDavid Howells len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds /* read the contents of the file from the server into the 1731da177e4SLinus Torvalds * page */ 17400d3b7a4SDavid Howells ret = afs_vnode_fetch_data(vnode, key, offset, len, page); 1751da177e4SLinus Torvalds if (ret < 0) { 1761da177e4SLinus Torvalds if (ret == -ENOENT) { 1771da177e4SLinus Torvalds _debug("got NOENT from server" 1781da177e4SLinus Torvalds " - marking file deleted and stale"); 17908e0e7c8SDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 1801da177e4SLinus Torvalds ret = -ESTALE; 1811da177e4SLinus Torvalds } 1829b3f26c9SDavid Howells 1839b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 1849b3f26c9SDavid Howells fscache_uncache_page(vnode->cache, page); 1851da177e4SLinus Torvalds #endif 1869b3f26c9SDavid Howells BUG_ON(PageFsCache(page)); 1871da177e4SLinus Torvalds goto error; 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds SetPageUptodate(page); 1911da177e4SLinus Torvalds 1929b3f26c9SDavid Howells /* send the page to the cache */ 1939b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 1949b3f26c9SDavid Howells if (PageFsCache(page) && 1959b3f26c9SDavid Howells fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) { 1969b3f26c9SDavid Howells fscache_uncache_page(vnode->cache, page); 1979b3f26c9SDavid Howells BUG_ON(PageFsCache(page)); 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds #endif 2009b3f26c9SDavid Howells unlock_page(page); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds _leave(" = 0"); 2041da177e4SLinus Torvalds return 0; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds error: 2071da177e4SLinus Torvalds SetPageError(page); 2081da177e4SLinus Torvalds unlock_page(page); 2091da177e4SLinus Torvalds _leave(" = %d", ret); 2101da177e4SLinus Torvalds return ret; 211ec26815aSDavid Howells } 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds /* 214f6d335c0SAl Viro * read page from file, directory or symlink, given a file to nominate the key 215f6d335c0SAl Viro * to be used 216f6d335c0SAl Viro */ 217f6d335c0SAl Viro static int afs_readpage(struct file *file, struct page *page) 218f6d335c0SAl Viro { 219f6d335c0SAl Viro struct key *key; 220f6d335c0SAl Viro int ret; 221f6d335c0SAl Viro 222f6d335c0SAl Viro if (file) { 223f6d335c0SAl Viro key = file->private_data; 224f6d335c0SAl Viro ASSERT(key != NULL); 225f6d335c0SAl Viro ret = afs_page_filler(key, page); 226f6d335c0SAl Viro } else { 227f6d335c0SAl Viro struct inode *inode = page->mapping->host; 228f6d335c0SAl Viro key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell); 229f6d335c0SAl Viro if (IS_ERR(key)) { 230f6d335c0SAl Viro ret = PTR_ERR(key); 231f6d335c0SAl Viro } else { 232f6d335c0SAl Viro ret = afs_page_filler(key, page); 233f6d335c0SAl Viro key_put(key); 234f6d335c0SAl Viro } 235f6d335c0SAl Viro } 236f6d335c0SAl Viro return ret; 237f6d335c0SAl Viro } 238f6d335c0SAl Viro 239f6d335c0SAl Viro /* 2409b3f26c9SDavid Howells * read a set of pages 2411da177e4SLinus Torvalds */ 2429b3f26c9SDavid Howells static int afs_readpages(struct file *file, struct address_space *mapping, 2439b3f26c9SDavid Howells struct list_head *pages, unsigned nr_pages) 2441da177e4SLinus Torvalds { 245f6d335c0SAl Viro struct key *key = file->private_data; 2469b3f26c9SDavid Howells struct afs_vnode *vnode; 2479b3f26c9SDavid Howells int ret = 0; 2481da177e4SLinus Torvalds 249f6d335c0SAl Viro _enter("{%d},{%lu},,%d", 250f6d335c0SAl Viro key_serial(key), mapping->host->i_ino, nr_pages); 251f6d335c0SAl Viro 252f6d335c0SAl Viro ASSERT(key != NULL); 2531da177e4SLinus Torvalds 2549b3f26c9SDavid Howells vnode = AFS_FS_I(mapping->host); 255ad2a8e60SDan Carpenter if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 2569b3f26c9SDavid Howells _leave(" = -ESTALE"); 2579b3f26c9SDavid Howells return -ESTALE; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2609b3f26c9SDavid Howells /* attempt to read as many of the pages as possible */ 2619b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 2629b3f26c9SDavid Howells ret = fscache_read_or_alloc_pages(vnode->cache, 2639b3f26c9SDavid Howells mapping, 2649b3f26c9SDavid Howells pages, 2659b3f26c9SDavid Howells &nr_pages, 2669b3f26c9SDavid Howells afs_file_readpage_read_complete, 2679b3f26c9SDavid Howells NULL, 2689b3f26c9SDavid Howells mapping_gfp_mask(mapping)); 2699b3f26c9SDavid Howells #else 2709b3f26c9SDavid Howells ret = -ENOBUFS; 2719b3f26c9SDavid Howells #endif 2729b3f26c9SDavid Howells 2739b3f26c9SDavid Howells switch (ret) { 2749b3f26c9SDavid Howells /* all pages are being read from the cache */ 2759b3f26c9SDavid Howells case 0: 2769b3f26c9SDavid Howells BUG_ON(!list_empty(pages)); 2779b3f26c9SDavid Howells BUG_ON(nr_pages != 0); 2789b3f26c9SDavid Howells _leave(" = 0 [reading all]"); 2799b3f26c9SDavid Howells return 0; 2809b3f26c9SDavid Howells 2819b3f26c9SDavid Howells /* there were pages that couldn't be read from the cache */ 2829b3f26c9SDavid Howells case -ENODATA: 2839b3f26c9SDavid Howells case -ENOBUFS: 2849b3f26c9SDavid Howells break; 2859b3f26c9SDavid Howells 2869b3f26c9SDavid Howells /* other error */ 2879b3f26c9SDavid Howells default: 2881da177e4SLinus Torvalds _leave(" = %d", ret); 2899b3f26c9SDavid Howells return ret; 2909b3f26c9SDavid Howells } 2919b3f26c9SDavid Howells 2929b3f26c9SDavid Howells /* load the missing pages from the network */ 293f6d335c0SAl Viro ret = read_cache_pages(mapping, pages, afs_page_filler, key); 2949b3f26c9SDavid Howells 2959b3f26c9SDavid Howells _leave(" = %d [netting]", ret); 2969b3f26c9SDavid Howells return ret; 297ec26815aSDavid Howells } 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds /* 30031143d5dSDavid Howells * write back a dirty page 30131143d5dSDavid Howells */ 30231143d5dSDavid Howells static int afs_launder_page(struct page *page) 30331143d5dSDavid Howells { 30431143d5dSDavid Howells _enter("{%lu}", page->index); 30531143d5dSDavid Howells 30631143d5dSDavid Howells return 0; 30731143d5dSDavid Howells } 30831143d5dSDavid Howells 30931143d5dSDavid Howells /* 3109b3f26c9SDavid Howells * invalidate part or all of a page 3119b3f26c9SDavid Howells * - release a page and clean up its private data if offset is 0 (indicating 3129b3f26c9SDavid Howells * the entire page) 3139b3f26c9SDavid Howells */ 314*d47992f8SLukas Czerner static void afs_invalidatepage(struct page *page, unsigned int offset, 315*d47992f8SLukas Czerner unsigned int length) 3169b3f26c9SDavid Howells { 3179b3f26c9SDavid Howells struct afs_writeback *wb = (struct afs_writeback *) page_private(page); 3189b3f26c9SDavid Howells 319*d47992f8SLukas Czerner _enter("{%lu},%u,%u", page->index, offset, length); 3209b3f26c9SDavid Howells 3219b3f26c9SDavid Howells BUG_ON(!PageLocked(page)); 3229b3f26c9SDavid Howells 3239b3f26c9SDavid Howells /* we clean up only if the entire page is being invalidated */ 324*d47992f8SLukas Czerner if (offset == 0 && length == PAGE_CACHE_SIZE) { 3259b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 3269b3f26c9SDavid Howells if (PageFsCache(page)) { 3279b3f26c9SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 3289b3f26c9SDavid Howells fscache_wait_on_page_write(vnode->cache, page); 3299b3f26c9SDavid Howells fscache_uncache_page(vnode->cache, page); 3309b3f26c9SDavid Howells } 3319b3f26c9SDavid Howells #endif 3329b3f26c9SDavid Howells 3339b3f26c9SDavid Howells if (PagePrivate(page)) { 3349b3f26c9SDavid Howells if (wb && !PageWriteback(page)) { 3359b3f26c9SDavid Howells set_page_private(page, 0); 3369b3f26c9SDavid Howells afs_put_writeback(wb); 3379b3f26c9SDavid Howells } 3389b3f26c9SDavid Howells 3399b3f26c9SDavid Howells if (!page_private(page)) 3409b3f26c9SDavid Howells ClearPagePrivate(page); 3419b3f26c9SDavid Howells } 3429b3f26c9SDavid Howells } 3439b3f26c9SDavid Howells 3449b3f26c9SDavid Howells _leave(""); 3459b3f26c9SDavid Howells } 3469b3f26c9SDavid Howells 3479b3f26c9SDavid Howells /* 3489b3f26c9SDavid Howells * release a page and clean up its private state if it's not busy 3499b3f26c9SDavid Howells * - return true if the page can now be released, false if not 3501da177e4SLinus Torvalds */ 351416351f2SDavid Howells static int afs_releasepage(struct page *page, gfp_t gfp_flags) 3521da177e4SLinus Torvalds { 3539b3f26c9SDavid Howells struct afs_writeback *wb = (struct afs_writeback *) page_private(page); 354416351f2SDavid Howells struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 3551da177e4SLinus Torvalds 356416351f2SDavid Howells _enter("{{%x:%u}[%lu],%lx},%x", 357416351f2SDavid Howells vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, 358416351f2SDavid Howells gfp_flags); 3591da177e4SLinus Torvalds 3609b3f26c9SDavid Howells /* deny if page is being written to the cache and the caller hasn't 3619b3f26c9SDavid Howells * elected to wait */ 3629b3f26c9SDavid Howells #ifdef CONFIG_AFS_FSCACHE 363201a1542SDavid Howells if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { 3649b3f26c9SDavid Howells _leave(" = F [cache busy]"); 3659b3f26c9SDavid Howells return 0; 3669b3f26c9SDavid Howells } 3679b3f26c9SDavid Howells #endif 3689b3f26c9SDavid Howells 3699b3f26c9SDavid Howells if (PagePrivate(page)) { 3709b3f26c9SDavid Howells if (wb) { 3719b3f26c9SDavid Howells set_page_private(page, 0); 3729b3f26c9SDavid Howells afs_put_writeback(wb); 3739b3f26c9SDavid Howells } 3749b3f26c9SDavid Howells ClearPagePrivate(page); 3759b3f26c9SDavid Howells } 3769b3f26c9SDavid Howells 3779b3f26c9SDavid Howells /* indicate that the page can be released */ 3789b3f26c9SDavid Howells _leave(" = T"); 3799b3f26c9SDavid Howells return 1; 380ec26815aSDavid Howells } 381