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