summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-04-06 09:17:25 -0400
committerDavid Howells <dhowells@redhat.com>2018-04-09 16:54:48 -0400
commitf3ddee8dc4e2cff37936afbeed2fdaa95b7fb7c6 (patch)
treee077005245794c5cacfc36eb6100cb3c819a8954 /fs
parent66c7e1d319a5b3a57de688a36200e463ec87e88e (diff)
afs: Fix directory handling
AFS directories are structured blobs that are downloaded just like files and then parsed by the lookup and readdir code and, as such, are currently handled in the pagecache like any other file, with the entire directory content being thrown away each time the directory changes. However, since the blob is a known structure and since the data version counter on a directory increases by exactly one for each change committed to that directory, we can actually edit the directory locally rather than fetching it from the server after each locally-induced change. What we can't do, though, is mix data from the server and data from the client since the server is technically at liberty to rearrange or compress a directory if it sees fit, provided it updates the data version number when it does so and breaks the callback (ie. sends a notification). Further, lookup with lookup-ahead, readdir and, when it arrives, local editing are likely want to scan the whole of a directory. So directory handling needs to be improved to maintain the coherency of the directory blob prior to permitting local directory editing. To this end: (1) If any directory page gets discarded, invalidate and reread the entire directory. (2) If readpage notes that if when it fetches a single page that the version number has changed, the entire directory is flagged for invalidation. (3) Read as much of the directory in one go as we can. Note that this removes local caching of directories in fscache for the moment as we can't pass the pages to fscache_read_or_alloc_pages() since page->lru is in use by the LRU. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/dir.c294
-rw-r--r--fs/afs/file.c14
-rw-r--r--fs/afs/fsclient.c24
-rw-r--r--fs/afs/inode.c26
-rw-r--r--fs/afs/internal.h13
-rw-r--r--fs/afs/proc.c5
-rw-r--r--fs/afs/write.c3
7 files changed, 271 insertions, 108 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 405ebd609b87..8beecbcd9679 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -1,6 +1,6 @@
1/* dir.c: AFS filesystem directory handling 1/* dir.c: AFS filesystem directory handling
2 * 2 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2002, 2018 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
@@ -13,8 +13,10 @@
13#include <linux/fs.h> 13#include <linux/fs.h>
14#include <linux/namei.h> 14#include <linux/namei.h>
15#include <linux/pagemap.h> 15#include <linux/pagemap.h>
16#include <linux/swap.h>
16#include <linux/ctype.h> 17#include <linux/ctype.h>
17#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/task_io_accounting_ops.h>
18#include "internal.h" 20#include "internal.h"
19 21
20static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, 22static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
@@ -39,6 +41,14 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
39static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, 41static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
40 struct inode *new_dir, struct dentry *new_dentry, 42 struct inode *new_dir, struct dentry *new_dentry,
41 unsigned int flags); 43 unsigned int flags);
44static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags);
45static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
46 unsigned int length);
47
48static int afs_dir_set_page_dirty(struct page *page)
49{
50 BUG(); /* This should never happen. */
51}
42 52
43const struct file_operations afs_dir_file_operations = { 53const struct file_operations afs_dir_file_operations = {
44 .open = afs_dir_open, 54 .open = afs_dir_open,
@@ -63,6 +73,12 @@ const struct inode_operations afs_dir_inode_operations = {
63 .listxattr = afs_listxattr, 73 .listxattr = afs_listxattr,
64}; 74};
65 75
76const struct address_space_operations afs_dir_aops = {
77 .set_page_dirty = afs_dir_set_page_dirty,
78 .releasepage = afs_dir_releasepage,
79 .invalidatepage = afs_dir_invalidatepage,
80};
81
66const struct dentry_operations afs_fs_dentry_operations = { 82const struct dentry_operations afs_fs_dentry_operations = {
67 .d_revalidate = afs_d_revalidate, 83 .d_revalidate = afs_d_revalidate,
68 .d_delete = afs_d_delete, 84 .d_delete = afs_d_delete,
@@ -140,32 +156,17 @@ struct afs_lookup_cookie {
140/* 156/*
141 * check that a directory page is valid 157 * check that a directory page is valid
142 */ 158 */
143bool afs_dir_check_page(struct inode *dir, struct page *page) 159static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
160 loff_t i_size)
144{ 161{
145 struct afs_dir_page *dbuf; 162 struct afs_dir_page *dbuf;
146 struct afs_vnode *vnode = AFS_FS_I(dir); 163 loff_t latter, off;
147 loff_t latter, i_size, off;
148 int tmp, qty; 164 int tmp, qty;
149 165
150#if 0
151 /* check the page count */
152 qty = desc.size / sizeof(dbuf->blocks[0]);
153 if (qty == 0)
154 goto error;
155
156 if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) {
157 printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
158 __func__, dir->i_ino, qty,
159 ntohs(dbuf->blocks[0].pagehdr.npages));
160 goto error;
161 }
162#endif
163
164 /* Determine how many magic numbers there should be in this page, but 166 /* Determine how many magic numbers there should be in this page, but
165 * we must take care because the directory may change size under us. 167 * we must take care because the directory may change size under us.
166 */ 168 */
167 off = page_offset(page); 169 off = page_offset(page);
168 i_size = i_size_read(dir);
169 if (i_size <= off) 170 if (i_size <= off)
170 goto checked; 171 goto checked;
171 172
@@ -181,60 +182,22 @@ bool afs_dir_check_page(struct inode *dir, struct page *page)
181 for (tmp = 0; tmp < qty; tmp++) { 182 for (tmp = 0; tmp < qty; tmp++) {
182 if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) { 183 if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
183 printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", 184 printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n",
184 __func__, dir->i_ino, tmp, qty, 185 __func__, dvnode->vfs_inode.i_ino, tmp, qty,
185 ntohs(dbuf->blocks[tmp].pagehdr.magic)); 186 ntohs(dbuf->blocks[tmp].pagehdr.magic));
186 trace_afs_dir_check_failed(vnode, off, i_size); 187 trace_afs_dir_check_failed(dvnode, off, i_size);
187 goto error; 188 goto error;
188 } 189 }
189 } 190 }
190 191
191checked: 192checked:
192 afs_stat_v(vnode, n_read_dir); 193 afs_stat_v(dvnode, n_read_dir);
193 SetPageChecked(page);
194 return true; 194 return true;
195 195
196error: 196error:
197 SetPageError(page);
198 return false; 197 return false;
199} 198}
200 199
201/* 200/*
202 * discard a page cached in the pagecache
203 */
204static inline void afs_dir_put_page(struct page *page)
205{
206 kunmap(page);
207 unlock_page(page);
208 put_page(page);
209}
210
211/*
212 * get a page into the pagecache
213 */
214static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
215 struct key *key)
216{
217 struct page *page;
218 _enter("{%lu},%lu", dir->i_ino, index);
219
220 page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
221 if (!IS_ERR(page)) {
222 lock_page(page);
223 kmap(page);
224 if (unlikely(!PageChecked(page))) {
225 if (PageError(page))
226 goto fail;
227 }
228 }
229 return page;
230
231fail:
232 afs_dir_put_page(page);
233 _leave(" = -EIO");
234 return ERR_PTR(-EIO);
235}
236
237/*
238 * open an AFS directory file 201 * open an AFS directory file
239 */ 202 */
240static int afs_dir_open(struct inode *inode, struct file *file) 203static int afs_dir_open(struct inode *inode, struct file *file)
@@ -251,6 +214,147 @@ static int afs_dir_open(struct inode *inode, struct file *file)
251} 214}
252 215
253/* 216/*
217 * Read the directory into the pagecache in one go, scrubbing the previous
218 * contents. The list of pages is returned, pinning them so that they don't
219 * get reclaimed during the iteration.
220 */
221static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
222{
223 struct afs_read *req;
224 loff_t i_size;
225 int nr_pages, nr_inline, i, n;
226 int ret = -ENOMEM;
227
228retry:
229 i_size = i_size_read(&dvnode->vfs_inode);
230 if (i_size < 2048)
231 return ERR_PTR(-EIO);
232 if (i_size > 2048 * 1024)
233 return ERR_PTR(-EFBIG);
234
235 _enter("%llu", i_size);
236
237 /* Get a request record to hold the page list. We want to hold it
238 * inline if we can, but we don't want to make an order 1 allocation.
239 */
240 nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE;
241 nr_inline = nr_pages;
242 if (nr_inline > (PAGE_SIZE - sizeof(*req)) / sizeof(struct page *))
243 nr_inline = 0;
244
245 req = kzalloc(sizeof(*req) + sizeof(struct page *) * nr_inline,
246 GFP_KERNEL);
247 if (!req)
248 return ERR_PTR(-ENOMEM);
249
250 refcount_set(&req->usage, 1);
251 req->nr_pages = nr_pages;
252 req->actual_len = i_size; /* May change */
253 req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */
254 req->data_version = dvnode->status.data_version; /* May change */
255 if (nr_inline > 0) {
256 req->pages = req->array;
257 } else {
258 req->pages = kcalloc(nr_pages, sizeof(struct page *),
259 GFP_KERNEL);
260 if (!req->pages)
261 goto error;
262 }
263
264 /* Get a list of all the pages that hold or will hold the directory
265 * content. We need to fill in any gaps that we might find where the
266 * memory reclaimer has been at work. If there are any gaps, we will
267 * need to reread the entire directory contents.
268 */
269 i = 0;
270 do {
271 n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i,
272 req->nr_pages - i,
273 req->pages + i);
274 _debug("find %u at %u/%u", n, i, req->nr_pages);
275 if (n == 0) {
276 gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask;
277
278 if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
279 afs_stat_v(dvnode, n_inval);
280
281 ret = -ENOMEM;
282 req->pages[i] = __page_cache_alloc(gfp);
283 if (!req->pages[i])
284 goto error;
285 ret = add_to_page_cache_lru(req->pages[i],
286 dvnode->vfs_inode.i_mapping,
287 i, gfp);
288 if (ret < 0)
289 goto error;
290
291 set_page_private(req->pages[i], 1);
292 SetPagePrivate(req->pages[i]);
293 unlock_page(req->pages[i]);
294 i++;
295 } else {
296 i += n;
297 }
298 } while (i < req->nr_pages);
299
300 /* If we're going to reload, we need to lock all the pages to prevent
301 * races.
302 */
303 if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
304 ret = -ERESTARTSYS;
305 for (i = 0; i < req->nr_pages; i++)
306 if (lock_page_killable(req->pages[i]) < 0)
307 goto error_unlock;
308
309 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
310 goto success;
311
312 ret = afs_fetch_data(dvnode, key, req);
313 if (ret < 0)
314 goto error_unlock_all;
315
316 task_io_account_read(PAGE_SIZE * req->nr_pages);
317
318 if (req->len < req->file_size)
319 goto content_has_grown;
320
321 /* Validate the data we just read. */
322 ret = -EIO;
323 for (i = 0; i < req->nr_pages; i++)
324 if (!afs_dir_check_page(dvnode, req->pages[i],
325 req->actual_len))
326 goto error_unlock_all;
327
328 // TODO: Trim excess pages
329
330 set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags);
331 }
332
333success:
334 i = req->nr_pages;
335 while (i > 0)
336 unlock_page(req->pages[--i]);
337 return req;
338
339error_unlock_all:
340 i = req->nr_pages;
341error_unlock:
342 while (i > 0)
343 unlock_page(req->pages[--i]);
344error:
345 afs_put_read(req);
346 _leave(" = %d", ret);
347 return ERR_PTR(ret);
348
349content_has_grown:
350 i = req->nr_pages;
351 while (i > 0)
352 unlock_page(req->pages[--i]);
353 afs_put_read(req);
354 goto retry;
355}
356
357/*
254 * deal with one block in an AFS directory 358 * deal with one block in an AFS directory
255 */ 359 */
256static int afs_dir_iterate_block(struct dir_context *ctx, 360static int afs_dir_iterate_block(struct dir_context *ctx,
@@ -347,8 +451,10 @@ static int afs_dir_iterate_block(struct dir_context *ctx,
347static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, 451static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
348 struct key *key) 452 struct key *key)
349{ 453{
454 struct afs_vnode *dvnode = AFS_FS_I(dir);
350 union afs_dir_block *dblock; 455 union afs_dir_block *dblock;
351 struct afs_dir_page *dbuf; 456 struct afs_dir_page *dbuf;
457 struct afs_read *req;
352 struct page *page; 458 struct page *page;
353 unsigned blkoff, limit; 459 unsigned blkoff, limit;
354 int ret; 460 int ret;
@@ -360,25 +466,32 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
360 return -ESTALE; 466 return -ESTALE;
361 } 467 }
362 468
469 req = afs_read_dir(dvnode, key);
470 if (IS_ERR(req))
471 return PTR_ERR(req);
472
363 /* round the file position up to the next entry boundary */ 473 /* round the file position up to the next entry boundary */
364 ctx->pos += sizeof(union afs_dirent) - 1; 474 ctx->pos += sizeof(union afs_dirent) - 1;
365 ctx->pos &= ~(sizeof(union afs_dirent) - 1); 475 ctx->pos &= ~(sizeof(union afs_dirent) - 1);
366 476
367 /* walk through the blocks in sequence */ 477 /* walk through the blocks in sequence */
368 ret = 0; 478 ret = 0;
369 while (ctx->pos < dir->i_size) { 479 while (ctx->pos < req->actual_len) {
370 blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1); 480 blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);
371 481
372 /* fetch the appropriate page from the directory */ 482 /* Fetch the appropriate page from the directory and re-add it
373 page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); 483 * to the LRU.
374 if (IS_ERR(page)) { 484 */
375 ret = PTR_ERR(page); 485 page = req->pages[blkoff / PAGE_SIZE];
486 if (!page) {
487 ret = -EIO;
376 break; 488 break;
377 } 489 }
490 mark_page_accessed(page);
378 491
379 limit = blkoff & ~(PAGE_SIZE - 1); 492 limit = blkoff & ~(PAGE_SIZE - 1);
380 493
381 dbuf = page_address(page); 494 dbuf = kmap(page);
382 495
383 /* deal with the individual blocks stashed on this page */ 496 /* deal with the individual blocks stashed on this page */
384 do { 497 do {
@@ -386,7 +499,7 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
386 sizeof(union afs_dir_block)]; 499 sizeof(union afs_dir_block)];
387 ret = afs_dir_iterate_block(ctx, dblock, blkoff); 500 ret = afs_dir_iterate_block(ctx, dblock, blkoff);
388 if (ret != 1) { 501 if (ret != 1) {
389 afs_dir_put_page(page); 502 kunmap(page);
390 goto out; 503 goto out;
391 } 504 }
392 505
@@ -394,11 +507,12 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
394 507
395 } while (ctx->pos < dir->i_size && blkoff < limit); 508 } while (ctx->pos < dir->i_size && blkoff < limit);
396 509
397 afs_dir_put_page(page); 510 kunmap(page);
398 ret = 0; 511 ret = 0;
399 } 512 }
400 513
401out: 514out:
515 afs_put_read(req);
402 _leave(" = %d", ret); 516 _leave(" = %d", ret);
403 return ret; 517 return ret;
404} 518}
@@ -1491,3 +1605,47 @@ error:
1491 _leave(" = %d", ret); 1605 _leave(" = %d", ret);
1492 return ret; 1606 return ret;
1493} 1607}
1608
1609/*
1610 * Release a directory page and clean up its private state if it's not busy
1611 * - return true if the page can now be released, false if not
1612 */
1613static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags)
1614{
1615 struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host);
1616
1617 _enter("{{%x:%u}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index);
1618
1619 set_page_private(page, 0);
1620 ClearPagePrivate(page);
1621
1622 /* The directory will need reloading. */
1623 if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1624 afs_stat_v(dvnode, n_relpg);
1625 return 1;
1626}
1627
1628/*
1629 * invalidate part or all of a page
1630 * - release a page and clean up its private data if offset is 0 (indicating
1631 * the entire page)
1632 */
1633static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
1634 unsigned int length)
1635{
1636 struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host);
1637
1638 _enter("{%lu},%u,%u", page->index, offset, length);
1639
1640 BUG_ON(!PageLocked(page));
1641
1642 /* The directory will need reloading. */
1643 if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1644 afs_stat_v(dvnode, n_inval);
1645
1646 /* we clean up only if the entire page is being invalidated */
1647 if (offset == 0 && length == PAGE_SIZE) {
1648 set_page_private(page, 0);
1649 ClearPagePrivate(page);
1650 }
1651}
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 79e665a35fea..91ff1335fd33 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -187,10 +187,12 @@ void afs_put_read(struct afs_read *req)
187{ 187{
188 int i; 188 int i;
189 189
190 if (atomic_dec_and_test(&req->usage)) { 190 if (refcount_dec_and_test(&req->usage)) {
191 for (i = 0; i < req->nr_pages; i++) 191 for (i = 0; i < req->nr_pages; i++)
192 if (req->pages[i]) 192 if (req->pages[i])
193 put_page(req->pages[i]); 193 put_page(req->pages[i]);
194 if (req->pages != req->array)
195 kfree(req->pages);
194 kfree(req); 196 kfree(req);
195 } 197 }
196} 198}
@@ -297,10 +299,11 @@ int afs_page_filler(void *data, struct page *page)
297 * end of the file, the server will return a short read and the 299 * end of the file, the server will return a short read and the
298 * unmarshalling code will clear the unfilled space. 300 * unmarshalling code will clear the unfilled space.
299 */ 301 */
300 atomic_set(&req->usage, 1); 302 refcount_set(&req->usage, 1);
301 req->pos = (loff_t)page->index << PAGE_SHIFT; 303 req->pos = (loff_t)page->index << PAGE_SHIFT;
302 req->len = PAGE_SIZE; 304 req->len = PAGE_SIZE;
303 req->nr_pages = 1; 305 req->nr_pages = 1;
306 req->pages = req->array;
304 req->pages[0] = page; 307 req->pages[0] = page;
305 get_page(page); 308 get_page(page);
306 309
@@ -309,10 +312,6 @@ int afs_page_filler(void *data, struct page *page)
309 ret = afs_fetch_data(vnode, key, req); 312 ret = afs_fetch_data(vnode, key, req);
310 afs_put_read(req); 313 afs_put_read(req);
311 314
312 if (ret >= 0 && S_ISDIR(inode->i_mode) &&
313 !afs_dir_check_page(inode, page))
314 ret = -EIO;
315
316 if (ret < 0) { 315 if (ret < 0) {
317 if (ret == -ENOENT) { 316 if (ret == -ENOENT) {
318 _debug("got NOENT from server" 317 _debug("got NOENT from server"
@@ -447,10 +446,11 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping,
447 if (!req) 446 if (!req)
448 return -ENOMEM; 447 return -ENOMEM;
449 448
450 atomic_set(&req->usage, 1); 449 refcount_set(&req->usage, 1);
451 req->page_done = afs_readpages_page_done; 450 req->page_done = afs_readpages_page_done;
452 req->pos = first->index; 451 req->pos = first->index;
453 req->pos <<= PAGE_SHIFT; 452 req->pos <<= PAGE_SHIFT;
453 req->pages = req->array;
454 454
455 /* Transfer the pages to the request. We add them in until one fails 455 /* Transfer the pages to the request. We add them in until one fails
456 * to add to the LRU and then we stop (as that'll make a hole in the 456 * to add to the LRU and then we stop (as that'll make a hole in the
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index f7570d229dcc..b66ff0dc8a5a 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -101,8 +101,12 @@ void afs_update_inode_from_status(struct afs_vnode *vnode,
101 vnode->fid.vid, vnode->fid.vnode, 101 vnode->fid.vid, vnode->fid.vnode,
102 (unsigned long long) *expected_version); 102 (unsigned long long) *expected_version);
103 vnode->invalid_before = status->data_version; 103 vnode->invalid_before = status->data_version;
104 set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags); 104 if (vnode->status.type == AFS_FTYPE_DIR) {
105 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 105 if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
106 afs_stat_v(vnode, n_inval);
107 } else {
108 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
109 }
106 } 110 }
107 } 111 }
108 112
@@ -119,7 +123,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
119 struct afs_file_status *status, 123 struct afs_file_status *status,
120 struct afs_vnode *vnode, 124 struct afs_vnode *vnode,
121 const afs_dataversion_t *expected_version, 125 const afs_dataversion_t *expected_version,
122 afs_dataversion_t *_version) 126 struct afs_read *read_req)
123{ 127{
124 const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; 128 const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
125 u64 data_version, size; 129 u64 data_version, size;
@@ -197,8 +201,11 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
197 status->data_version = data_version; 201 status->data_version = data_version;
198 flags |= AFS_VNODE_DATA_CHANGED; 202 flags |= AFS_VNODE_DATA_CHANGED;
199 } 203 }
200 if (_version) 204
201 *_version = data_version; 205 if (read_req) {
206 read_req->data_version = data_version;
207 read_req->file_size = size;
208 }
202 209
203 *_bp = (const void *)*_bp + sizeof(*xdr); 210 *_bp = (const void *)*_bp + sizeof(*xdr);
204 211
@@ -543,8 +550,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
543 550
544 bp = call->buffer; 551 bp = call->buffer;
545 if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, 552 if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
546 &vnode->status.data_version, 553 &vnode->status.data_version, req) < 0)
547 &req->new_version) < 0)
548 return -EBADMSG; 554 return -EBADMSG;
549 xdr_decode_AFSCallBack(call, vnode, &bp); 555 xdr_decode_AFSCallBack(call, vnode, &bp);
550 if (call->reply[1]) 556 if (call->reply[1])
@@ -628,7 +634,7 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
628 bp[6] = 0; 634 bp[6] = 0;
629 bp[7] = htonl(lower_32_bits(req->len)); 635 bp[7] = htonl(lower_32_bits(req->len));
630 636
631 atomic_inc(&req->usage); 637 refcount_inc(&req->usage);
632 call->cb_break = fc->cb_break; 638 call->cb_break = fc->cb_break;
633 afs_use_fs_server(call, fc->cbi); 639 afs_use_fs_server(call, fc->cbi);
634 trace_afs_make_fs_call(call, &vnode->fid); 640 trace_afs_make_fs_call(call, &vnode->fid);
@@ -671,7 +677,7 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
671 bp[4] = htonl(lower_32_bits(req->pos)); 677 bp[4] = htonl(lower_32_bits(req->pos));
672 bp[5] = htonl(lower_32_bits(req->len)); 678 bp[5] = htonl(lower_32_bits(req->len));
673 679
674 atomic_inc(&req->usage); 680 refcount_inc(&req->usage);
675 call->cb_break = fc->cb_break; 681 call->cb_break = fc->cb_break;
676 afs_use_fs_server(call, fc->cbi); 682 afs_use_fs_server(call, fc->cbi);
677 trace_afs_make_fs_call(call, &vnode->fid); 683 trace_afs_make_fs_call(call, &vnode->fid);
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 07f450513f3e..69bcfb82dd69 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -53,11 +53,13 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key)
53 inode->i_mode = S_IFREG | vnode->status.mode; 53 inode->i_mode = S_IFREG | vnode->status.mode;
54 inode->i_op = &afs_file_inode_operations; 54 inode->i_op = &afs_file_inode_operations;
55 inode->i_fop = &afs_file_operations; 55 inode->i_fop = &afs_file_operations;
56 inode->i_mapping->a_ops = &afs_fs_aops;
56 break; 57 break;
57 case AFS_FTYPE_DIR: 58 case AFS_FTYPE_DIR:
58 inode->i_mode = S_IFDIR | vnode->status.mode; 59 inode->i_mode = S_IFDIR | vnode->status.mode;
59 inode->i_op = &afs_dir_inode_operations; 60 inode->i_op = &afs_dir_inode_operations;
60 inode->i_fop = &afs_dir_file_operations; 61 inode->i_fop = &afs_dir_file_operations;
62 inode->i_mapping->a_ops = &afs_dir_aops;
61 break; 63 break;
62 case AFS_FTYPE_SYMLINK: 64 case AFS_FTYPE_SYMLINK:
63 /* Symlinks with a mode of 0644 are actually mountpoints. */ 65 /* Symlinks with a mode of 0644 are actually mountpoints. */
@@ -69,9 +71,11 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key)
69 inode->i_mode = S_IFDIR | 0555; 71 inode->i_mode = S_IFDIR | 0555;
70 inode->i_op = &afs_mntpt_inode_operations; 72 inode->i_op = &afs_mntpt_inode_operations;
71 inode->i_fop = &afs_mntpt_file_operations; 73 inode->i_fop = &afs_mntpt_file_operations;
74 inode->i_mapping->a_ops = &afs_fs_aops;
72 } else { 75 } else {
73 inode->i_mode = S_IFLNK | vnode->status.mode; 76 inode->i_mode = S_IFLNK | vnode->status.mode;
74 inode->i_op = &afs_symlink_inode_operations; 77 inode->i_op = &afs_symlink_inode_operations;
78 inode->i_mapping->a_ops = &afs_fs_aops;
75 } 79 }
76 inode_nohighmem(inode); 80 inode_nohighmem(inode);
77 break; 81 break;
@@ -82,15 +86,9 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key)
82 } 86 }
83 87
84 inode->i_blocks = 0; 88 inode->i_blocks = 0;
85 inode->i_mapping->a_ops = &afs_fs_aops;
86 vnode->invalid_before = vnode->status.data_version; 89 vnode->invalid_before = vnode->status.data_version;
87 90
88 read_sequnlock_excl(&vnode->cb_lock); 91 read_sequnlock_excl(&vnode->cb_lock);
89
90#ifdef CONFIG_AFS_FSCACHE
91 if (vnode->status.size > 0)
92 fscache_attr_changed(vnode->cache);
93#endif
94 return 0; 92 return 0;
95} 93}
96 94
@@ -247,6 +245,11 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)
247 } __packed key; 245 } __packed key;
248 struct afs_vnode_cache_aux aux; 246 struct afs_vnode_cache_aux aux;
249 247
248 if (vnode->status.type == AFS_FTYPE_DIR) {
249 vnode->cache = NULL;
250 return;
251 }
252
250 key.vnode_id = vnode->fid.vnode; 253 key.vnode_id = vnode->fid.vnode;
251 key.unique = vnode->fid.unique; 254 key.unique = vnode->fid.unique;
252 key.vnode_id_ext[0] = 0; 255 key.vnode_id_ext[0] = 0;
@@ -338,10 +341,6 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
338 341
339 /* failure */ 342 /* failure */
340bad_inode: 343bad_inode:
341#ifdef CONFIG_AFS_FSCACHE
342 fscache_relinquish_cookie(vnode->cache, NULL, ret == -ENOENT);
343 vnode->cache = NULL;
344#endif
345 iget_failed(inode); 344 iget_failed(inode);
346 _leave(" = %d [bad]", ret); 345 _leave(" = %d [bad]", ret);
347 return ERR_PTR(ret); 346 return ERR_PTR(ret);
@@ -355,9 +354,6 @@ void afs_zap_data(struct afs_vnode *vnode)
355{ 354{
356 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); 355 _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
357 356
358 if (S_ISDIR(vnode->vfs_inode.i_mode))
359 afs_stat_v(vnode, n_inval);
360
361#ifdef CONFIG_AFS_FSCACHE 357#ifdef CONFIG_AFS_FSCACHE
362 fscache_invalidate(vnode->cache); 358 fscache_invalidate(vnode->cache);
363#endif 359#endif
@@ -399,7 +395,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
399 if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 395 if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
400 if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { 396 if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) {
401 vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; 397 vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
402 } else if (!test_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags) && 398 } else if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) &&
403 !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && 399 !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
404 vnode->cb_expires_at - 10 > now) { 400 vnode->cb_expires_at - 10 > now) {
405 valid = true; 401 valid = true;
@@ -445,8 +441,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
445 * different */ 441 * different */
446 if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) 442 if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
447 afs_zap_data(vnode); 443 afs_zap_data(vnode);
448
449 clear_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
450 mutex_unlock(&vnode->validate_lock); 444 mutex_unlock(&vnode->validate_lock);
451valid: 445valid:
452 _leave(" = 0"); 446 _leave(" = 0");
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index b6ec46ae03c3..86f3066d9ab0 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -174,12 +174,14 @@ struct afs_read {
174 loff_t len; /* How much we're asking for */ 174 loff_t len; /* How much we're asking for */
175 loff_t actual_len; /* How much we're actually getting */ 175 loff_t actual_len; /* How much we're actually getting */
176 loff_t remain; /* Amount remaining */ 176 loff_t remain; /* Amount remaining */
177 afs_dataversion_t new_version; /* Version number returned by server */ 177 loff_t file_size; /* File size returned by server */
178 atomic_t usage; 178 afs_dataversion_t data_version; /* Version number returned by server */
179 refcount_t usage;
179 unsigned int index; /* Which page we're reading into */ 180 unsigned int index; /* Which page we're reading into */
180 unsigned int nr_pages; 181 unsigned int nr_pages;
181 void (*page_done)(struct afs_call *, struct afs_read *); 182 void (*page_done)(struct afs_call *, struct afs_read *);
182 struct page *pages[]; 183 struct page **pages;
184 struct page *array[];
183}; 185};
184 186
185/* 187/*
@@ -267,6 +269,7 @@ struct afs_net {
267 atomic_t n_lookup; /* Number of lookups done */ 269 atomic_t n_lookup; /* Number of lookups done */
268 atomic_t n_reval; /* Number of dentries needing revalidation */ 270 atomic_t n_reval; /* Number of dentries needing revalidation */
269 atomic_t n_inval; /* Number of invalidations by the server */ 271 atomic_t n_inval; /* Number of invalidations by the server */
272 atomic_t n_relpg; /* Number of invalidations by releasepage */
270 atomic_t n_read_dir; /* Number of directory pages read */ 273 atomic_t n_read_dir; /* Number of directory pages read */
271}; 274};
272 275
@@ -491,7 +494,7 @@ struct afs_vnode {
491 unsigned long flags; 494 unsigned long flags;
492#define AFS_VNODE_CB_PROMISED 0 /* Set if vnode has a callback promise */ 495#define AFS_VNODE_CB_PROMISED 0 /* Set if vnode has a callback promise */
493#define AFS_VNODE_UNSET 1 /* set if vnode attributes not yet set */ 496#define AFS_VNODE_UNSET 1 /* set if vnode attributes not yet set */
494#define AFS_VNODE_DIR_MODIFIED 2 /* set if dir vnode's data modified */ 497#define AFS_VNODE_DIR_VALID 2 /* Set if dir contents are valid */
495#define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */ 498#define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */
496#define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */ 499#define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */
497#define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */ 500#define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */
@@ -671,9 +674,9 @@ extern bool afs_cm_incoming_call(struct afs_call *);
671 */ 674 */
672extern const struct file_operations afs_dir_file_operations; 675extern const struct file_operations afs_dir_file_operations;
673extern const struct inode_operations afs_dir_inode_operations; 676extern const struct inode_operations afs_dir_inode_operations;
677extern const struct address_space_operations afs_dir_aops;
674extern const struct dentry_operations afs_fs_dentry_operations; 678extern const struct dentry_operations afs_fs_dentry_operations;
675 679
676extern bool afs_dir_check_page(struct inode *, struct page *);
677extern void afs_d_release(struct dentry *); 680extern void afs_d_release(struct dentry *);
678 681
679/* 682/*
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 8bffb17f9728..6f5a000f44a7 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -910,10 +910,11 @@ static int afs_proc_stats_show(struct seq_file *m, void *v)
910 910
911 seq_puts(m, "kAFS statistics\n"); 911 seq_puts(m, "kAFS statistics\n");
912 912
913 seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u\n", 913 seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n",
914 atomic_read(&net->n_lookup), 914 atomic_read(&net->n_lookup),
915 atomic_read(&net->n_reval), 915 atomic_read(&net->n_reval),
916 atomic_read(&net->n_inval)); 916 atomic_read(&net->n_inval),
917 atomic_read(&net->n_relpg));
917 918
918 seq_printf(m, "dir-data: rdpg=%u\n", 919 seq_printf(m, "dir-data: rdpg=%u\n",
919 atomic_read(&net->n_read_dir)); 920 atomic_read(&net->n_read_dir));
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 9370e2feb999..70a563c14e6f 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -42,10 +42,11 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
42 if (!req) 42 if (!req)
43 return -ENOMEM; 43 return -ENOMEM;
44 44
45 atomic_set(&req->usage, 1); 45 refcount_set(&req->usage, 1);
46 req->pos = pos; 46 req->pos = pos;
47 req->len = len; 47 req->len = len;
48 req->nr_pages = 1; 48 req->nr_pages = 1;
49 req->pages = req->array;
49 req->pages[0] = page; 50 req->pages[0] = page;
50 get_page(page); 51 get_page(page);
51 52