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