Blame view
fs/afs/file.c
8.56 KB
08e0e7c82
|
1 |
/* AFS filesystem file handling |
1da177e4c
|
2 |
* |
08e0e7c82
|
3 |
* Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
1da177e4c
|
4 5 6 7 8 9 10 11 12 13 14 |
* Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> |
1da177e4c
|
15 16 |
#include <linux/fs.h> #include <linux/pagemap.h> |
31143d5d5
|
17 |
#include <linux/writeback.h> |
5a0e3ad6a
|
18 |
#include <linux/gfp.h> |
1da177e4c
|
19 |
#include "internal.h" |
416351f28
|
20 21 22 |
static int afs_readpage(struct file *file, struct page *page); static void afs_invalidatepage(struct page *page, unsigned long offset); static int afs_releasepage(struct page *page, gfp_t gfp_flags); |
31143d5d5
|
23 |
static int afs_launder_page(struct page *page); |
1da177e4c
|
24 |
|
9b3f26c91
|
25 26 |
static int afs_readpages(struct file *filp, struct address_space *mapping, struct list_head *pages, unsigned nr_pages); |
00d3b7a45
|
27 28 29 30 31 |
const struct file_operations afs_file_operations = { .open = afs_open, .release = afs_release, .llseek = generic_file_llseek, .read = do_sync_read, |
31143d5d5
|
32 |
.write = do_sync_write, |
00d3b7a45
|
33 |
.aio_read = generic_file_aio_read, |
31143d5d5
|
34 |
.aio_write = afs_file_write, |
00d3b7a45
|
35 |
.mmap = generic_file_readonly_mmap, |
5ffc4ef45
|
36 |
.splice_read = generic_file_splice_read, |
31143d5d5
|
37 |
.fsync = afs_fsync, |
e8d6c5541
|
38 39 |
.lock = afs_lock, .flock = afs_flock, |
00d3b7a45
|
40 |
}; |
754661f14
|
41 |
const struct inode_operations afs_file_inode_operations = { |
416351f28
|
42 |
.getattr = afs_getattr, |
31143d5d5
|
43 |
.setattr = afs_setattr, |
00d3b7a45
|
44 |
.permission = afs_permission, |
1da177e4c
|
45 |
}; |
f5e54d6e5
|
46 |
const struct address_space_operations afs_fs_aops = { |
416351f28
|
47 |
.readpage = afs_readpage, |
9b3f26c91
|
48 |
.readpages = afs_readpages, |
31143d5d5
|
49 50 |
.set_page_dirty = afs_set_page_dirty, .launder_page = afs_launder_page, |
416351f28
|
51 52 |
.releasepage = afs_releasepage, .invalidatepage = afs_invalidatepage, |
15b4650e5
|
53 54 |
.write_begin = afs_write_begin, .write_end = afs_write_end, |
31143d5d5
|
55 56 |
.writepage = afs_writepage, .writepages = afs_writepages, |
1da177e4c
|
57 |
}; |
1da177e4c
|
58 |
/* |
00d3b7a45
|
59 60 61 62 63 64 |
* open an AFS file or directory and attach a key to it */ int afs_open(struct inode *inode, struct file *file) { struct afs_vnode *vnode = AFS_FS_I(inode); struct key *key; |
260a98031
|
65 |
int ret; |
00d3b7a45
|
66 |
|
416351f28
|
67 |
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); |
00d3b7a45
|
68 69 70 71 72 73 |
key = afs_request_key(vnode->volume->cell); if (IS_ERR(key)) { _leave(" = %ld [key]", PTR_ERR(key)); return PTR_ERR(key); } |
260a98031
|
74 75 76 77 78 |
ret = afs_validate(vnode, key); if (ret < 0) { _leave(" = %d [val]", ret); return ret; } |
00d3b7a45
|
79 80 81 82 83 84 85 86 87 88 89 |
file->private_data = key; _leave(" = 0"); return 0; } /* * release an AFS file or directory and discard its key */ int afs_release(struct inode *inode, struct file *file) { struct afs_vnode *vnode = AFS_FS_I(inode); |
416351f28
|
90 |
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); |
00d3b7a45
|
91 92 93 94 95 |
key_put(file->private_data); _leave(" = 0"); return 0; } |
6566abdbd
|
96 |
#ifdef CONFIG_AFS_FSCACHE |
00d3b7a45
|
97 |
/* |
1da177e4c
|
98 99 |
* deal with notification that a page was read from the cache */ |
9b3f26c91
|
100 101 102 |
static void afs_file_readpage_read_complete(struct page *page, void *data, int error) |
1da177e4c
|
103 |
{ |
9b3f26c91
|
104 |
_enter("%p,%p,%d", page, data, error); |
1da177e4c
|
105 |
|
9b3f26c91
|
106 107 108 |
/* if the read completes with an error, we just unlock the page and let * the VM reissue the readpage */ if (!error) |
1da177e4c
|
109 110 |
SetPageUptodate(page); unlock_page(page); |
ec26815ad
|
111 |
} |
6566abdbd
|
112 |
#endif |
1da177e4c
|
113 |
|
1da177e4c
|
114 |
/* |
f6d335c08
|
115 |
* read page from file, directory or symlink, given a key to use |
1da177e4c
|
116 |
*/ |
f6d335c08
|
117 |
int afs_page_filler(void *data, struct page *page) |
1da177e4c
|
118 |
{ |
f6d335c08
|
119 120 121 |
struct inode *inode = page->mapping->host; struct afs_vnode *vnode = AFS_FS_I(inode); struct key *key = data; |
08e0e7c82
|
122 123 |
size_t len; off_t offset; |
1da177e4c
|
124 |
int ret; |
00d3b7a45
|
125 |
_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); |
1da177e4c
|
126 |
|
cd7619d6b
|
127 |
BUG_ON(!PageLocked(page)); |
1da177e4c
|
128 129 |
ret = -ESTALE; |
08e0e7c82
|
130 |
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
1da177e4c
|
131 |
goto error; |
1da177e4c
|
132 |
/* is it cached? */ |
9b3f26c91
|
133 134 |
#ifdef CONFIG_AFS_FSCACHE ret = fscache_read_or_alloc_page(vnode->cache, |
1da177e4c
|
135 136 137 138 139 140 141 |
page, afs_file_readpage_read_complete, NULL, GFP_KERNEL); #else ret = -ENOBUFS; #endif |
1da177e4c
|
142 |
switch (ret) { |
1da177e4c
|
143 144 145 |
/* read BIO submitted (page in cache) */ case 0: break; |
9b3f26c91
|
146 |
/* page not yet cached */ |
1da177e4c
|
147 |
case -ENODATA: |
9b3f26c91
|
148 149 150 151 152 153 |
_debug("cache said ENODATA"); goto go_on; /* page will not be cached */ case -ENOBUFS: _debug("cache said ENOBUFS"); |
1da177e4c
|
154 |
default: |
9b3f26c91
|
155 |
go_on: |
08e0e7c82
|
156 157 |
offset = page->index << PAGE_CACHE_SHIFT; len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); |
1da177e4c
|
158 159 160 |
/* read the contents of the file from the server into the * page */ |
00d3b7a45
|
161 |
ret = afs_vnode_fetch_data(vnode, key, offset, len, page); |
1da177e4c
|
162 |
if (ret < 0) { |
08e0e7c82
|
163 |
if (ret == -ENOENT) { |
1da177e4c
|
164 165 |
_debug("got NOENT from server" " - marking file deleted and stale"); |
08e0e7c82
|
166 |
set_bit(AFS_VNODE_DELETED, &vnode->flags); |
1da177e4c
|
167 168 |
ret = -ESTALE; } |
9b3f26c91
|
169 170 171 |
#ifdef CONFIG_AFS_FSCACHE fscache_uncache_page(vnode->cache, page); |
1da177e4c
|
172 |
#endif |
9b3f26c91
|
173 |
BUG_ON(PageFsCache(page)); |
1da177e4c
|
174 175 176 177 |
goto error; } SetPageUptodate(page); |
9b3f26c91
|
178 179 180 181 182 183 |
/* send the page to the cache */ #ifdef CONFIG_AFS_FSCACHE if (PageFsCache(page) && fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) { fscache_uncache_page(vnode->cache, page); BUG_ON(PageFsCache(page)); |
1da177e4c
|
184 |
} |
1da177e4c
|
185 |
#endif |
9b3f26c91
|
186 |
unlock_page(page); |
1da177e4c
|
187 188 189 190 |
} _leave(" = 0"); return 0; |
08e0e7c82
|
191 |
error: |
1da177e4c
|
192 193 |
SetPageError(page); unlock_page(page); |
1da177e4c
|
194 195 |
_leave(" = %d", ret); return ret; |
ec26815ad
|
196 |
} |
1da177e4c
|
197 |
|
1da177e4c
|
198 |
/* |
f6d335c08
|
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
* read page from file, directory or symlink, given a file to nominate the key * to be used */ static int afs_readpage(struct file *file, struct page *page) { struct key *key; int ret; if (file) { key = file->private_data; ASSERT(key != NULL); ret = afs_page_filler(key, page); } else { struct inode *inode = page->mapping->host; key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); } else { ret = afs_page_filler(key, page); key_put(key); } } return ret; } /* |
9b3f26c91
|
225 |
* read a set of pages |
1da177e4c
|
226 |
*/ |
9b3f26c91
|
227 228 |
static int afs_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) |
1da177e4c
|
229 |
{ |
f6d335c08
|
230 |
struct key *key = file->private_data; |
9b3f26c91
|
231 232 |
struct afs_vnode *vnode; int ret = 0; |
1da177e4c
|
233 |
|
f6d335c08
|
234 235 236 237 |
_enter("{%d},{%lu},,%d", key_serial(key), mapping->host->i_ino, nr_pages); ASSERT(key != NULL); |
1da177e4c
|
238 |
|
9b3f26c91
|
239 240 241 242 243 |
vnode = AFS_FS_I(mapping->host); if (vnode->flags & AFS_VNODE_DELETED) { _leave(" = -ESTALE"); return -ESTALE; } |
1da177e4c
|
244 |
|
9b3f26c91
|
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
/* attempt to read as many of the pages as possible */ #ifdef CONFIG_AFS_FSCACHE ret = fscache_read_or_alloc_pages(vnode->cache, mapping, pages, &nr_pages, afs_file_readpage_read_complete, NULL, mapping_gfp_mask(mapping)); #else ret = -ENOBUFS; #endif switch (ret) { /* all pages are being read from the cache */ case 0: BUG_ON(!list_empty(pages)); BUG_ON(nr_pages != 0); _leave(" = 0 [reading all]"); return 0; /* there were pages that couldn't be read from the cache */ case -ENODATA: case -ENOBUFS: break; /* other error */ default: _leave(" = %d", ret); return ret; |
1da177e4c
|
275 |
} |
9b3f26c91
|
276 |
/* load the missing pages from the network */ |
f6d335c08
|
277 |
ret = read_cache_pages(mapping, pages, afs_page_filler, key); |
9b3f26c91
|
278 279 280 |
_leave(" = %d [netting]", ret); return ret; |
ec26815ad
|
281 |
} |
1da177e4c
|
282 |
|
1da177e4c
|
283 |
/* |
31143d5d5
|
284 285 286 287 288 289 290 291 292 293 |
* write back a dirty page */ static int afs_launder_page(struct page *page) { _enter("{%lu}", page->index); return 0; } /* |
9b3f26c91
|
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
* invalidate part or all of a page * - release a page and clean up its private data if offset is 0 (indicating * the entire page) */ static void afs_invalidatepage(struct page *page, unsigned long offset) { struct afs_writeback *wb = (struct afs_writeback *) page_private(page); _enter("{%lu},%lu", page->index, offset); BUG_ON(!PageLocked(page)); /* we clean up only if the entire page is being invalidated */ if (offset == 0) { #ifdef CONFIG_AFS_FSCACHE if (PageFsCache(page)) { struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); fscache_wait_on_page_write(vnode->cache, page); fscache_uncache_page(vnode->cache, page); |
9b3f26c91
|
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
} #endif if (PagePrivate(page)) { if (wb && !PageWriteback(page)) { set_page_private(page, 0); afs_put_writeback(wb); } if (!page_private(page)) ClearPagePrivate(page); } } _leave(""); } /* * release a page and clean up its private state if it's not busy * - return true if the page can now be released, false if not |
1da177e4c
|
333 |
*/ |
416351f28
|
334 |
static int afs_releasepage(struct page *page, gfp_t gfp_flags) |
1da177e4c
|
335 |
{ |
9b3f26c91
|
336 |
struct afs_writeback *wb = (struct afs_writeback *) page_private(page); |
416351f28
|
337 |
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
1da177e4c
|
338 |
|
416351f28
|
339 340 341 |
_enter("{{%x:%u}[%lu],%lx},%x", vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, gfp_flags); |
1da177e4c
|
342 |
|
9b3f26c91
|
343 344 345 |
/* deny if page is being written to the cache and the caller hasn't * elected to wait */ #ifdef CONFIG_AFS_FSCACHE |
201a15428
|
346 347 348 |
if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { _leave(" = F [cache busy]"); return 0; |
9b3f26c91
|
349 350 |
} #endif |
1da177e4c
|
351 |
if (PagePrivate(page)) { |
9b3f26c91
|
352 353 354 355 |
if (wb) { set_page_private(page, 0); afs_put_writeback(wb); } |
1da177e4c
|
356 |
ClearPagePrivate(page); |
1da177e4c
|
357 |
} |
9b3f26c91
|
358 359 360 |
/* indicate that the page can be released */ _leave(" = T"); return 1; |
ec26815ad
|
361 |
} |