aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ncpfs/dir.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-12-24 21:41:47 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2015-01-25 23:16:26 -0500
commit5e993e2534e29b62790f9a2908b551b7fb3a63f0 (patch)
tree3278906dba789c91609feb98f636538031e61dd8 /fs/ncpfs/dir.c
parentad52184b705c1048aa01225eccde119ef5c93000 (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.c98
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 *);
77static int ncp_compare_dentry(const struct dentry *, const struct dentry *, 77static 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 *);
79static int ncp_delete_dentry(const struct dentry *); 79static int ncp_delete_dentry(const struct dentry *);
80static void ncp_d_prune(struct dentry *dentry);
80 81
81const struct dentry_operations ncp_dentry_operations = 82const 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
387static struct dentry *
388ncp_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
419out:
420 return dent;
421}
422
423static time_t ncp_obtain_mtime(struct dentry *dentry) 389static 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
404static inline void
405ncp_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
438static int ncp_readdir(struct file *file, struct dir_context *ctx) 418static 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;
550read_really: 541read_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
570static 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
576static int 577static int
577ncp_fill_cache(struct file *file, struct dir_context *ctx, 578ncp_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);
667end_advance: 671end_advance: