diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-24 21:41:47 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-01-25 23:16:26 -0500 |
commit | 5e993e2534e29b62790f9a2908b551b7fb3a63f0 (patch) | |
tree | 3278906dba789c91609feb98f636538031e61dd8 /fs/ncpfs/dir.c | |
parent | ad52184b705c1048aa01225eccde119ef5c93000 (diff) |
ncpfs: get rid of d_validate() nonsense
What we want is to have non-counting references to children in
pagecache of parent directory, and avoid picking them after a child
has been freed. Fine, so let's just have ->d_prune() clear
parent's inode "has directory contents in page cache" flag.
That way we don't need ->d_fsdata for storing offsets, so we can
use it as a quick and dirty "is it referenced from page cache"
flag.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ncpfs/dir.c')
-rw-r--r-- | fs/ncpfs/dir.c | 98 |
1 files changed, 51 insertions, 47 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 008960101520..e7ca827d7694 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
@@ -77,6 +77,7 @@ static int ncp_hash_dentry(const struct dentry *, struct qstr *); | |||
77 | static int ncp_compare_dentry(const struct dentry *, const struct dentry *, | 77 | static int ncp_compare_dentry(const struct dentry *, const struct dentry *, |
78 | unsigned int, const char *, const struct qstr *); | 78 | unsigned int, const char *, const struct qstr *); |
79 | static int ncp_delete_dentry(const struct dentry *); | 79 | static int ncp_delete_dentry(const struct dentry *); |
80 | static void ncp_d_prune(struct dentry *dentry); | ||
80 | 81 | ||
81 | const struct dentry_operations ncp_dentry_operations = | 82 | const struct dentry_operations ncp_dentry_operations = |
82 | { | 83 | { |
@@ -84,6 +85,7 @@ const struct dentry_operations ncp_dentry_operations = | |||
84 | .d_hash = ncp_hash_dentry, | 85 | .d_hash = ncp_hash_dentry, |
85 | .d_compare = ncp_compare_dentry, | 86 | .d_compare = ncp_compare_dentry, |
86 | .d_delete = ncp_delete_dentry, | 87 | .d_delete = ncp_delete_dentry, |
88 | .d_prune = ncp_d_prune, | ||
87 | }; | 89 | }; |
88 | 90 | ||
89 | #define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber]) | 91 | #define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber]) |
@@ -384,42 +386,6 @@ finished: | |||
384 | return val; | 386 | return val; |
385 | } | 387 | } |
386 | 388 | ||
387 | static struct dentry * | ||
388 | ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | ||
389 | { | ||
390 | struct dentry *dent = dentry; | ||
391 | |||
392 | if (d_validate(dent, parent)) { | ||
393 | if (dent->d_name.len <= NCP_MAXPATHLEN && | ||
394 | (unsigned long)dent->d_fsdata == fpos) { | ||
395 | if (!dent->d_inode) { | ||
396 | dput(dent); | ||
397 | dent = NULL; | ||
398 | } | ||
399 | return dent; | ||
400 | } | ||
401 | dput(dent); | ||
402 | } | ||
403 | |||
404 | /* If a pointer is invalid, we search the dentry. */ | ||
405 | spin_lock(&parent->d_lock); | ||
406 | list_for_each_entry(dent, &parent->d_subdirs, d_child) { | ||
407 | if ((unsigned long)dent->d_fsdata == fpos) { | ||
408 | if (dent->d_inode) | ||
409 | dget(dent); | ||
410 | else | ||
411 | dent = NULL; | ||
412 | spin_unlock(&parent->d_lock); | ||
413 | goto out; | ||
414 | } | ||
415 | } | ||
416 | spin_unlock(&parent->d_lock); | ||
417 | return NULL; | ||
418 | |||
419 | out: | ||
420 | return dent; | ||
421 | } | ||
422 | |||
423 | static time_t ncp_obtain_mtime(struct dentry *dentry) | 389 | static time_t ncp_obtain_mtime(struct dentry *dentry) |
424 | { | 390 | { |
425 | struct inode *inode = dentry->d_inode; | 391 | struct inode *inode = dentry->d_inode; |
@@ -435,6 +401,20 @@ static time_t ncp_obtain_mtime(struct dentry *dentry) | |||
435 | return ncp_date_dos2unix(i.modifyTime, i.modifyDate); | 401 | return ncp_date_dos2unix(i.modifyTime, i.modifyDate); |
436 | } | 402 | } |
437 | 403 | ||
404 | static inline void | ||
405 | ncp_invalidate_dircache_entries(struct dentry *parent) | ||
406 | { | ||
407 | struct ncp_server *server = NCP_SERVER(parent->d_inode); | ||
408 | struct dentry *dentry; | ||
409 | |||
410 | spin_lock(&parent->d_lock); | ||
411 | list_for_each_entry(dentry, &parent->d_subdirs, d_child) { | ||
412 | dentry->d_fsdata = NULL; | ||
413 | ncp_age_dentry(server, dentry); | ||
414 | } | ||
415 | spin_unlock(&parent->d_lock); | ||
416 | } | ||
417 | |||
438 | static int ncp_readdir(struct file *file, struct dir_context *ctx) | 418 | static int ncp_readdir(struct file *file, struct dir_context *ctx) |
439 | { | 419 | { |
440 | struct dentry *dentry = file->f_path.dentry; | 420 | struct dentry *dentry = file->f_path.dentry; |
@@ -500,10 +480,21 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx) | |||
500 | struct dentry *dent; | 480 | struct dentry *dent; |
501 | bool over; | 481 | bool over; |
502 | 482 | ||
503 | dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], | 483 | spin_lock(&dentry->d_lock); |
504 | dentry, ctx->pos); | 484 | if (!(NCP_FINFO(inode)->flags & NCPI_DIR_CACHE)) { |
505 | if (!dent) | 485 | spin_unlock(&dentry->d_lock); |
486 | goto invalid_cache; | ||
487 | } | ||
488 | dent = ctl.cache->dentry[ctl.idx]; | ||
489 | if (unlikely(!lockref_get_not_dead(&dent->d_lockref))) { | ||
490 | spin_unlock(&dentry->d_lock); | ||
491 | goto invalid_cache; | ||
492 | } | ||
493 | spin_unlock(&dentry->d_lock); | ||
494 | if (!dent->d_inode) { | ||
495 | dput(dent); | ||
506 | goto invalid_cache; | 496 | goto invalid_cache; |
497 | } | ||
507 | over = !dir_emit(ctx, dent->d_name.name, | 498 | over = !dir_emit(ctx, dent->d_name.name, |
508 | dent->d_name.len, | 499 | dent->d_name.len, |
509 | dent->d_inode->i_ino, DT_UNKNOWN); | 500 | dent->d_inode->i_ino, DT_UNKNOWN); |
@@ -548,6 +539,9 @@ init_cache: | |||
548 | ctl.filled = 0; | 539 | ctl.filled = 0; |
549 | ctl.valid = 1; | 540 | ctl.valid = 1; |
550 | read_really: | 541 | read_really: |
542 | spin_lock(&dentry->d_lock); | ||
543 | NCP_FINFO(inode)->flags |= NCPI_DIR_CACHE; | ||
544 | spin_unlock(&dentry->d_lock); | ||
551 | if (ncp_is_server_root(inode)) { | 545 | if (ncp_is_server_root(inode)) { |
552 | ncp_read_volume_list(file, ctx, &ctl); | 546 | ncp_read_volume_list(file, ctx, &ctl); |
553 | } else { | 547 | } else { |
@@ -573,6 +567,13 @@ out: | |||
573 | return result; | 567 | return result; |
574 | } | 568 | } |
575 | 569 | ||
570 | static void ncp_d_prune(struct dentry *dentry) | ||
571 | { | ||
572 | if (!dentry->d_fsdata) /* not referenced from page cache */ | ||
573 | return; | ||
574 | NCP_FINFO(dentry->d_parent->d_inode)->flags &= ~NCPI_DIR_CACHE; | ||
575 | } | ||
576 | |||
576 | static int | 577 | static int |
577 | ncp_fill_cache(struct file *file, struct dir_context *ctx, | 578 | ncp_fill_cache(struct file *file, struct dir_context *ctx, |
578 | struct ncp_cache_control *ctrl, struct ncp_entry_info *entry, | 579 | struct ncp_cache_control *ctrl, struct ncp_entry_info *entry, |
@@ -630,6 +631,10 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, | |||
630 | d_instantiate(newdent, inode); | 631 | d_instantiate(newdent, inode); |
631 | if (!hashed) | 632 | if (!hashed) |
632 | d_rehash(newdent); | 633 | d_rehash(newdent); |
634 | } else { | ||
635 | spin_lock(&dentry->d_lock); | ||
636 | NCP_FINFO(inode)->flags &= ~NCPI_DIR_CACHE; | ||
637 | spin_unlock(&dentry->d_lock); | ||
633 | } | 638 | } |
634 | } else { | 639 | } else { |
635 | struct inode *inode = newdent->d_inode; | 640 | struct inode *inode = newdent->d_inode; |
@@ -639,12 +644,6 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, | |||
639 | mutex_unlock(&inode->i_mutex); | 644 | mutex_unlock(&inode->i_mutex); |
640 | } | 645 | } |
641 | 646 | ||
642 | if (newdent->d_inode) { | ||
643 | ino = newdent->d_inode->i_ino; | ||
644 | newdent->d_fsdata = (void *) ctl.fpos; | ||
645 | ncp_new_dentry(newdent); | ||
646 | } | ||
647 | |||
648 | if (ctl.idx >= NCP_DIRCACHE_SIZE) { | 647 | if (ctl.idx >= NCP_DIRCACHE_SIZE) { |
649 | if (ctl.page) { | 648 | if (ctl.page) { |
650 | kunmap(ctl.page); | 649 | kunmap(ctl.page); |
@@ -660,8 +659,13 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, | |||
660 | ctl.cache = kmap(ctl.page); | 659 | ctl.cache = kmap(ctl.page); |
661 | } | 660 | } |
662 | if (ctl.cache) { | 661 | if (ctl.cache) { |
663 | ctl.cache->dentry[ctl.idx] = newdent; | 662 | if (newdent->d_inode) { |
664 | valid = 1; | 663 | newdent->d_fsdata = newdent; |
664 | ctl.cache->dentry[ctl.idx] = newdent; | ||
665 | ino = newdent->d_inode->i_ino; | ||
666 | ncp_new_dentry(newdent); | ||
667 | } | ||
668 | valid = 1; | ||
665 | } | 669 | } |
666 | dput(newdent); | 670 | dput(newdent); |
667 | end_advance: | 671 | end_advance: |