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