diff options
author | David Howells <dhowells@redhat.com> | 2007-04-26 18:55:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-04-26 18:55:03 -0400 |
commit | 08e0e7c82eeadec6f4871a386b86bf0f0fbcb4eb (patch) | |
tree | 1c4f7e91e20e56ff2ec755e988a6ee828b1a21c0 /fs/afs/dir.c | |
parent | 651350d10f93bed7003c9a66e24cf25e0f8eed3d (diff) |
[AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC.
Make the in-kernel AFS filesystem use AF_RXRPC instead of the old RxRPC code.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs/afs/dir.c')
-rw-r--r-- | fs/afs/dir.c | 286 |
1 files changed, 178 insertions, 108 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 2f6d92376461..d7697f6f3b7f 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -15,11 +15,6 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/smp_lock.h> | ||
19 | #include "vnode.h" | ||
20 | #include "volume.h" | ||
21 | #include <rxrpc/call.h> | ||
22 | #include "super.h" | ||
23 | #include "internal.h" | 18 | #include "internal.h" |
24 | 19 | ||
25 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | 20 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, |
@@ -127,9 +122,10 @@ static inline void afs_dir_check_page(struct inode *dir, struct page *page) | |||
127 | if (qty == 0) | 122 | if (qty == 0) |
128 | goto error; | 123 | goto error; |
129 | 124 | ||
130 | if (page->index==0 && qty!=ntohs(dbuf->blocks[0].pagehdr.npages)) { | 125 | if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) { |
131 | printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n", | 126 | printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n", |
132 | __FUNCTION__,dir->i_ino,qty,ntohs(dbuf->blocks[0].pagehdr.npages)); | 127 | __FUNCTION__, dir->i_ino, qty, |
128 | ntohs(dbuf->blocks[0].pagehdr.npages)); | ||
133 | goto error; | 129 | goto error; |
134 | } | 130 | } |
135 | #endif | 131 | #endif |
@@ -194,6 +190,7 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) | |||
194 | 190 | ||
195 | fail: | 191 | fail: |
196 | afs_dir_put_page(page); | 192 | afs_dir_put_page(page); |
193 | _leave(" = -EIO"); | ||
197 | return ERR_PTR(-EIO); | 194 | return ERR_PTR(-EIO); |
198 | } | 195 | } |
199 | 196 | ||
@@ -207,7 +204,7 @@ static int afs_dir_open(struct inode *inode, struct file *file) | |||
207 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | 204 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); |
208 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | 205 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); |
209 | 206 | ||
210 | if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) | 207 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) |
211 | return -ENOENT; | 208 | return -ENOENT; |
212 | 209 | ||
213 | _leave(" = 0"); | 210 | _leave(" = 0"); |
@@ -242,7 +239,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
242 | /* skip entries marked unused in the bitmap */ | 239 | /* skip entries marked unused in the bitmap */ |
243 | if (!(block->pagehdr.bitmap[offset / 8] & | 240 | if (!(block->pagehdr.bitmap[offset / 8] & |
244 | (1 << (offset % 8)))) { | 241 | (1 << (offset % 8)))) { |
245 | _debug("ENT[%Zu.%u]: unused\n", | 242 | _debug("ENT[%Zu.%u]: unused", |
246 | blkoff / sizeof(union afs_dir_block), offset); | 243 | blkoff / sizeof(union afs_dir_block), offset); |
247 | if (offset >= curr) | 244 | if (offset >= curr) |
248 | *fpos = blkoff + | 245 | *fpos = blkoff + |
@@ -256,7 +253,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
256 | sizeof(*block) - | 253 | sizeof(*block) - |
257 | offset * sizeof(union afs_dirent)); | 254 | offset * sizeof(union afs_dirent)); |
258 | 255 | ||
259 | _debug("ENT[%Zu.%u]: %s %Zu \"%s\"\n", | 256 | _debug("ENT[%Zu.%u]: %s %Zu \"%s\"", |
260 | blkoff / sizeof(union afs_dir_block), offset, | 257 | blkoff / sizeof(union afs_dir_block), offset, |
261 | (offset < curr ? "skip" : "fill"), | 258 | (offset < curr ? "skip" : "fill"), |
262 | nlen, dire->u.name); | 259 | nlen, dire->u.name); |
@@ -266,7 +263,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
266 | if (next >= AFS_DIRENT_PER_BLOCK) { | 263 | if (next >= AFS_DIRENT_PER_BLOCK) { |
267 | _debug("ENT[%Zu.%u]:" | 264 | _debug("ENT[%Zu.%u]:" |
268 | " %u travelled beyond end dir block" | 265 | " %u travelled beyond end dir block" |
269 | " (len %u/%Zu)\n", | 266 | " (len %u/%Zu)", |
270 | blkoff / sizeof(union afs_dir_block), | 267 | blkoff / sizeof(union afs_dir_block), |
271 | offset, next, tmp, nlen); | 268 | offset, next, tmp, nlen); |
272 | return -EIO; | 269 | return -EIO; |
@@ -274,13 +271,13 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
274 | if (!(block->pagehdr.bitmap[next / 8] & | 271 | if (!(block->pagehdr.bitmap[next / 8] & |
275 | (1 << (next % 8)))) { | 272 | (1 << (next % 8)))) { |
276 | _debug("ENT[%Zu.%u]:" | 273 | _debug("ENT[%Zu.%u]:" |
277 | " %u unmarked extension (len %u/%Zu)\n", | 274 | " %u unmarked extension (len %u/%Zu)", |
278 | blkoff / sizeof(union afs_dir_block), | 275 | blkoff / sizeof(union afs_dir_block), |
279 | offset, next, tmp, nlen); | 276 | offset, next, tmp, nlen); |
280 | return -EIO; | 277 | return -EIO; |
281 | } | 278 | } |
282 | 279 | ||
283 | _debug("ENT[%Zu.%u]: ext %u/%Zu\n", | 280 | _debug("ENT[%Zu.%u]: ext %u/%Zu", |
284 | blkoff / sizeof(union afs_dir_block), | 281 | blkoff / sizeof(union afs_dir_block), |
285 | next, tmp, nlen); | 282 | next, tmp, nlen); |
286 | next++; | 283 | next++; |
@@ -311,12 +308,12 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
311 | } | 308 | } |
312 | 309 | ||
313 | /* | 310 | /* |
314 | * read an AFS directory | 311 | * iterate through the data blob that lists the contents of an AFS directory |
315 | */ | 312 | */ |
316 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | 313 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, |
317 | filldir_t filldir) | 314 | filldir_t filldir) |
318 | { | 315 | { |
319 | union afs_dir_block *dblock; | 316 | union afs_dir_block *dblock; |
320 | struct afs_dir_page *dbuf; | 317 | struct afs_dir_page *dbuf; |
321 | struct page *page; | 318 | struct page *page; |
322 | unsigned blkoff, limit; | 319 | unsigned blkoff, limit; |
@@ -324,7 +321,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | |||
324 | 321 | ||
325 | _enter("{%lu},%u,,", dir->i_ino, *fpos); | 322 | _enter("{%lu},%u,,", dir->i_ino, *fpos); |
326 | 323 | ||
327 | if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) { | 324 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { |
328 | _leave(" = -ESTALE"); | 325 | _leave(" = -ESTALE"); |
329 | return -ESTALE; | 326 | return -ESTALE; |
330 | } | 327 | } |
@@ -381,10 +378,12 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir) | |||
381 | unsigned fpos; | 378 | unsigned fpos; |
382 | int ret; | 379 | int ret; |
383 | 380 | ||
384 | _enter("{%Ld,{%lu}}", file->f_pos, file->f_path.dentry->d_inode->i_ino); | 381 | _enter("{%Ld,{%lu}}", |
382 | file->f_pos, file->f_path.dentry->d_inode->i_ino); | ||
385 | 383 | ||
386 | fpos = file->f_pos; | 384 | fpos = file->f_pos; |
387 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, cookie, filldir); | 385 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, |
386 | cookie, filldir); | ||
388 | file->f_pos = fpos; | 387 | file->f_pos = fpos; |
389 | 388 | ||
390 | _leave(" = %d", ret); | 389 | _leave(" = %d", ret); |
@@ -401,9 +400,13 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
401 | { | 400 | { |
402 | struct afs_dir_lookup_cookie *cookie = _cookie; | 401 | struct afs_dir_lookup_cookie *cookie = _cookie; |
403 | 402 | ||
404 | _enter("{%s,%Zu},%s,%u,,%lu,%u", | 403 | _enter("{%s,%Zu},%s,%u,,%llu,%u", |
405 | cookie->name, cookie->nlen, name, nlen, ino, dtype); | 404 | cookie->name, cookie->nlen, name, nlen, ino, dtype); |
406 | 405 | ||
406 | /* insanity checks first */ | ||
407 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | ||
408 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | ||
409 | |||
407 | if (cookie->nlen != nlen || memcmp(cookie->name, name, nlen) != 0) { | 410 | if (cookie->nlen != nlen || memcmp(cookie->name, name, nlen) != 0) { |
408 | _leave(" = 0 [no]"); | 411 | _leave(" = 0 [no]"); |
409 | return 0; | 412 | return 0; |
@@ -418,34 +421,17 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
418 | } | 421 | } |
419 | 422 | ||
420 | /* | 423 | /* |
421 | * look up an entry in a directory | 424 | * do a lookup in a directory |
422 | */ | 425 | */ |
423 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | 426 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, |
424 | struct nameidata *nd) | 427 | struct afs_fid *fid) |
425 | { | 428 | { |
426 | struct afs_dir_lookup_cookie cookie; | 429 | struct afs_dir_lookup_cookie cookie; |
427 | struct afs_super_info *as; | 430 | struct afs_super_info *as; |
428 | struct afs_vnode *vnode; | ||
429 | struct inode *inode; | ||
430 | unsigned fpos; | 431 | unsigned fpos; |
431 | int ret; | 432 | int ret; |
432 | 433 | ||
433 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); | 434 | _enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name); |
434 | |||
435 | /* insanity checks first */ | ||
436 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | ||
437 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | ||
438 | |||
439 | if (dentry->d_name.len > 255) { | ||
440 | _leave(" = -ENAMETOOLONG"); | ||
441 | return ERR_PTR(-ENAMETOOLONG); | ||
442 | } | ||
443 | |||
444 | vnode = AFS_FS_I(dir); | ||
445 | if (vnode->flags & AFS_VNODE_DELETED) { | ||
446 | _leave(" = -ESTALE"); | ||
447 | return ERR_PTR(-ESTALE); | ||
448 | } | ||
449 | 435 | ||
450 | as = dir->i_sb->s_fs_info; | 436 | as = dir->i_sb->s_fs_info; |
451 | 437 | ||
@@ -458,30 +444,64 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
458 | fpos = 0; | 444 | fpos = 0; |
459 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir); | 445 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir); |
460 | if (ret < 0) { | 446 | if (ret < 0) { |
461 | _leave(" = %d", ret); | 447 | _leave(" = %d [iter]", ret); |
462 | return ERR_PTR(ret); | 448 | return ret; |
463 | } | 449 | } |
464 | 450 | ||
465 | ret = -ENOENT; | 451 | ret = -ENOENT; |
466 | if (!cookie.found) { | 452 | if (!cookie.found) { |
467 | _leave(" = %d", ret); | 453 | _leave(" = -ENOENT [not found]"); |
468 | return ERR_PTR(ret); | 454 | return -ENOENT; |
469 | } | 455 | } |
470 | 456 | ||
471 | /* instantiate the dentry */ | 457 | *fid = cookie.fid; |
472 | ret = afs_iget(dir->i_sb, &cookie.fid, &inode); | 458 | _leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique); |
459 | return 0; | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * look up an entry in a directory | ||
464 | */ | ||
465 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | ||
466 | struct nameidata *nd) | ||
467 | { | ||
468 | struct afs_vnode *vnode; | ||
469 | struct afs_fid fid; | ||
470 | struct inode *inode; | ||
471 | int ret; | ||
472 | |||
473 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); | ||
474 | |||
475 | if (dentry->d_name.len > 255) { | ||
476 | _leave(" = -ENAMETOOLONG"); | ||
477 | return ERR_PTR(-ENAMETOOLONG); | ||
478 | } | ||
479 | |||
480 | vnode = AFS_FS_I(dir); | ||
481 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | ||
482 | _leave(" = -ESTALE"); | ||
483 | return ERR_PTR(-ESTALE); | ||
484 | } | ||
485 | |||
486 | ret = afs_do_lookup(dir, dentry, &fid); | ||
473 | if (ret < 0) { | 487 | if (ret < 0) { |
474 | _leave(" = %d", ret); | 488 | _leave(" = %d [do]", ret); |
475 | return ERR_PTR(ret); | 489 | return ERR_PTR(ret); |
476 | } | 490 | } |
477 | 491 | ||
492 | /* instantiate the dentry */ | ||
493 | inode = afs_iget(dir->i_sb, &fid); | ||
494 | if (IS_ERR(inode)) { | ||
495 | _leave(" = %ld", PTR_ERR(inode)); | ||
496 | return ERR_PTR(PTR_ERR(inode)); | ||
497 | } | ||
498 | |||
478 | dentry->d_op = &afs_fs_dentry_operations; | 499 | dentry->d_op = &afs_fs_dentry_operations; |
479 | dentry->d_fsdata = (void *) (unsigned long) vnode->status.version; | ||
480 | 500 | ||
481 | d_add(dentry, inode); | 501 | d_add(dentry, inode); |
482 | _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }", | 502 | _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }", |
483 | cookie.fid.vnode, | 503 | fid.vnode, |
484 | cookie.fid.unique, | 504 | fid.unique, |
485 | dentry->d_inode->i_ino, | 505 | dentry->d_inode->i_ino, |
486 | dentry->d_inode->i_version); | 506 | dentry->d_inode->i_version); |
487 | 507 | ||
@@ -489,23 +509,65 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
489 | } | 509 | } |
490 | 510 | ||
491 | /* | 511 | /* |
512 | * propagate changed and modified flags on a directory to all the children of | ||
513 | * that directory as they may indicate that the ACL on the dir has changed, | ||
514 | * potentially rendering the child inaccessible or that a file has been deleted | ||
515 | * or renamed | ||
516 | */ | ||
517 | static void afs_propagate_dir_changes(struct dentry *dir) | ||
518 | { | ||
519 | struct dentry *child; | ||
520 | bool c, m; | ||
521 | |||
522 | c = test_bit(AFS_VNODE_CHANGED, &AFS_FS_I(dir->d_inode)->flags); | ||
523 | m = test_bit(AFS_VNODE_MODIFIED, &AFS_FS_I(dir->d_inode)->flags); | ||
524 | |||
525 | _enter("{%d,%d}", c, m); | ||
526 | |||
527 | spin_lock(&dir->d_lock); | ||
528 | |||
529 | list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) { | ||
530 | if (child->d_inode) { | ||
531 | struct afs_vnode *vnode; | ||
532 | |||
533 | _debug("tag %s", child->d_name.name); | ||
534 | vnode = AFS_FS_I(child->d_inode); | ||
535 | if (c) | ||
536 | set_bit(AFS_VNODE_DIR_CHANGED, &vnode->flags); | ||
537 | if (m) | ||
538 | set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | spin_unlock(&dir->d_lock); | ||
543 | } | ||
544 | |||
545 | /* | ||
492 | * check that a dentry lookup hit has found a valid entry | 546 | * check that a dentry lookup hit has found a valid entry |
493 | * - NOTE! the hit can be a negative hit too, so we can't assume we have an | 547 | * - NOTE! the hit can be a negative hit too, so we can't assume we have an |
494 | * inode | 548 | * inode |
495 | * (derived from nfs_lookup_revalidate) | 549 | * - there are several things we need to check |
550 | * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, | ||
551 | * symlink) | ||
552 | * - parent dir metadata changed (security changes) | ||
553 | * - dentry data changed (write, truncate) | ||
554 | * - dentry metadata changed (security changes) | ||
496 | */ | 555 | */ |
497 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | 556 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) |
498 | { | 557 | { |
499 | struct afs_dir_lookup_cookie cookie; | 558 | struct afs_vnode *vnode; |
559 | struct afs_fid fid; | ||
500 | struct dentry *parent; | 560 | struct dentry *parent; |
501 | struct inode *inode, *dir; | 561 | struct inode *inode, *dir; |
502 | unsigned fpos; | ||
503 | int ret; | 562 | int ret; |
504 | 563 | ||
505 | _enter("{sb=%p n=%s},", dentry->d_sb, dentry->d_name.name); | 564 | vnode = AFS_FS_I(dentry->d_inode); |
565 | |||
566 | _enter("{sb=%p n=%s fl=%lx},", | ||
567 | dentry->d_sb, dentry->d_name.name, vnode->flags); | ||
506 | 568 | ||
507 | /* lock down the parent dentry so we can peer at it */ | 569 | /* lock down the parent dentry so we can peer at it */ |
508 | parent = dget_parent(dentry->d_parent); | 570 | parent = dget_parent(dentry); |
509 | 571 | ||
510 | dir = parent->d_inode; | 572 | dir = parent->d_inode; |
511 | inode = dentry->d_inode; | 573 | inode = dentry->d_inode; |
@@ -517,81 +579,92 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
517 | /* handle a bad inode */ | 579 | /* handle a bad inode */ |
518 | if (is_bad_inode(inode)) { | 580 | if (is_bad_inode(inode)) { |
519 | printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n", | 581 | printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n", |
520 | dentry->d_parent->d_name.name, dentry->d_name.name); | 582 | parent->d_name.name, dentry->d_name.name); |
521 | goto out_bad; | 583 | goto out_bad; |
522 | } | 584 | } |
523 | 585 | ||
524 | /* force a full look up if the parent directory changed since last the | 586 | /* check that this dirent still exists if the directory's contents were |
525 | * server was consulted | 587 | * modified */ |
526 | * - otherwise this inode must still exist, even if the inode details | 588 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { |
527 | * themselves have changed | ||
528 | */ | ||
529 | if (AFS_FS_I(dir)->flags & AFS_VNODE_CHANGED) | ||
530 | afs_vnode_fetch_status(AFS_FS_I(dir)); | ||
531 | |||
532 | if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) { | ||
533 | _debug("%s: parent dir deleted", dentry->d_name.name); | 589 | _debug("%s: parent dir deleted", dentry->d_name.name); |
534 | goto out_bad; | 590 | goto out_bad; |
535 | } | 591 | } |
536 | 592 | ||
537 | if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) { | 593 | if (test_and_clear_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags)) { |
538 | _debug("%s: file already deleted", dentry->d_name.name); | 594 | /* rm/rmdir/rename may have occurred */ |
539 | goto out_bad; | 595 | _debug("dir modified"); |
540 | } | ||
541 | |||
542 | if ((unsigned long) dentry->d_fsdata != | ||
543 | (unsigned long) AFS_FS_I(dir)->status.version) { | ||
544 | _debug("%s: parent changed %lu -> %u", | ||
545 | dentry->d_name.name, | ||
546 | (unsigned long) dentry->d_fsdata, | ||
547 | (unsigned) AFS_FS_I(dir)->status.version); | ||
548 | 596 | ||
549 | /* search the directory for this vnode */ | 597 | /* search the directory for this vnode */ |
550 | cookie.name = dentry->d_name.name; | 598 | ret = afs_do_lookup(dir, dentry, &fid); |
551 | cookie.nlen = dentry->d_name.len; | 599 | if (ret == -ENOENT) { |
552 | cookie.fid.vid = AFS_FS_I(inode)->volume->vid; | 600 | _debug("%s: dirent not found", dentry->d_name.name); |
553 | cookie.found = 0; | 601 | goto not_found; |
554 | 602 | } | |
555 | fpos = 0; | ||
556 | ret = afs_dir_iterate(dir, &fpos, &cookie, | ||
557 | afs_dir_lookup_filldir); | ||
558 | if (ret < 0) { | 603 | if (ret < 0) { |
559 | _debug("failed to iterate dir %s: %d", | 604 | _debug("failed to iterate dir %s: %d", |
560 | parent->d_name.name, ret); | 605 | parent->d_name.name, ret); |
561 | goto out_bad; | 606 | goto out_bad; |
562 | } | 607 | } |
563 | 608 | ||
564 | if (!cookie.found) { | ||
565 | _debug("%s: dirent not found", dentry->d_name.name); | ||
566 | goto not_found; | ||
567 | } | ||
568 | |||
569 | /* if the vnode ID has changed, then the dirent points to a | 609 | /* if the vnode ID has changed, then the dirent points to a |
570 | * different file */ | 610 | * different file */ |
571 | if (cookie.fid.vnode != AFS_FS_I(inode)->fid.vnode) { | 611 | if (fid.vnode != vnode->fid.vnode) { |
572 | _debug("%s: dirent changed", dentry->d_name.name); | 612 | _debug("%s: dirent changed [%u != %u]", |
613 | dentry->d_name.name, fid.vnode, | ||
614 | vnode->fid.vnode); | ||
573 | goto not_found; | 615 | goto not_found; |
574 | } | 616 | } |
575 | 617 | ||
576 | /* if the vnode ID uniqifier has changed, then the file has | 618 | /* if the vnode ID uniqifier has changed, then the file has |
577 | * been deleted */ | 619 | * been deleted */ |
578 | if (cookie.fid.unique != AFS_FS_I(inode)->fid.unique) { | 620 | if (fid.unique != vnode->fid.unique) { |
579 | _debug("%s: file deleted (uq %u -> %u I:%lu)", | 621 | _debug("%s: file deleted (uq %u -> %u I:%lu)", |
580 | dentry->d_name.name, | 622 | dentry->d_name.name, fid.unique, |
581 | cookie.fid.unique, | 623 | vnode->fid.unique, inode->i_version); |
582 | AFS_FS_I(inode)->fid.unique, | 624 | spin_lock(&vnode->lock); |
583 | inode->i_version); | 625 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
584 | spin_lock(&AFS_FS_I(inode)->lock); | 626 | spin_unlock(&vnode->lock); |
585 | AFS_FS_I(inode)->flags |= AFS_VNODE_DELETED; | ||
586 | spin_unlock(&AFS_FS_I(inode)->lock); | ||
587 | invalidate_remote_inode(inode); | 627 | invalidate_remote_inode(inode); |
588 | goto out_bad; | 628 | goto out_bad; |
589 | } | 629 | } |
630 | } | ||
631 | |||
632 | /* if the directory's metadata were changed then the security may be | ||
633 | * different and we may no longer have access */ | ||
634 | mutex_lock(&vnode->cb_broken_lock); | ||
590 | 635 | ||
591 | dentry->d_fsdata = | 636 | if (test_and_clear_bit(AFS_VNODE_DIR_CHANGED, &vnode->flags) || |
592 | (void *) (unsigned long) AFS_FS_I(dir)->status.version; | 637 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { |
638 | _debug("%s: changed", dentry->d_name.name); | ||
639 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
640 | if (afs_vnode_fetch_status(vnode) < 0) { | ||
641 | mutex_unlock(&vnode->cb_broken_lock); | ||
642 | goto out_bad; | ||
643 | } | ||
593 | } | 644 | } |
594 | 645 | ||
646 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | ||
647 | _debug("%s: file already deleted", dentry->d_name.name); | ||
648 | mutex_unlock(&vnode->cb_broken_lock); | ||
649 | goto out_bad; | ||
650 | } | ||
651 | |||
652 | /* if the vnode's data version number changed then its contents are | ||
653 | * different */ | ||
654 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | ||
655 | _debug("zap data"); | ||
656 | invalidate_remote_inode(inode); | ||
657 | } | ||
658 | |||
659 | if (S_ISDIR(inode->i_mode) && | ||
660 | (test_bit(AFS_VNODE_CHANGED, &vnode->flags) || | ||
661 | test_bit(AFS_VNODE_MODIFIED, &vnode->flags))) | ||
662 | afs_propagate_dir_changes(dentry); | ||
663 | |||
664 | clear_bit(AFS_VNODE_CHANGED, &vnode->flags); | ||
665 | clear_bit(AFS_VNODE_MODIFIED, &vnode->flags); | ||
666 | mutex_unlock(&vnode->cb_broken_lock); | ||
667 | |||
595 | out_valid: | 668 | out_valid: |
596 | dput(parent); | 669 | dput(parent); |
597 | _leave(" = 1 [valid]"); | 670 | _leave(" = 1 [valid]"); |
@@ -610,12 +683,10 @@ out_bad: | |||
610 | goto out_valid; | 683 | goto out_valid; |
611 | } | 684 | } |
612 | 685 | ||
613 | shrink_dcache_parent(dentry); | ||
614 | |||
615 | _debug("dropping dentry %s/%s", | 686 | _debug("dropping dentry %s/%s", |
616 | dentry->d_parent->d_name.name, dentry->d_name.name); | 687 | parent->d_name.name, dentry->d_name.name); |
688 | shrink_dcache_parent(dentry); | ||
617 | d_drop(dentry); | 689 | d_drop(dentry); |
618 | |||
619 | dput(parent); | 690 | dput(parent); |
620 | 691 | ||
621 | _leave(" = 0 [bad]"); | 692 | _leave(" = 0 [bad]"); |
@@ -635,10 +706,9 @@ static int afs_d_delete(struct dentry *dentry) | |||
635 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | 706 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) |
636 | goto zap; | 707 | goto zap; |
637 | 708 | ||
638 | if (dentry->d_inode) { | 709 | if (dentry->d_inode && |
639 | if (AFS_FS_I(dentry->d_inode)->flags & AFS_VNODE_DELETED) | 710 | test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags)) |
640 | goto zap; | 711 | goto zap; |
641 | } | ||
642 | 712 | ||
643 | _leave(" = 0 [keep]"); | 713 | _leave(" = 0 [keep]"); |
644 | return 0; | 714 | return 0; |