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 | |
| 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')
| -rw-r--r-- | fs/ncpfs/dir.c | 98 | ||||
| -rw-r--r-- | fs/ncpfs/ncp_fs_i.h | 1 | ||||
| -rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 30 |
3 files changed, 52 insertions, 77 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: |
diff --git a/fs/ncpfs/ncp_fs_i.h b/fs/ncpfs/ncp_fs_i.h index 4b0bec477846..c4794504f843 100644 --- a/fs/ncpfs/ncp_fs_i.h +++ b/fs/ncpfs/ncp_fs_i.h | |||
| @@ -22,6 +22,7 @@ struct ncp_inode_info { | |||
| 22 | int access; | 22 | int access; |
| 23 | int flags; | 23 | int flags; |
| 24 | #define NCPI_KLUDGE_SYMLINK 0x0001 | 24 | #define NCPI_KLUDGE_SYMLINK 0x0001 |
| 25 | #define NCPI_DIR_CACHE 0x0002 | ||
| 25 | __u8 file_handle[6]; | 26 | __u8 file_handle[6]; |
| 26 | struct inode vfs_inode; | 27 | struct inode vfs_inode; |
| 27 | }; | 28 | }; |
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index b785f74bfe3c..250e443a07f3 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h | |||
| @@ -184,36 +184,6 @@ ncp_new_dentry(struct dentry* dentry) | |||
| 184 | dentry->d_time = jiffies; | 184 | dentry->d_time = jiffies; |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | static inline void | ||
| 188 | ncp_renew_dentries(struct dentry *parent) | ||
| 189 | { | ||
| 190 | struct ncp_server *server = NCP_SERVER(parent->d_inode); | ||
| 191 | struct dentry *dentry; | ||
| 192 | |||
| 193 | spin_lock(&parent->d_lock); | ||
| 194 | list_for_each_entry(dentry, &parent->d_subdirs, d_child) { | ||
| 195 | if (dentry->d_fsdata == NULL) | ||
| 196 | ncp_age_dentry(server, dentry); | ||
| 197 | else | ||
| 198 | ncp_new_dentry(dentry); | ||
| 199 | } | ||
| 200 | spin_unlock(&parent->d_lock); | ||
| 201 | } | ||
| 202 | |||
| 203 | static inline void | ||
| 204 | ncp_invalidate_dircache_entries(struct dentry *parent) | ||
| 205 | { | ||
| 206 | struct ncp_server *server = NCP_SERVER(parent->d_inode); | ||
| 207 | struct dentry *dentry; | ||
| 208 | |||
| 209 | spin_lock(&parent->d_lock); | ||
| 210 | list_for_each_entry(dentry, &parent->d_subdirs, d_child) { | ||
| 211 | dentry->d_fsdata = NULL; | ||
| 212 | ncp_age_dentry(server, dentry); | ||
| 213 | } | ||
| 214 | spin_unlock(&parent->d_lock); | ||
| 215 | } | ||
| 216 | |||
| 217 | struct ncp_cache_head { | 187 | struct ncp_cache_head { |
| 218 | time_t mtime; | 188 | time_t mtime; |
| 219 | unsigned long time; /* cache age */ | 189 | unsigned long time; /* cache age */ |
