1*1da177e4SLinus Torvalds /* file.c: AFS filesystem file handling 2*1da177e4SLinus Torvalds * 3*1da177e4SLinus Torvalds * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 4*1da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 7*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 8*1da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 9*1da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 10*1da177e4SLinus Torvalds */ 11*1da177e4SLinus Torvalds 12*1da177e4SLinus Torvalds #include <linux/kernel.h> 13*1da177e4SLinus Torvalds #include <linux/module.h> 14*1da177e4SLinus Torvalds #include <linux/init.h> 15*1da177e4SLinus Torvalds #include <linux/sched.h> 16*1da177e4SLinus Torvalds #include <linux/slab.h> 17*1da177e4SLinus Torvalds #include <linux/fs.h> 18*1da177e4SLinus Torvalds #include <linux/pagemap.h> 19*1da177e4SLinus Torvalds #include <linux/buffer_head.h> 20*1da177e4SLinus Torvalds #include "volume.h" 21*1da177e4SLinus Torvalds #include "vnode.h" 22*1da177e4SLinus Torvalds #include <rxrpc/call.h> 23*1da177e4SLinus Torvalds #include "internal.h" 24*1da177e4SLinus Torvalds 25*1da177e4SLinus Torvalds #if 0 26*1da177e4SLinus Torvalds static int afs_file_open(struct inode *inode, struct file *file); 27*1da177e4SLinus Torvalds static int afs_file_release(struct inode *inode, struct file *file); 28*1da177e4SLinus Torvalds #endif 29*1da177e4SLinus Torvalds 30*1da177e4SLinus Torvalds static int afs_file_readpage(struct file *file, struct page *page); 31*1da177e4SLinus Torvalds static int afs_file_invalidatepage(struct page *page, unsigned long offset); 32*1da177e4SLinus Torvalds static int afs_file_releasepage(struct page *page, int gfp_flags); 33*1da177e4SLinus Torvalds 34*1da177e4SLinus Torvalds static ssize_t afs_file_write(struct file *file, const char __user *buf, 35*1da177e4SLinus Torvalds size_t size, loff_t *off); 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds struct inode_operations afs_file_inode_operations = { 38*1da177e4SLinus Torvalds .getattr = afs_inode_getattr, 39*1da177e4SLinus Torvalds }; 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds struct file_operations afs_file_file_operations = { 42*1da177e4SLinus Torvalds .read = generic_file_read, 43*1da177e4SLinus Torvalds .write = afs_file_write, 44*1da177e4SLinus Torvalds .mmap = generic_file_mmap, 45*1da177e4SLinus Torvalds #if 0 46*1da177e4SLinus Torvalds .open = afs_file_open, 47*1da177e4SLinus Torvalds .release = afs_file_release, 48*1da177e4SLinus Torvalds .fsync = afs_file_fsync, 49*1da177e4SLinus Torvalds #endif 50*1da177e4SLinus Torvalds }; 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds struct address_space_operations afs_fs_aops = { 53*1da177e4SLinus Torvalds .readpage = afs_file_readpage, 54*1da177e4SLinus Torvalds .sync_page = block_sync_page, 55*1da177e4SLinus Torvalds .set_page_dirty = __set_page_dirty_nobuffers, 56*1da177e4SLinus Torvalds .releasepage = afs_file_releasepage, 57*1da177e4SLinus Torvalds .invalidatepage = afs_file_invalidatepage, 58*1da177e4SLinus Torvalds }; 59*1da177e4SLinus Torvalds 60*1da177e4SLinus Torvalds /*****************************************************************************/ 61*1da177e4SLinus Torvalds /* 62*1da177e4SLinus Torvalds * AFS file write 63*1da177e4SLinus Torvalds */ 64*1da177e4SLinus Torvalds static ssize_t afs_file_write(struct file *file, const char __user *buf, 65*1da177e4SLinus Torvalds size_t size, loff_t *off) 66*1da177e4SLinus Torvalds { 67*1da177e4SLinus Torvalds struct afs_vnode *vnode; 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds vnode = AFS_FS_I(file->f_dentry->d_inode); 70*1da177e4SLinus Torvalds if (vnode->flags & AFS_VNODE_DELETED) 71*1da177e4SLinus Torvalds return -ESTALE; 72*1da177e4SLinus Torvalds 73*1da177e4SLinus Torvalds return -EIO; 74*1da177e4SLinus Torvalds } /* end afs_file_write() */ 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds /*****************************************************************************/ 77*1da177e4SLinus Torvalds /* 78*1da177e4SLinus Torvalds * deal with notification that a page was read from the cache 79*1da177e4SLinus Torvalds */ 80*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 81*1da177e4SLinus Torvalds static void afs_file_readpage_read_complete(void *cookie_data, 82*1da177e4SLinus Torvalds struct page *page, 83*1da177e4SLinus Torvalds void *data, 84*1da177e4SLinus Torvalds int error) 85*1da177e4SLinus Torvalds { 86*1da177e4SLinus Torvalds _enter("%p,%p,%p,%d", cookie_data, page, data, error); 87*1da177e4SLinus Torvalds 88*1da177e4SLinus Torvalds if (error) 89*1da177e4SLinus Torvalds SetPageError(page); 90*1da177e4SLinus Torvalds else 91*1da177e4SLinus Torvalds SetPageUptodate(page); 92*1da177e4SLinus Torvalds unlock_page(page); 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds } /* end afs_file_readpage_read_complete() */ 95*1da177e4SLinus Torvalds #endif 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds /*****************************************************************************/ 98*1da177e4SLinus Torvalds /* 99*1da177e4SLinus Torvalds * deal with notification that a page was written to the cache 100*1da177e4SLinus Torvalds */ 101*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 102*1da177e4SLinus Torvalds static void afs_file_readpage_write_complete(void *cookie_data, 103*1da177e4SLinus Torvalds struct page *page, 104*1da177e4SLinus Torvalds void *data, 105*1da177e4SLinus Torvalds int error) 106*1da177e4SLinus Torvalds { 107*1da177e4SLinus Torvalds _enter("%p,%p,%p,%d", cookie_data, page, data, error); 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds unlock_page(page); 110*1da177e4SLinus Torvalds 111*1da177e4SLinus Torvalds } /* end afs_file_readpage_write_complete() */ 112*1da177e4SLinus Torvalds #endif 113*1da177e4SLinus Torvalds 114*1da177e4SLinus Torvalds /*****************************************************************************/ 115*1da177e4SLinus Torvalds /* 116*1da177e4SLinus Torvalds * AFS read page from file (or symlink) 117*1da177e4SLinus Torvalds */ 118*1da177e4SLinus Torvalds static int afs_file_readpage(struct file *file, struct page *page) 119*1da177e4SLinus Torvalds { 120*1da177e4SLinus Torvalds struct afs_rxfs_fetch_descriptor desc; 121*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 122*1da177e4SLinus Torvalds struct cachefs_page *pageio; 123*1da177e4SLinus Torvalds #endif 124*1da177e4SLinus Torvalds struct afs_vnode *vnode; 125*1da177e4SLinus Torvalds struct inode *inode; 126*1da177e4SLinus Torvalds int ret; 127*1da177e4SLinus Torvalds 128*1da177e4SLinus Torvalds inode = page->mapping->host; 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds _enter("{%lu},{%lu}", inode->i_ino, page->index); 131*1da177e4SLinus Torvalds 132*1da177e4SLinus Torvalds vnode = AFS_FS_I(inode); 133*1da177e4SLinus Torvalds 134*1da177e4SLinus Torvalds if (!PageLocked(page)) 135*1da177e4SLinus Torvalds PAGE_BUG(page); 136*1da177e4SLinus Torvalds 137*1da177e4SLinus Torvalds ret = -ESTALE; 138*1da177e4SLinus Torvalds if (vnode->flags & AFS_VNODE_DELETED) 139*1da177e4SLinus Torvalds goto error; 140*1da177e4SLinus Torvalds 141*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 142*1da177e4SLinus Torvalds ret = cachefs_page_get_private(page, &pageio, GFP_NOIO); 143*1da177e4SLinus Torvalds if (ret < 0) 144*1da177e4SLinus Torvalds goto error; 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds /* is it cached? */ 147*1da177e4SLinus Torvalds ret = cachefs_read_or_alloc_page(vnode->cache, 148*1da177e4SLinus Torvalds page, 149*1da177e4SLinus Torvalds afs_file_readpage_read_complete, 150*1da177e4SLinus Torvalds NULL, 151*1da177e4SLinus Torvalds GFP_KERNEL); 152*1da177e4SLinus Torvalds #else 153*1da177e4SLinus Torvalds ret = -ENOBUFS; 154*1da177e4SLinus Torvalds #endif 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds switch (ret) { 157*1da177e4SLinus Torvalds /* read BIO submitted and wb-journal entry found */ 158*1da177e4SLinus Torvalds case 1: 159*1da177e4SLinus Torvalds BUG(); // TODO - handle wb-journal match 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds /* read BIO submitted (page in cache) */ 162*1da177e4SLinus Torvalds case 0: 163*1da177e4SLinus Torvalds break; 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds /* no page available in cache */ 166*1da177e4SLinus Torvalds case -ENOBUFS: 167*1da177e4SLinus Torvalds case -ENODATA: 168*1da177e4SLinus Torvalds default: 169*1da177e4SLinus Torvalds desc.fid = vnode->fid; 170*1da177e4SLinus Torvalds desc.offset = page->index << PAGE_CACHE_SHIFT; 171*1da177e4SLinus Torvalds desc.size = min((size_t) (inode->i_size - desc.offset), 172*1da177e4SLinus Torvalds (size_t) PAGE_SIZE); 173*1da177e4SLinus Torvalds desc.buffer = kmap(page); 174*1da177e4SLinus Torvalds 175*1da177e4SLinus Torvalds clear_page(desc.buffer); 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds /* read the contents of the file from the server into the 178*1da177e4SLinus Torvalds * page */ 179*1da177e4SLinus Torvalds ret = afs_vnode_fetch_data(vnode, &desc); 180*1da177e4SLinus Torvalds kunmap(page); 181*1da177e4SLinus Torvalds if (ret < 0) { 182*1da177e4SLinus Torvalds if (ret==-ENOENT) { 183*1da177e4SLinus Torvalds _debug("got NOENT from server" 184*1da177e4SLinus Torvalds " - marking file deleted and stale"); 185*1da177e4SLinus Torvalds vnode->flags |= AFS_VNODE_DELETED; 186*1da177e4SLinus Torvalds ret = -ESTALE; 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds 189*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 190*1da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache, page); 191*1da177e4SLinus Torvalds #endif 192*1da177e4SLinus Torvalds goto error; 193*1da177e4SLinus Torvalds } 194*1da177e4SLinus Torvalds 195*1da177e4SLinus Torvalds SetPageUptodate(page); 196*1da177e4SLinus Torvalds 197*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 198*1da177e4SLinus Torvalds if (cachefs_write_page(vnode->cache, 199*1da177e4SLinus Torvalds page, 200*1da177e4SLinus Torvalds afs_file_readpage_write_complete, 201*1da177e4SLinus Torvalds NULL, 202*1da177e4SLinus Torvalds GFP_KERNEL) != 0 203*1da177e4SLinus Torvalds ) { 204*1da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache, page); 205*1da177e4SLinus Torvalds unlock_page(page); 206*1da177e4SLinus Torvalds } 207*1da177e4SLinus Torvalds #else 208*1da177e4SLinus Torvalds unlock_page(page); 209*1da177e4SLinus Torvalds #endif 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds 212*1da177e4SLinus Torvalds _leave(" = 0"); 213*1da177e4SLinus Torvalds return 0; 214*1da177e4SLinus Torvalds 215*1da177e4SLinus Torvalds error: 216*1da177e4SLinus Torvalds SetPageError(page); 217*1da177e4SLinus Torvalds unlock_page(page); 218*1da177e4SLinus Torvalds 219*1da177e4SLinus Torvalds _leave(" = %d", ret); 220*1da177e4SLinus Torvalds return ret; 221*1da177e4SLinus Torvalds 222*1da177e4SLinus Torvalds } /* end afs_file_readpage() */ 223*1da177e4SLinus Torvalds 224*1da177e4SLinus Torvalds /*****************************************************************************/ 225*1da177e4SLinus Torvalds /* 226*1da177e4SLinus Torvalds * get a page cookie for the specified page 227*1da177e4SLinus Torvalds */ 228*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 229*1da177e4SLinus Torvalds int afs_cache_get_page_cookie(struct page *page, 230*1da177e4SLinus Torvalds struct cachefs_page **_page_cookie) 231*1da177e4SLinus Torvalds { 232*1da177e4SLinus Torvalds int ret; 233*1da177e4SLinus Torvalds 234*1da177e4SLinus Torvalds _enter(""); 235*1da177e4SLinus Torvalds ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO); 236*1da177e4SLinus Torvalds 237*1da177e4SLinus Torvalds _leave(" = %d", ret); 238*1da177e4SLinus Torvalds return ret; 239*1da177e4SLinus Torvalds } /* end afs_cache_get_page_cookie() */ 240*1da177e4SLinus Torvalds #endif 241*1da177e4SLinus Torvalds 242*1da177e4SLinus Torvalds /*****************************************************************************/ 243*1da177e4SLinus Torvalds /* 244*1da177e4SLinus Torvalds * invalidate part or all of a page 245*1da177e4SLinus Torvalds */ 246*1da177e4SLinus Torvalds static int afs_file_invalidatepage(struct page *page, unsigned long offset) 247*1da177e4SLinus Torvalds { 248*1da177e4SLinus Torvalds int ret = 1; 249*1da177e4SLinus Torvalds 250*1da177e4SLinus Torvalds _enter("{%lu},%lu", page->index, offset); 251*1da177e4SLinus Torvalds 252*1da177e4SLinus Torvalds BUG_ON(!PageLocked(page)); 253*1da177e4SLinus Torvalds 254*1da177e4SLinus Torvalds if (PagePrivate(page)) { 255*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 256*1da177e4SLinus Torvalds struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 257*1da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache,page); 258*1da177e4SLinus Torvalds #endif 259*1da177e4SLinus Torvalds 260*1da177e4SLinus Torvalds /* We release buffers only if the entire page is being 261*1da177e4SLinus Torvalds * invalidated. 262*1da177e4SLinus Torvalds * The get_block cached value has been unconditionally 263*1da177e4SLinus Torvalds * invalidated, so real IO is not possible anymore. 264*1da177e4SLinus Torvalds */ 265*1da177e4SLinus Torvalds if (offset == 0) { 266*1da177e4SLinus Torvalds BUG_ON(!PageLocked(page)); 267*1da177e4SLinus Torvalds 268*1da177e4SLinus Torvalds ret = 0; 269*1da177e4SLinus Torvalds if (!PageWriteback(page)) 270*1da177e4SLinus Torvalds ret = page->mapping->a_ops->releasepage(page, 271*1da177e4SLinus Torvalds 0); 272*1da177e4SLinus Torvalds } 273*1da177e4SLinus Torvalds } 274*1da177e4SLinus Torvalds 275*1da177e4SLinus Torvalds _leave(" = %d", ret); 276*1da177e4SLinus Torvalds return ret; 277*1da177e4SLinus Torvalds } /* end afs_file_invalidatepage() */ 278*1da177e4SLinus Torvalds 279*1da177e4SLinus Torvalds /*****************************************************************************/ 280*1da177e4SLinus Torvalds /* 281*1da177e4SLinus Torvalds * release a page and cleanup its private data 282*1da177e4SLinus Torvalds */ 283*1da177e4SLinus Torvalds static int afs_file_releasepage(struct page *page, int gfp_flags) 284*1da177e4SLinus Torvalds { 285*1da177e4SLinus Torvalds struct cachefs_page *pageio; 286*1da177e4SLinus Torvalds 287*1da177e4SLinus Torvalds _enter("{%lu},%x", page->index, gfp_flags); 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds if (PagePrivate(page)) { 290*1da177e4SLinus Torvalds #ifdef AFS_CACHING_SUPPORT 291*1da177e4SLinus Torvalds struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); 292*1da177e4SLinus Torvalds cachefs_uncache_page(vnode->cache, page); 293*1da177e4SLinus Torvalds #endif 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds pageio = (struct cachefs_page *) page->private; 296*1da177e4SLinus Torvalds page->private = 0; 297*1da177e4SLinus Torvalds ClearPagePrivate(page); 298*1da177e4SLinus Torvalds 299*1da177e4SLinus Torvalds if (pageio) 300*1da177e4SLinus Torvalds kfree(pageio); 301*1da177e4SLinus Torvalds } 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds _leave(" = 0"); 304*1da177e4SLinus Torvalds return 0; 305*1da177e4SLinus Torvalds } /* end afs_file_releasepage() */ 306