diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 17:56:45 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 17:56:45 -0500 |
| commit | 50652963eae6afe13678dc84d789a174306a4df7 (patch) | |
| tree | 44d6bc6c2cd938cf59db7ba2b7e514d9b3665f40 | |
| parent | e2b74f232e84dfccd0047eb47545b1d028df8ff1 (diff) | |
| parent | 87b95ce0964c016ede92763be9c164e49f1019e9 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc VFS updates from Al Viro:
"This cycle a lot of stuff sits on topical branches, so I'll be sending
more or less one pull request per branch.
This is the first pile; more to follow in a few. In this one are
several misc commits from early in the cycle (before I went for
separate branches), plus the rework of mntput/dput ordering on umount,
switching to use of fs_pin instead of convoluted games in
namespace_unlock()"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
switch the IO-triggering parts of umount to fs_pin
new fs_pin killing logics
allow attaching fs_pin to a group not associated with some superblock
get rid of the second argument of acct_kill()
take count and rcu_head out of fs_pin
dcache: let the dentry count go down to zero without taking d_lock
pull bumping refcount into ->kill()
kill pin_put()
mode_t whack-a-mole: chelsio
file->f_path.dentry is pinned down for as long as the file is open...
get rid of lustre_dump_dentry()
gut proc_register() a bit
kill d_validate()
ncpfs: get rid of d_validate() nonsense
selinuxfs: don't open-code d_genocide()
| -rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h | 2 | ||||
| -rw-r--r-- | drivers/staging/lustre/lustre/llite/dcache.c | 8 | ||||
| -rw-r--r-- | drivers/staging/lustre/lustre/llite/llite_internal.h | 1 | ||||
| -rw-r--r-- | drivers/staging/lustre/lustre/llite/llite_lib.c | 42 | ||||
| -rw-r--r-- | fs/dcache.c | 149 | ||||
| -rw-r--r-- | fs/fs_pin.c | 96 | ||||
| -rw-r--r-- | fs/internal.h | 2 | ||||
| -rw-r--r-- | fs/mount.h | 4 | ||||
| -rw-r--r-- | fs/namespace.c | 44 | ||||
| -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 | ||||
| -rw-r--r-- | fs/proc/generic.c | 25 | ||||
| -rw-r--r-- | fs/super.c | 4 | ||||
| -rw-r--r-- | include/linux/dcache.h | 3 | ||||
| -rw-r--r-- | include/linux/fs_pin.h | 25 | ||||
| -rw-r--r-- | include/linux/lockref.h | 3 | ||||
| -rw-r--r-- | include/linux/pid_namespace.h | 4 | ||||
| -rw-r--r-- | kernel/acct.c | 94 | ||||
| -rw-r--r-- | kernel/auditsc.c | 5 | ||||
| -rw-r--r-- | lib/lockref.c | 36 | ||||
| -rw-r--r-- | security/commoncap.c | 6 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 52 |
23 files changed, 356 insertions, 378 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h index b63cfee2d963..8f418ba868bd 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h | |||
| @@ -55,7 +55,7 @@ static const struct file_operations name##_debugfs_fops = { \ | |||
| 55 | struct t4_debugfs_entry { | 55 | struct t4_debugfs_entry { |
| 56 | const char *name; | 56 | const char *name; |
| 57 | const struct file_operations *ops; | 57 | const struct file_operations *ops; |
| 58 | mode_t mode; | 58 | umode_t mode; |
| 59 | unsigned char data; | 59 | unsigned char data; |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 5bb9c85cec81..88614b71cf6d 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c | |||
| @@ -263,14 +263,6 @@ void ll_invalidate_aliases(struct inode *inode) | |||
| 263 | dentry, dentry, dentry->d_parent, | 263 | dentry, dentry, dentry->d_parent, |
| 264 | dentry->d_inode, dentry->d_flags); | 264 | dentry->d_inode, dentry->d_flags); |
| 265 | 265 | ||
| 266 | if (unlikely(dentry == dentry->d_sb->s_root)) { | ||
| 267 | CERROR("%s: called on root dentry=%p, fid="DFID"\n", | ||
| 268 | ll_get_fsname(dentry->d_sb, NULL, 0), | ||
| 269 | dentry, PFID(ll_inode2fid(inode))); | ||
| 270 | lustre_dump_dentry(dentry, 1); | ||
| 271 | dump_stack(); | ||
| 272 | } | ||
| 273 | |||
| 274 | d_lustre_invalidate(dentry, 0); | 266 | d_lustre_invalidate(dentry, 0); |
| 275 | } | 267 | } |
| 276 | ll_unlock_dcache(inode); | 268 | ll_unlock_dcache(inode); |
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 37306e0c7aad..d032c2b086cc 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h | |||
| @@ -816,7 +816,6 @@ int ll_show_options(struct seq_file *seq, struct dentry *dentry); | |||
| 816 | void ll_dirty_page_discard_warn(struct page *page, int ioret); | 816 | void ll_dirty_page_discard_warn(struct page *page, int ioret); |
| 817 | int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, | 817 | int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, |
| 818 | struct super_block *, struct lookup_intent *); | 818 | struct super_block *, struct lookup_intent *); |
| 819 | void lustre_dump_dentry(struct dentry *, int recur); | ||
| 820 | int ll_obd_statfs(struct inode *inode, void *arg); | 819 | int ll_obd_statfs(struct inode *inode, void *arg); |
| 821 | int ll_get_max_mdsize(struct ll_sb_info *sbi, int *max_mdsize); | 820 | int ll_get_max_mdsize(struct ll_sb_info *sbi, int *max_mdsize); |
| 822 | int ll_get_default_mdsize(struct ll_sb_info *sbi, int *default_mdsize); | 821 | int ll_get_default_mdsize(struct ll_sb_info *sbi, int *default_mdsize); |
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 45aaa1cc56bc..0c1b583a4ea1 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c | |||
| @@ -665,48 +665,6 @@ int ll_get_default_cookiesize(struct ll_sb_info *sbi, int *lmmsize) | |||
| 665 | return rc; | 665 | return rc; |
| 666 | } | 666 | } |
| 667 | 667 | ||
| 668 | static void ll_dump_inode(struct inode *inode) | ||
| 669 | { | ||
| 670 | struct ll_d_hlist_node *tmp; | ||
| 671 | int dentry_count = 0; | ||
| 672 | |||
| 673 | LASSERT(inode != NULL); | ||
| 674 | |||
| 675 | ll_d_hlist_for_each(tmp, &inode->i_dentry) | ||
| 676 | dentry_count++; | ||
| 677 | |||
| 678 | CERROR("inode %p dump: dev=%s ino=%lu mode=%o count=%u, %d dentries\n", | ||
| 679 | inode, ll_i2mdexp(inode)->exp_obd->obd_name, inode->i_ino, | ||
| 680 | inode->i_mode, atomic_read(&inode->i_count), dentry_count); | ||
| 681 | } | ||
| 682 | |||
| 683 | void lustre_dump_dentry(struct dentry *dentry, int recur) | ||
| 684 | { | ||
| 685 | struct list_head *tmp; | ||
| 686 | int subdirs = 0; | ||
| 687 | |||
| 688 | LASSERT(dentry != NULL); | ||
| 689 | |||
| 690 | list_for_each(tmp, &dentry->d_subdirs) | ||
| 691 | subdirs++; | ||
| 692 | |||
| 693 | CERROR("dentry %p dump: name=%pd parent=%pd (%p), inode=%p, count=%u, flags=0x%x, fsdata=%p, %d subdirs\n", | ||
| 694 | dentry, dentry, dentry->d_parent, dentry->d_parent, | ||
| 695 | dentry->d_inode, d_count(dentry), | ||
| 696 | dentry->d_flags, dentry->d_fsdata, subdirs); | ||
| 697 | if (dentry->d_inode != NULL) | ||
| 698 | ll_dump_inode(dentry->d_inode); | ||
| 699 | |||
| 700 | if (recur == 0) | ||
| 701 | return; | ||
| 702 | |||
| 703 | list_for_each(tmp, &dentry->d_subdirs) { | ||
| 704 | struct dentry *d = list_entry(tmp, struct dentry, d_child); | ||
| 705 | |||
| 706 | lustre_dump_dentry(d, recur - 1); | ||
| 707 | } | ||
| 708 | } | ||
| 709 | |||
| 710 | static void client_common_put_super(struct super_block *sb) | 668 | static void client_common_put_super(struct super_block *sb) |
| 711 | { | 669 | { |
| 712 | struct ll_sb_info *sbi = ll_s2sbi(sb); | 670 | struct ll_sb_info *sbi = ll_s2sbi(sb); |
diff --git a/fs/dcache.c b/fs/dcache.c index 7d34f04ec7aa..dc400fd29f4d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -511,7 +511,7 @@ static void __dentry_kill(struct dentry *dentry) | |||
| 511 | * dentry_iput drops the locks, at which point nobody (except | 511 | * dentry_iput drops the locks, at which point nobody (except |
| 512 | * transient RCU lookups) can reach this dentry. | 512 | * transient RCU lookups) can reach this dentry. |
| 513 | */ | 513 | */ |
| 514 | BUG_ON((int)dentry->d_lockref.count > 0); | 514 | BUG_ON(dentry->d_lockref.count > 0); |
| 515 | this_cpu_dec(nr_dentry); | 515 | this_cpu_dec(nr_dentry); |
| 516 | if (dentry->d_op && dentry->d_op->d_release) | 516 | if (dentry->d_op && dentry->d_op->d_release) |
| 517 | dentry->d_op->d_release(dentry); | 517 | dentry->d_op->d_release(dentry); |
| @@ -564,7 +564,7 @@ static inline struct dentry *lock_parent(struct dentry *dentry) | |||
| 564 | struct dentry *parent = dentry->d_parent; | 564 | struct dentry *parent = dentry->d_parent; |
| 565 | if (IS_ROOT(dentry)) | 565 | if (IS_ROOT(dentry)) |
| 566 | return NULL; | 566 | return NULL; |
| 567 | if (unlikely((int)dentry->d_lockref.count < 0)) | 567 | if (unlikely(dentry->d_lockref.count < 0)) |
| 568 | return NULL; | 568 | return NULL; |
| 569 | if (likely(spin_trylock(&parent->d_lock))) | 569 | if (likely(spin_trylock(&parent->d_lock))) |
| 570 | return parent; | 570 | return parent; |
| @@ -593,6 +593,110 @@ again: | |||
| 593 | return parent; | 593 | return parent; |
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | /* | ||
| 597 | * Try to do a lockless dput(), and return whether that was successful. | ||
| 598 | * | ||
| 599 | * If unsuccessful, we return false, having already taken the dentry lock. | ||
| 600 | * | ||
| 601 | * The caller needs to hold the RCU read lock, so that the dentry is | ||
| 602 | * guaranteed to stay around even if the refcount goes down to zero! | ||
| 603 | */ | ||
| 604 | static inline bool fast_dput(struct dentry *dentry) | ||
| 605 | { | ||
| 606 | int ret; | ||
| 607 | unsigned int d_flags; | ||
| 608 | |||
| 609 | /* | ||
| 610 | * If we have a d_op->d_delete() operation, we sould not | ||
| 611 | * let the dentry count go to zero, so use "put__or_lock". | ||
| 612 | */ | ||
| 613 | if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) | ||
| 614 | return lockref_put_or_lock(&dentry->d_lockref); | ||
| 615 | |||
| 616 | /* | ||
| 617 | * .. otherwise, we can try to just decrement the | ||
| 618 | * lockref optimistically. | ||
| 619 | */ | ||
| 620 | ret = lockref_put_return(&dentry->d_lockref); | ||
| 621 | |||
| 622 | /* | ||
| 623 | * If the lockref_put_return() failed due to the lock being held | ||
| 624 | * by somebody else, the fast path has failed. We will need to | ||
| 625 | * get the lock, and then check the count again. | ||
| 626 | */ | ||
| 627 | if (unlikely(ret < 0)) { | ||
| 628 | spin_lock(&dentry->d_lock); | ||
| 629 | if (dentry->d_lockref.count > 1) { | ||
| 630 | dentry->d_lockref.count--; | ||
| 631 | spin_unlock(&dentry->d_lock); | ||
| 632 | return 1; | ||
| 633 | } | ||
| 634 | return 0; | ||
| 635 | } | ||
| 636 | |||
| 637 | /* | ||
| 638 | * If we weren't the last ref, we're done. | ||
| 639 | */ | ||
| 640 | if (ret) | ||
| 641 | return 1; | ||
| 642 | |||
| 643 | /* | ||
| 644 | * Careful, careful. The reference count went down | ||
| 645 | * to zero, but we don't hold the dentry lock, so | ||
| 646 | * somebody else could get it again, and do another | ||
| 647 | * dput(), and we need to not race with that. | ||
| 648 | * | ||
| 649 | * However, there is a very special and common case | ||
| 650 | * where we don't care, because there is nothing to | ||
| 651 | * do: the dentry is still hashed, it does not have | ||
| 652 | * a 'delete' op, and it's referenced and already on | ||
| 653 | * the LRU list. | ||
| 654 | * | ||
| 655 | * NOTE! Since we aren't locked, these values are | ||
| 656 | * not "stable". However, it is sufficient that at | ||
| 657 | * some point after we dropped the reference the | ||
| 658 | * dentry was hashed and the flags had the proper | ||
| 659 | * value. Other dentry users may have re-gotten | ||
| 660 | * a reference to the dentry and change that, but | ||
| 661 | * our work is done - we can leave the dentry | ||
| 662 | * around with a zero refcount. | ||
| 663 | */ | ||
| 664 | smp_rmb(); | ||
| 665 | d_flags = ACCESS_ONCE(dentry->d_flags); | ||
| 666 | d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST; | ||
| 667 | |||
| 668 | /* Nothing to do? Dropping the reference was all we needed? */ | ||
| 669 | if (d_flags == (DCACHE_REFERENCED | DCACHE_LRU_LIST) && !d_unhashed(dentry)) | ||
| 670 | return 1; | ||
| 671 | |||
| 672 | /* | ||
| 673 | * Not the fast normal case? Get the lock. We've already decremented | ||
| 674 | * the refcount, but we'll need to re-check the situation after | ||
| 675 | * getting the lock. | ||
| 676 | */ | ||
| 677 | spin_lock(&dentry->d_lock); | ||
| 678 | |||
| 679 | /* | ||
| 680 | * Did somebody else grab a reference to it in the meantime, and | ||
| 681 | * we're no longer the last user after all? Alternatively, somebody | ||
| 682 | * else could have killed it and marked it dead. Either way, we | ||
| 683 | * don't need to do anything else. | ||
| 684 | */ | ||
| 685 | if (dentry->d_lockref.count) { | ||
| 686 | spin_unlock(&dentry->d_lock); | ||
| 687 | return 1; | ||
| 688 | } | ||
| 689 | |||
| 690 | /* | ||
| 691 | * Re-get the reference we optimistically dropped. We hold the | ||
| 692 | * lock, and we just tested that it was zero, so we can just | ||
| 693 | * set it to 1. | ||
| 694 | */ | ||
| 695 | dentry->d_lockref.count = 1; | ||
| 696 | return 0; | ||
| 697 | } | ||
| 698 | |||
| 699 | |||
| 596 | /* | 700 | /* |
| 597 | * This is dput | 701 | * This is dput |
| 598 | * | 702 | * |
| @@ -625,8 +729,14 @@ void dput(struct dentry *dentry) | |||
| 625 | return; | 729 | return; |
| 626 | 730 | ||
| 627 | repeat: | 731 | repeat: |
| 628 | if (lockref_put_or_lock(&dentry->d_lockref)) | 732 | rcu_read_lock(); |
| 733 | if (likely(fast_dput(dentry))) { | ||
| 734 | rcu_read_unlock(); | ||
| 629 | return; | 735 | return; |
| 736 | } | ||
| 737 | |||
| 738 | /* Slow case: now with the dentry lock held */ | ||
| 739 | rcu_read_unlock(); | ||
| 630 | 740 | ||
| 631 | /* Unreachable? Get rid of it */ | 741 | /* Unreachable? Get rid of it */ |
| 632 | if (unlikely(d_unhashed(dentry))) | 742 | if (unlikely(d_unhashed(dentry))) |
| @@ -813,7 +923,7 @@ static void shrink_dentry_list(struct list_head *list) | |||
| 813 | * We found an inuse dentry which was not removed from | 923 | * We found an inuse dentry which was not removed from |
| 814 | * the LRU because of laziness during lookup. Do not free it. | 924 | * the LRU because of laziness during lookup. Do not free it. |
| 815 | */ | 925 | */ |
| 816 | if ((int)dentry->d_lockref.count > 0) { | 926 | if (dentry->d_lockref.count > 0) { |
| 817 | spin_unlock(&dentry->d_lock); | 927 | spin_unlock(&dentry->d_lock); |
| 818 | if (parent) | 928 | if (parent) |
| 819 | spin_unlock(&parent->d_lock); | 929 | spin_unlock(&parent->d_lock); |
| @@ -2191,37 +2301,6 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) | |||
| 2191 | } | 2301 | } |
| 2192 | EXPORT_SYMBOL(d_hash_and_lookup); | 2302 | EXPORT_SYMBOL(d_hash_and_lookup); |
| 2193 | 2303 | ||
| 2194 | /** | ||
| 2195 | * d_validate - verify dentry provided from insecure source (deprecated) | ||
| 2196 | * @dentry: The dentry alleged to be valid child of @dparent | ||
| 2197 | * @dparent: The parent dentry (known to be valid) | ||
| 2198 | * | ||
| 2199 | * An insecure source has sent us a dentry, here we verify it and dget() it. | ||
| 2200 | * This is used by ncpfs in its readdir implementation. | ||
| 2201 | * Zero is returned in the dentry is invalid. | ||
| 2202 | * | ||
| 2203 | * This function is slow for big directories, and deprecated, do not use it. | ||
| 2204 | */ | ||
| 2205 | int d_validate(struct dentry *dentry, struct dentry *dparent) | ||
| 2206 | { | ||
| 2207 | struct dentry *child; | ||
| 2208 | |||
| 2209 | spin_lock(&dparent->d_lock); | ||
| 2210 | list_for_each_entry(child, &dparent->d_subdirs, d_child) { | ||
| 2211 | if (dentry == child) { | ||
| 2212 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
| 2213 | __dget_dlock(dentry); | ||
| 2214 | spin_unlock(&dentry->d_lock); | ||
| 2215 | spin_unlock(&dparent->d_lock); | ||
| 2216 | return 1; | ||
| 2217 | } | ||
| 2218 | } | ||
| 2219 | spin_unlock(&dparent->d_lock); | ||
| 2220 | |||
| 2221 | return 0; | ||
| 2222 | } | ||
| 2223 | EXPORT_SYMBOL(d_validate); | ||
| 2224 | |||
| 2225 | /* | 2304 | /* |
| 2226 | * When a file is deleted, we have two options: | 2305 | * When a file is deleted, we have two options: |
| 2227 | * - turn this dentry into a negative dentry | 2306 | * - turn this dentry into a negative dentry |
diff --git a/fs/fs_pin.c b/fs/fs_pin.c index 9368236ca100..b06c98796afb 100644 --- a/fs/fs_pin.c +++ b/fs/fs_pin.c | |||
| @@ -1,78 +1,102 @@ | |||
| 1 | #include <linux/fs.h> | 1 | #include <linux/fs.h> |
| 2 | #include <linux/sched.h> | ||
| 2 | #include <linux/slab.h> | 3 | #include <linux/slab.h> |
| 3 | #include <linux/fs_pin.h> | ||
| 4 | #include "internal.h" | 4 | #include "internal.h" |
| 5 | #include "mount.h" | 5 | #include "mount.h" |
| 6 | 6 | ||
| 7 | static void pin_free_rcu(struct rcu_head *head) | ||
| 8 | { | ||
| 9 | kfree(container_of(head, struct fs_pin, rcu)); | ||
| 10 | } | ||
| 11 | |||
| 12 | static DEFINE_SPINLOCK(pin_lock); | 7 | static DEFINE_SPINLOCK(pin_lock); |
| 13 | 8 | ||
| 14 | void pin_put(struct fs_pin *p) | ||
| 15 | { | ||
| 16 | if (atomic_long_dec_and_test(&p->count)) | ||
| 17 | call_rcu(&p->rcu, pin_free_rcu); | ||
| 18 | } | ||
| 19 | |||
| 20 | void pin_remove(struct fs_pin *pin) | 9 | void pin_remove(struct fs_pin *pin) |
| 21 | { | 10 | { |
| 22 | spin_lock(&pin_lock); | 11 | spin_lock(&pin_lock); |
| 23 | hlist_del(&pin->m_list); | 12 | hlist_del(&pin->m_list); |
| 24 | hlist_del(&pin->s_list); | 13 | hlist_del(&pin->s_list); |
| 25 | spin_unlock(&pin_lock); | 14 | spin_unlock(&pin_lock); |
| 15 | spin_lock_irq(&pin->wait.lock); | ||
| 16 | pin->done = 1; | ||
| 17 | wake_up_locked(&pin->wait); | ||
| 18 | spin_unlock_irq(&pin->wait.lock); | ||
| 26 | } | 19 | } |
| 27 | 20 | ||
| 28 | void pin_insert(struct fs_pin *pin, struct vfsmount *m) | 21 | void pin_insert_group(struct fs_pin *pin, struct vfsmount *m, struct hlist_head *p) |
| 29 | { | 22 | { |
| 30 | spin_lock(&pin_lock); | 23 | spin_lock(&pin_lock); |
| 31 | hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins); | 24 | if (p) |
| 25 | hlist_add_head(&pin->s_list, p); | ||
| 32 | hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins); | 26 | hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins); |
| 33 | spin_unlock(&pin_lock); | 27 | spin_unlock(&pin_lock); |
| 34 | } | 28 | } |
| 35 | 29 | ||
| 30 | void pin_insert(struct fs_pin *pin, struct vfsmount *m) | ||
| 31 | { | ||
| 32 | pin_insert_group(pin, m, &m->mnt_sb->s_pins); | ||
| 33 | } | ||
| 34 | |||
| 35 | void pin_kill(struct fs_pin *p) | ||
| 36 | { | ||
| 37 | wait_queue_t wait; | ||
| 38 | |||
| 39 | if (!p) { | ||
| 40 | rcu_read_unlock(); | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | init_wait(&wait); | ||
| 44 | spin_lock_irq(&p->wait.lock); | ||
| 45 | if (likely(!p->done)) { | ||
| 46 | p->done = -1; | ||
| 47 | spin_unlock_irq(&p->wait.lock); | ||
| 48 | rcu_read_unlock(); | ||
| 49 | p->kill(p); | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | if (p->done > 0) { | ||
| 53 | spin_unlock_irq(&p->wait.lock); | ||
| 54 | rcu_read_unlock(); | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | __add_wait_queue(&p->wait, &wait); | ||
| 58 | while (1) { | ||
| 59 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 60 | spin_unlock_irq(&p->wait.lock); | ||
| 61 | rcu_read_unlock(); | ||
| 62 | schedule(); | ||
| 63 | rcu_read_lock(); | ||
| 64 | if (likely(list_empty(&wait.task_list))) | ||
| 65 | break; | ||
| 66 | /* OK, we know p couldn't have been freed yet */ | ||
| 67 | spin_lock_irq(&p->wait.lock); | ||
| 68 | if (p->done > 0) { | ||
| 69 | spin_unlock_irq(&p->wait.lock); | ||
| 70 | break; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | rcu_read_unlock(); | ||
| 74 | } | ||
| 75 | |||
| 36 | void mnt_pin_kill(struct mount *m) | 76 | void mnt_pin_kill(struct mount *m) |
| 37 | { | 77 | { |
| 38 | while (1) { | 78 | while (1) { |
| 39 | struct hlist_node *p; | 79 | struct hlist_node *p; |
| 40 | struct fs_pin *pin; | ||
| 41 | rcu_read_lock(); | 80 | rcu_read_lock(); |
| 42 | p = ACCESS_ONCE(m->mnt_pins.first); | 81 | p = ACCESS_ONCE(m->mnt_pins.first); |
| 43 | if (!p) { | 82 | if (!p) { |
| 44 | rcu_read_unlock(); | 83 | rcu_read_unlock(); |
| 45 | break; | 84 | break; |
| 46 | } | 85 | } |
| 47 | pin = hlist_entry(p, struct fs_pin, m_list); | 86 | pin_kill(hlist_entry(p, struct fs_pin, m_list)); |
| 48 | if (!atomic_long_inc_not_zero(&pin->count)) { | ||
| 49 | rcu_read_unlock(); | ||
| 50 | cpu_relax(); | ||
| 51 | continue; | ||
| 52 | } | ||
| 53 | rcu_read_unlock(); | ||
| 54 | pin->kill(pin); | ||
| 55 | } | 87 | } |
| 56 | } | 88 | } |
| 57 | 89 | ||
| 58 | void sb_pin_kill(struct super_block *sb) | 90 | void group_pin_kill(struct hlist_head *p) |
| 59 | { | 91 | { |
| 60 | while (1) { | 92 | while (1) { |
| 61 | struct hlist_node *p; | 93 | struct hlist_node *q; |
| 62 | struct fs_pin *pin; | ||
| 63 | rcu_read_lock(); | 94 | rcu_read_lock(); |
| 64 | p = ACCESS_ONCE(sb->s_pins.first); | 95 | q = ACCESS_ONCE(p->first); |
| 65 | if (!p) { | 96 | if (!q) { |
| 66 | rcu_read_unlock(); | 97 | rcu_read_unlock(); |
| 67 | break; | 98 | break; |
| 68 | } | 99 | } |
| 69 | pin = hlist_entry(p, struct fs_pin, s_list); | 100 | pin_kill(hlist_entry(q, struct fs_pin, s_list)); |
| 70 | if (!atomic_long_inc_not_zero(&pin->count)) { | ||
| 71 | rcu_read_unlock(); | ||
| 72 | cpu_relax(); | ||
| 73 | continue; | ||
| 74 | } | ||
| 75 | rcu_read_unlock(); | ||
| 76 | pin->kill(pin); | ||
| 77 | } | 101 | } |
| 78 | } | 102 | } |
diff --git a/fs/internal.h b/fs/internal.h index d92c346a793d..30459dab409d 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
| @@ -144,7 +144,7 @@ extern const struct file_operations pipefifo_fops; | |||
| 144 | /* | 144 | /* |
| 145 | * fs_pin.c | 145 | * fs_pin.c |
| 146 | */ | 146 | */ |
| 147 | extern void sb_pin_kill(struct super_block *sb); | 147 | extern void group_pin_kill(struct hlist_head *p); |
| 148 | extern void mnt_pin_kill(struct mount *m); | 148 | extern void mnt_pin_kill(struct mount *m); |
| 149 | 149 | ||
| 150 | /* | 150 | /* |
diff --git a/fs/mount.h b/fs/mount.h index 0ad6f760ce52..6a61c2b3e385 100644 --- a/fs/mount.h +++ b/fs/mount.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #include <linux/seq_file.h> | 2 | #include <linux/seq_file.h> |
| 3 | #include <linux/poll.h> | 3 | #include <linux/poll.h> |
| 4 | #include <linux/ns_common.h> | 4 | #include <linux/ns_common.h> |
| 5 | #include <linux/fs_pin.h> | ||
| 5 | 6 | ||
| 6 | struct mnt_namespace { | 7 | struct mnt_namespace { |
| 7 | atomic_t count; | 8 | atomic_t count; |
| @@ -62,7 +63,8 @@ struct mount { | |||
| 62 | int mnt_group_id; /* peer group identifier */ | 63 | int mnt_group_id; /* peer group identifier */ |
| 63 | int mnt_expiry_mark; /* true if marked for expiry */ | 64 | int mnt_expiry_mark; /* true if marked for expiry */ |
| 64 | struct hlist_head mnt_pins; | 65 | struct hlist_head mnt_pins; |
| 65 | struct path mnt_ex_mountpoint; | 66 | struct fs_pin mnt_umount; |
| 67 | struct dentry *mnt_ex_mountpoint; | ||
| 66 | }; | 68 | }; |
| 67 | 69 | ||
| 68 | #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */ | 70 | #define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */ |
diff --git a/fs/namespace.c b/fs/namespace.c index 6dae553dd69c..72a286e0d33e 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -190,6 +190,14 @@ unsigned int mnt_get_count(struct mount *mnt) | |||
| 190 | #endif | 190 | #endif |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | static void drop_mountpoint(struct fs_pin *p) | ||
| 194 | { | ||
| 195 | struct mount *m = container_of(p, struct mount, mnt_umount); | ||
| 196 | dput(m->mnt_ex_mountpoint); | ||
| 197 | pin_remove(p); | ||
| 198 | mntput(&m->mnt); | ||
| 199 | } | ||
| 200 | |||
| 193 | static struct mount *alloc_vfsmnt(const char *name) | 201 | static struct mount *alloc_vfsmnt(const char *name) |
| 194 | { | 202 | { |
| 195 | struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); | 203 | struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); |
| @@ -229,6 +237,7 @@ static struct mount *alloc_vfsmnt(const char *name) | |||
| 229 | #ifdef CONFIG_FSNOTIFY | 237 | #ifdef CONFIG_FSNOTIFY |
| 230 | INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); | 238 | INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); |
| 231 | #endif | 239 | #endif |
| 240 | init_fs_pin(&mnt->mnt_umount, drop_mountpoint); | ||
| 232 | } | 241 | } |
| 233 | return mnt; | 242 | return mnt; |
| 234 | 243 | ||
| @@ -1289,7 +1298,6 @@ static HLIST_HEAD(unmounted); /* protected by namespace_sem */ | |||
| 1289 | 1298 | ||
| 1290 | static void namespace_unlock(void) | 1299 | static void namespace_unlock(void) |
| 1291 | { | 1300 | { |
| 1292 | struct mount *mnt; | ||
| 1293 | struct hlist_head head = unmounted; | 1301 | struct hlist_head head = unmounted; |
| 1294 | 1302 | ||
| 1295 | if (likely(hlist_empty(&head))) { | 1303 | if (likely(hlist_empty(&head))) { |
| @@ -1299,23 +1307,11 @@ static void namespace_unlock(void) | |||
| 1299 | 1307 | ||
| 1300 | head.first->pprev = &head.first; | 1308 | head.first->pprev = &head.first; |
| 1301 | INIT_HLIST_HEAD(&unmounted); | 1309 | INIT_HLIST_HEAD(&unmounted); |
| 1302 | |||
| 1303 | /* undo decrements we'd done in umount_tree() */ | ||
| 1304 | hlist_for_each_entry(mnt, &head, mnt_hash) | ||
| 1305 | if (mnt->mnt_ex_mountpoint.mnt) | ||
| 1306 | mntget(mnt->mnt_ex_mountpoint.mnt); | ||
| 1307 | |||
| 1308 | up_write(&namespace_sem); | 1310 | up_write(&namespace_sem); |
| 1309 | 1311 | ||
| 1310 | synchronize_rcu(); | 1312 | synchronize_rcu(); |
| 1311 | 1313 | ||
| 1312 | while (!hlist_empty(&head)) { | 1314 | group_pin_kill(&head); |
| 1313 | mnt = hlist_entry(head.first, struct mount, mnt_hash); | ||
| 1314 | hlist_del_init(&mnt->mnt_hash); | ||
| 1315 | if (mnt->mnt_ex_mountpoint.mnt) | ||
| 1316 | path_put(&mnt->mnt_ex_mountpoint); | ||
| 1317 | mntput(&mnt->mnt); | ||
| 1318 | } | ||
| 1319 | } | 1315 | } |
| 1320 | 1316 | ||
| 1321 | static inline void namespace_lock(void) | 1317 | static inline void namespace_lock(void) |
| @@ -1334,7 +1330,6 @@ void umount_tree(struct mount *mnt, int how) | |||
| 1334 | { | 1330 | { |
| 1335 | HLIST_HEAD(tmp_list); | 1331 | HLIST_HEAD(tmp_list); |
| 1336 | struct mount *p; | 1332 | struct mount *p; |
| 1337 | struct mount *last = NULL; | ||
| 1338 | 1333 | ||
| 1339 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 1334 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
| 1340 | hlist_del_init_rcu(&p->mnt_hash); | 1335 | hlist_del_init_rcu(&p->mnt_hash); |
| @@ -1347,33 +1342,28 @@ void umount_tree(struct mount *mnt, int how) | |||
| 1347 | if (how) | 1342 | if (how) |
| 1348 | propagate_umount(&tmp_list); | 1343 | propagate_umount(&tmp_list); |
| 1349 | 1344 | ||
| 1350 | hlist_for_each_entry(p, &tmp_list, mnt_hash) { | 1345 | while (!hlist_empty(&tmp_list)) { |
| 1346 | p = hlist_entry(tmp_list.first, struct mount, mnt_hash); | ||
| 1347 | hlist_del_init_rcu(&p->mnt_hash); | ||
| 1351 | list_del_init(&p->mnt_expire); | 1348 | list_del_init(&p->mnt_expire); |
| 1352 | list_del_init(&p->mnt_list); | 1349 | list_del_init(&p->mnt_list); |
| 1353 | __touch_mnt_namespace(p->mnt_ns); | 1350 | __touch_mnt_namespace(p->mnt_ns); |
| 1354 | p->mnt_ns = NULL; | 1351 | p->mnt_ns = NULL; |
| 1355 | if (how < 2) | 1352 | if (how < 2) |
| 1356 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; | 1353 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; |
| 1354 | |||
| 1355 | pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, &unmounted); | ||
| 1357 | if (mnt_has_parent(p)) { | 1356 | if (mnt_has_parent(p)) { |
| 1358 | hlist_del_init(&p->mnt_mp_list); | 1357 | hlist_del_init(&p->mnt_mp_list); |
| 1359 | put_mountpoint(p->mnt_mp); | 1358 | put_mountpoint(p->mnt_mp); |
| 1360 | mnt_add_count(p->mnt_parent, -1); | 1359 | mnt_add_count(p->mnt_parent, -1); |
| 1361 | /* move the reference to mountpoint into ->mnt_ex_mountpoint */ | 1360 | /* old mountpoint will be dropped when we can do that */ |
| 1362 | p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint; | 1361 | p->mnt_ex_mountpoint = p->mnt_mountpoint; |
| 1363 | p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt; | ||
| 1364 | p->mnt_mountpoint = p->mnt.mnt_root; | 1362 | p->mnt_mountpoint = p->mnt.mnt_root; |
| 1365 | p->mnt_parent = p; | 1363 | p->mnt_parent = p; |
| 1366 | p->mnt_mp = NULL; | 1364 | p->mnt_mp = NULL; |
| 1367 | } | 1365 | } |
| 1368 | change_mnt_propagation(p, MS_PRIVATE); | 1366 | change_mnt_propagation(p, MS_PRIVATE); |
| 1369 | last = p; | ||
| 1370 | } | ||
| 1371 | if (last) { | ||
| 1372 | last->mnt_hash.next = unmounted.first; | ||
| 1373 | if (unmounted.first) | ||
| 1374 | unmounted.first->pprev = &last->mnt_hash.next; | ||
| 1375 | unmounted.first = tmp_list.first; | ||
| 1376 | unmounted.first->pprev = &unmounted.first; | ||
| 1377 | } | 1367 | } |
| 1378 | } | 1368 | } |
| 1379 | 1369 | ||
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 */ |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index de14e46fd807..3309f59d421b 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -350,29 +350,12 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
| 350 | if (ret) | 350 | if (ret) |
| 351 | return ret; | 351 | return ret; |
| 352 | 352 | ||
| 353 | if (S_ISDIR(dp->mode)) { | ||
| 354 | dp->proc_fops = &proc_dir_operations; | ||
| 355 | dp->proc_iops = &proc_dir_inode_operations; | ||
| 356 | dir->nlink++; | ||
| 357 | } else if (S_ISLNK(dp->mode)) { | ||
| 358 | dp->proc_iops = &proc_link_inode_operations; | ||
| 359 | } else if (S_ISREG(dp->mode)) { | ||
| 360 | BUG_ON(dp->proc_fops == NULL); | ||
| 361 | dp->proc_iops = &proc_file_inode_operations; | ||
| 362 | } else { | ||
| 363 | WARN_ON(1); | ||
| 364 | proc_free_inum(dp->low_ino); | ||
| 365 | return -EINVAL; | ||
| 366 | } | ||
| 367 | |||
| 368 | spin_lock(&proc_subdir_lock); | 353 | spin_lock(&proc_subdir_lock); |
| 369 | dp->parent = dir; | 354 | dp->parent = dir; |
| 370 | if (pde_subdir_insert(dir, dp) == false) { | 355 | if (pde_subdir_insert(dir, dp) == false) { |
| 371 | WARN(1, "proc_dir_entry '%s/%s' already registered\n", | 356 | WARN(1, "proc_dir_entry '%s/%s' already registered\n", |
| 372 | dir->name, dp->name); | 357 | dir->name, dp->name); |
| 373 | spin_unlock(&proc_subdir_lock); | 358 | spin_unlock(&proc_subdir_lock); |
| 374 | if (S_ISDIR(dp->mode)) | ||
| 375 | dir->nlink--; | ||
| 376 | proc_free_inum(dp->low_ino); | 359 | proc_free_inum(dp->low_ino); |
| 377 | return -EEXIST; | 360 | return -EEXIST; |
| 378 | } | 361 | } |
| @@ -431,6 +414,7 @@ struct proc_dir_entry *proc_symlink(const char *name, | |||
| 431 | ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL); | 414 | ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL); |
| 432 | if (ent->data) { | 415 | if (ent->data) { |
| 433 | strcpy((char*)ent->data,dest); | 416 | strcpy((char*)ent->data,dest); |
| 417 | ent->proc_iops = &proc_link_inode_operations; | ||
| 434 | if (proc_register(parent, ent) < 0) { | 418 | if (proc_register(parent, ent) < 0) { |
| 435 | kfree(ent->data); | 419 | kfree(ent->data); |
| 436 | kfree(ent); | 420 | kfree(ent); |
| @@ -456,8 +440,12 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, | |||
| 456 | ent = __proc_create(&parent, name, S_IFDIR | mode, 2); | 440 | ent = __proc_create(&parent, name, S_IFDIR | mode, 2); |
| 457 | if (ent) { | 441 | if (ent) { |
| 458 | ent->data = data; | 442 | ent->data = data; |
| 443 | ent->proc_fops = &proc_dir_operations; | ||
| 444 | ent->proc_iops = &proc_dir_inode_operations; | ||
| 445 | parent->nlink++; | ||
| 459 | if (proc_register(parent, ent) < 0) { | 446 | if (proc_register(parent, ent) < 0) { |
| 460 | kfree(ent); | 447 | kfree(ent); |
| 448 | parent->nlink--; | ||
| 461 | ent = NULL; | 449 | ent = NULL; |
| 462 | } | 450 | } |
| 463 | } | 451 | } |
| @@ -493,6 +481,8 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, | |||
| 493 | return NULL; | 481 | return NULL; |
| 494 | } | 482 | } |
| 495 | 483 | ||
| 484 | BUG_ON(proc_fops == NULL); | ||
| 485 | |||
| 496 | if ((mode & S_IALLUGO) == 0) | 486 | if ((mode & S_IALLUGO) == 0) |
| 497 | mode |= S_IRUGO; | 487 | mode |= S_IRUGO; |
| 498 | pde = __proc_create(&parent, name, mode, 1); | 488 | pde = __proc_create(&parent, name, mode, 1); |
| @@ -500,6 +490,7 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, | |||
| 500 | goto out; | 490 | goto out; |
| 501 | pde->proc_fops = proc_fops; | 491 | pde->proc_fops = proc_fops; |
| 502 | pde->data = data; | 492 | pde->data = data; |
| 493 | pde->proc_iops = &proc_file_inode_operations; | ||
| 503 | if (proc_register(parent, pde) < 0) | 494 | if (proc_register(parent, pde) < 0) |
| 504 | goto out_free; | 495 | goto out_free; |
| 505 | return pde; | 496 | return pde; |
diff --git a/fs/super.c b/fs/super.c index 1facd2c282e5..65a53efc1cf4 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -715,9 +715,9 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
| 715 | remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY); | 715 | remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY); |
| 716 | 716 | ||
| 717 | if (remount_ro) { | 717 | if (remount_ro) { |
| 718 | if (sb->s_pins.first) { | 718 | if (!hlist_empty(&sb->s_pins)) { |
| 719 | up_write(&sb->s_umount); | 719 | up_write(&sb->s_umount); |
| 720 | sb_pin_kill(sb); | 720 | group_pin_kill(&sb->s_pins); |
| 721 | down_write(&sb->s_umount); | 721 | down_write(&sb->s_umount); |
| 722 | if (!sb->s_root) | 722 | if (!sb->s_root) |
| 723 | return 0; | 723 | return 0; |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 5a813988e6d4..92c08cf7670e 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
| @@ -319,9 +319,6 @@ static inline unsigned d_count(const struct dentry *dentry) | |||
| 319 | return dentry->d_lockref.count; | 319 | return dentry->d_lockref.count; |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | /* validate "insecure" dentry pointer */ | ||
| 323 | extern int d_validate(struct dentry *, struct dentry *); | ||
| 324 | |||
| 325 | /* | 322 | /* |
| 326 | * helper function for dentry_operations.d_dname() members | 323 | * helper function for dentry_operations.d_dname() members |
| 327 | */ | 324 | */ |
diff --git a/include/linux/fs_pin.h b/include/linux/fs_pin.h index f66525e72ccf..9dc4e0384bfb 100644 --- a/include/linux/fs_pin.h +++ b/include/linux/fs_pin.h | |||
| @@ -1,17 +1,22 @@ | |||
| 1 | #include <linux/fs.h> | 1 | #include <linux/wait.h> |
| 2 | 2 | ||
| 3 | struct fs_pin { | 3 | struct fs_pin { |
| 4 | atomic_long_t count; | 4 | wait_queue_head_t wait; |
| 5 | union { | 5 | int done; |
| 6 | struct { | 6 | struct hlist_node s_list; |
| 7 | struct hlist_node s_list; | 7 | struct hlist_node m_list; |
| 8 | struct hlist_node m_list; | ||
| 9 | }; | ||
| 10 | struct rcu_head rcu; | ||
| 11 | }; | ||
| 12 | void (*kill)(struct fs_pin *); | 8 | void (*kill)(struct fs_pin *); |
| 13 | }; | 9 | }; |
| 14 | 10 | ||
| 15 | void pin_put(struct fs_pin *); | 11 | struct vfsmount; |
| 12 | |||
| 13 | static inline void init_fs_pin(struct fs_pin *p, void (*kill)(struct fs_pin *)) | ||
| 14 | { | ||
| 15 | init_waitqueue_head(&p->wait); | ||
| 16 | p->kill = kill; | ||
| 17 | } | ||
| 18 | |||
| 16 | void pin_remove(struct fs_pin *); | 19 | void pin_remove(struct fs_pin *); |
| 20 | void pin_insert_group(struct fs_pin *, struct vfsmount *, struct hlist_head *); | ||
| 17 | void pin_insert(struct fs_pin *, struct vfsmount *); | 21 | void pin_insert(struct fs_pin *, struct vfsmount *); |
| 22 | void pin_kill(struct fs_pin *); | ||
diff --git a/include/linux/lockref.h b/include/linux/lockref.h index 4bfde0e99ed5..b10b122dd099 100644 --- a/include/linux/lockref.h +++ b/include/linux/lockref.h | |||
| @@ -28,12 +28,13 @@ struct lockref { | |||
| 28 | #endif | 28 | #endif |
| 29 | struct { | 29 | struct { |
| 30 | spinlock_t lock; | 30 | spinlock_t lock; |
| 31 | unsigned int count; | 31 | int count; |
| 32 | }; | 32 | }; |
| 33 | }; | 33 | }; |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | extern void lockref_get(struct lockref *); | 36 | extern void lockref_get(struct lockref *); |
| 37 | extern int lockref_put_return(struct lockref *); | ||
| 37 | extern int lockref_get_not_zero(struct lockref *); | 38 | extern int lockref_get_not_zero(struct lockref *); |
| 38 | extern int lockref_get_or_lock(struct lockref *); | 39 | extern int lockref_get_or_lock(struct lockref *); |
| 39 | extern int lockref_put_or_lock(struct lockref *); | 40 | extern int lockref_put_or_lock(struct lockref *); |
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index b9cf6c51b181..918b117a7cd3 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h | |||
| @@ -19,7 +19,7 @@ struct pidmap { | |||
| 19 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) | 19 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) |
| 20 | #define PIDMAP_ENTRIES ((PID_MAX_LIMIT+BITS_PER_PAGE-1)/BITS_PER_PAGE) | 20 | #define PIDMAP_ENTRIES ((PID_MAX_LIMIT+BITS_PER_PAGE-1)/BITS_PER_PAGE) |
| 21 | 21 | ||
| 22 | struct bsd_acct_struct; | 22 | struct fs_pin; |
| 23 | 23 | ||
| 24 | struct pid_namespace { | 24 | struct pid_namespace { |
| 25 | struct kref kref; | 25 | struct kref kref; |
| @@ -37,7 +37,7 @@ struct pid_namespace { | |||
| 37 | struct dentry *proc_thread_self; | 37 | struct dentry *proc_thread_self; |
| 38 | #endif | 38 | #endif |
| 39 | #ifdef CONFIG_BSD_PROCESS_ACCT | 39 | #ifdef CONFIG_BSD_PROCESS_ACCT |
| 40 | struct bsd_acct_struct *bacct; | 40 | struct fs_pin *bacct; |
| 41 | #endif | 41 | #endif |
| 42 | struct user_namespace *user_ns; | 42 | struct user_namespace *user_ns; |
| 43 | struct work_struct proc_work; | 43 | struct work_struct proc_work; |
diff --git a/kernel/acct.c b/kernel/acct.c index 33738ef972f3..e6c10d1a4058 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
| @@ -76,10 +76,11 @@ int acct_parm[3] = {4, 2, 30}; | |||
| 76 | /* | 76 | /* |
| 77 | * External references and all of the globals. | 77 | * External references and all of the globals. |
| 78 | */ | 78 | */ |
| 79 | static void do_acct_process(struct bsd_acct_struct *acct); | ||
| 80 | 79 | ||
| 81 | struct bsd_acct_struct { | 80 | struct bsd_acct_struct { |
| 82 | struct fs_pin pin; | 81 | struct fs_pin pin; |
| 82 | atomic_long_t count; | ||
| 83 | struct rcu_head rcu; | ||
| 83 | struct mutex lock; | 84 | struct mutex lock; |
| 84 | int active; | 85 | int active; |
| 85 | unsigned long needcheck; | 86 | unsigned long needcheck; |
| @@ -89,6 +90,8 @@ struct bsd_acct_struct { | |||
| 89 | struct completion done; | 90 | struct completion done; |
| 90 | }; | 91 | }; |
| 91 | 92 | ||
| 93 | static void do_acct_process(struct bsd_acct_struct *acct); | ||
| 94 | |||
| 92 | /* | 95 | /* |
| 93 | * Check the amount of free space and suspend/resume accordingly. | 96 | * Check the amount of free space and suspend/resume accordingly. |
| 94 | */ | 97 | */ |
| @@ -124,32 +127,56 @@ out: | |||
| 124 | return acct->active; | 127 | return acct->active; |
| 125 | } | 128 | } |
| 126 | 129 | ||
| 130 | static void acct_put(struct bsd_acct_struct *p) | ||
| 131 | { | ||
| 132 | if (atomic_long_dec_and_test(&p->count)) | ||
| 133 | kfree_rcu(p, rcu); | ||
| 134 | } | ||
| 135 | |||
| 136 | static inline struct bsd_acct_struct *to_acct(struct fs_pin *p) | ||
| 137 | { | ||
| 138 | return p ? container_of(p, struct bsd_acct_struct, pin) : NULL; | ||
| 139 | } | ||
| 140 | |||
| 127 | static struct bsd_acct_struct *acct_get(struct pid_namespace *ns) | 141 | static struct bsd_acct_struct *acct_get(struct pid_namespace *ns) |
| 128 | { | 142 | { |
| 129 | struct bsd_acct_struct *res; | 143 | struct bsd_acct_struct *res; |
| 130 | again: | 144 | again: |
| 131 | smp_rmb(); | 145 | smp_rmb(); |
| 132 | rcu_read_lock(); | 146 | rcu_read_lock(); |
| 133 | res = ACCESS_ONCE(ns->bacct); | 147 | res = to_acct(ACCESS_ONCE(ns->bacct)); |
| 134 | if (!res) { | 148 | if (!res) { |
| 135 | rcu_read_unlock(); | 149 | rcu_read_unlock(); |
| 136 | return NULL; | 150 | return NULL; |
| 137 | } | 151 | } |
| 138 | if (!atomic_long_inc_not_zero(&res->pin.count)) { | 152 | if (!atomic_long_inc_not_zero(&res->count)) { |
| 139 | rcu_read_unlock(); | 153 | rcu_read_unlock(); |
| 140 | cpu_relax(); | 154 | cpu_relax(); |
| 141 | goto again; | 155 | goto again; |
| 142 | } | 156 | } |
| 143 | rcu_read_unlock(); | 157 | rcu_read_unlock(); |
| 144 | mutex_lock(&res->lock); | 158 | mutex_lock(&res->lock); |
| 145 | if (!res->ns) { | 159 | if (res != to_acct(ACCESS_ONCE(ns->bacct))) { |
| 146 | mutex_unlock(&res->lock); | 160 | mutex_unlock(&res->lock); |
| 147 | pin_put(&res->pin); | 161 | acct_put(res); |
| 148 | goto again; | 162 | goto again; |
| 149 | } | 163 | } |
| 150 | return res; | 164 | return res; |
| 151 | } | 165 | } |
| 152 | 166 | ||
| 167 | static void acct_pin_kill(struct fs_pin *pin) | ||
| 168 | { | ||
| 169 | struct bsd_acct_struct *acct = to_acct(pin); | ||
| 170 | mutex_lock(&acct->lock); | ||
| 171 | do_acct_process(acct); | ||
| 172 | schedule_work(&acct->work); | ||
| 173 | wait_for_completion(&acct->done); | ||
| 174 | cmpxchg(&acct->ns->bacct, pin, NULL); | ||
| 175 | mutex_unlock(&acct->lock); | ||
| 176 | pin_remove(pin); | ||
| 177 | acct_put(acct); | ||
| 178 | } | ||
| 179 | |||
| 153 | static void close_work(struct work_struct *work) | 180 | static void close_work(struct work_struct *work) |
| 154 | { | 181 | { |
| 155 | struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work); | 182 | struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work); |
| @@ -160,44 +187,13 @@ static void close_work(struct work_struct *work) | |||
| 160 | complete(&acct->done); | 187 | complete(&acct->done); |
| 161 | } | 188 | } |
| 162 | 189 | ||
| 163 | static void acct_kill(struct bsd_acct_struct *acct, | ||
| 164 | struct bsd_acct_struct *new) | ||
| 165 | { | ||
| 166 | if (acct) { | ||
| 167 | struct pid_namespace *ns = acct->ns; | ||
| 168 | do_acct_process(acct); | ||
| 169 | INIT_WORK(&acct->work, close_work); | ||
| 170 | init_completion(&acct->done); | ||
| 171 | schedule_work(&acct->work); | ||
| 172 | wait_for_completion(&acct->done); | ||
| 173 | pin_remove(&acct->pin); | ||
| 174 | ns->bacct = new; | ||
| 175 | acct->ns = NULL; | ||
| 176 | atomic_long_dec(&acct->pin.count); | ||
| 177 | mutex_unlock(&acct->lock); | ||
| 178 | pin_put(&acct->pin); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | static void acct_pin_kill(struct fs_pin *pin) | ||
| 183 | { | ||
| 184 | struct bsd_acct_struct *acct; | ||
| 185 | acct = container_of(pin, struct bsd_acct_struct, pin); | ||
| 186 | mutex_lock(&acct->lock); | ||
| 187 | if (!acct->ns) { | ||
| 188 | mutex_unlock(&acct->lock); | ||
| 189 | pin_put(pin); | ||
| 190 | acct = NULL; | ||
| 191 | } | ||
| 192 | acct_kill(acct, NULL); | ||
| 193 | } | ||
| 194 | |||
| 195 | static int acct_on(struct filename *pathname) | 190 | static int acct_on(struct filename *pathname) |
| 196 | { | 191 | { |
| 197 | struct file *file; | 192 | struct file *file; |
| 198 | struct vfsmount *mnt, *internal; | 193 | struct vfsmount *mnt, *internal; |
| 199 | struct pid_namespace *ns = task_active_pid_ns(current); | 194 | struct pid_namespace *ns = task_active_pid_ns(current); |
| 200 | struct bsd_acct_struct *acct, *old; | 195 | struct bsd_acct_struct *acct; |
| 196 | struct fs_pin *old; | ||
| 201 | int err; | 197 | int err; |
| 202 | 198 | ||
| 203 | acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL); | 199 | acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL); |
| @@ -238,21 +234,21 @@ static int acct_on(struct filename *pathname) | |||
| 238 | mnt = file->f_path.mnt; | 234 | mnt = file->f_path.mnt; |
| 239 | file->f_path.mnt = internal; | 235 | file->f_path.mnt = internal; |
| 240 | 236 | ||
| 241 | atomic_long_set(&acct->pin.count, 1); | 237 | atomic_long_set(&acct->count, 1); |
| 242 | acct->pin.kill = acct_pin_kill; | 238 | init_fs_pin(&acct->pin, acct_pin_kill); |
| 243 | acct->file = file; | 239 | acct->file = file; |
| 244 | acct->needcheck = jiffies; | 240 | acct->needcheck = jiffies; |
| 245 | acct->ns = ns; | 241 | acct->ns = ns; |
| 246 | mutex_init(&acct->lock); | 242 | mutex_init(&acct->lock); |
| 243 | INIT_WORK(&acct->work, close_work); | ||
| 244 | init_completion(&acct->done); | ||
| 247 | mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */ | 245 | mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */ |
| 248 | pin_insert(&acct->pin, mnt); | 246 | pin_insert(&acct->pin, mnt); |
| 249 | 247 | ||
| 250 | old = acct_get(ns); | 248 | rcu_read_lock(); |
| 251 | if (old) | 249 | old = xchg(&ns->bacct, &acct->pin); |
| 252 | acct_kill(old, acct); | ||
| 253 | else | ||
| 254 | ns->bacct = acct; | ||
| 255 | mutex_unlock(&acct->lock); | 250 | mutex_unlock(&acct->lock); |
| 251 | pin_kill(old); | ||
| 256 | mnt_drop_write(mnt); | 252 | mnt_drop_write(mnt); |
| 257 | mntput(mnt); | 253 | mntput(mnt); |
| 258 | return 0; | 254 | return 0; |
| @@ -288,7 +284,8 @@ SYSCALL_DEFINE1(acct, const char __user *, name) | |||
| 288 | mutex_unlock(&acct_on_mutex); | 284 | mutex_unlock(&acct_on_mutex); |
| 289 | putname(tmp); | 285 | putname(tmp); |
| 290 | } else { | 286 | } else { |
| 291 | acct_kill(acct_get(task_active_pid_ns(current)), NULL); | 287 | rcu_read_lock(); |
| 288 | pin_kill(task_active_pid_ns(current)->bacct); | ||
| 292 | } | 289 | } |
| 293 | 290 | ||
| 294 | return error; | 291 | return error; |
| @@ -296,7 +293,8 @@ SYSCALL_DEFINE1(acct, const char __user *, name) | |||
| 296 | 293 | ||
| 297 | void acct_exit_ns(struct pid_namespace *ns) | 294 | void acct_exit_ns(struct pid_namespace *ns) |
| 298 | { | 295 | { |
| 299 | acct_kill(acct_get(ns), NULL); | 296 | rcu_read_lock(); |
| 297 | pin_kill(ns->bacct); | ||
| 300 | } | 298 | } |
| 301 | 299 | ||
| 302 | /* | 300 | /* |
| @@ -576,7 +574,7 @@ static void slow_acct_process(struct pid_namespace *ns) | |||
| 576 | if (acct) { | 574 | if (acct) { |
| 577 | do_acct_process(acct); | 575 | do_acct_process(acct); |
| 578 | mutex_unlock(&acct->lock); | 576 | mutex_unlock(&acct->lock); |
| 579 | pin_put(&acct->pin); | 577 | acct_put(acct); |
| 580 | } | 578 | } |
| 581 | } | 579 | } |
| 582 | } | 580 | } |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 072566dd0caf..55f82fce2526 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -2405,7 +2405,6 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm, | |||
| 2405 | struct audit_aux_data_bprm_fcaps *ax; | 2405 | struct audit_aux_data_bprm_fcaps *ax; |
| 2406 | struct audit_context *context = current->audit_context; | 2406 | struct audit_context *context = current->audit_context; |
| 2407 | struct cpu_vfs_cap_data vcaps; | 2407 | struct cpu_vfs_cap_data vcaps; |
| 2408 | struct dentry *dentry; | ||
| 2409 | 2408 | ||
| 2410 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); | 2409 | ax = kmalloc(sizeof(*ax), GFP_KERNEL); |
| 2411 | if (!ax) | 2410 | if (!ax) |
| @@ -2415,9 +2414,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm, | |||
| 2415 | ax->d.next = context->aux; | 2414 | ax->d.next = context->aux; |
| 2416 | context->aux = (void *)ax; | 2415 | context->aux = (void *)ax; |
| 2417 | 2416 | ||
| 2418 | dentry = dget(bprm->file->f_path.dentry); | 2417 | get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); |
| 2419 | get_vfs_caps_from_disk(dentry, &vcaps); | ||
| 2420 | dput(dentry); | ||
| 2421 | 2418 | ||
| 2422 | ax->fcap.permitted = vcaps.permitted; | 2419 | ax->fcap.permitted = vcaps.permitted; |
| 2423 | ax->fcap.inheritable = vcaps.inheritable; | 2420 | ax->fcap.inheritable = vcaps.inheritable; |
diff --git a/lib/lockref.c b/lib/lockref.c index d2233de9a86e..ecb9a665ec19 100644 --- a/lib/lockref.c +++ b/lib/lockref.c | |||
| @@ -60,7 +60,7 @@ void lockref_get(struct lockref *lockref) | |||
| 60 | EXPORT_SYMBOL(lockref_get); | 60 | EXPORT_SYMBOL(lockref_get); |
| 61 | 61 | ||
| 62 | /** | 62 | /** |
| 63 | * lockref_get_not_zero - Increments count unless the count is 0 | 63 | * lockref_get_not_zero - Increments count unless the count is 0 or dead |
| 64 | * @lockref: pointer to lockref structure | 64 | * @lockref: pointer to lockref structure |
| 65 | * Return: 1 if count updated successfully or 0 if count was zero | 65 | * Return: 1 if count updated successfully or 0 if count was zero |
| 66 | */ | 66 | */ |
| @@ -70,7 +70,7 @@ int lockref_get_not_zero(struct lockref *lockref) | |||
| 70 | 70 | ||
| 71 | CMPXCHG_LOOP( | 71 | CMPXCHG_LOOP( |
| 72 | new.count++; | 72 | new.count++; |
| 73 | if (!old.count) | 73 | if (old.count <= 0) |
| 74 | return 0; | 74 | return 0; |
| 75 | , | 75 | , |
| 76 | return 1; | 76 | return 1; |
| @@ -78,7 +78,7 @@ int lockref_get_not_zero(struct lockref *lockref) | |||
| 78 | 78 | ||
| 79 | spin_lock(&lockref->lock); | 79 | spin_lock(&lockref->lock); |
| 80 | retval = 0; | 80 | retval = 0; |
| 81 | if (lockref->count) { | 81 | if (lockref->count > 0) { |
| 82 | lockref->count++; | 82 | lockref->count++; |
| 83 | retval = 1; | 83 | retval = 1; |
| 84 | } | 84 | } |
| @@ -88,7 +88,7 @@ int lockref_get_not_zero(struct lockref *lockref) | |||
| 88 | EXPORT_SYMBOL(lockref_get_not_zero); | 88 | EXPORT_SYMBOL(lockref_get_not_zero); |
| 89 | 89 | ||
| 90 | /** | 90 | /** |
| 91 | * lockref_get_or_lock - Increments count unless the count is 0 | 91 | * lockref_get_or_lock - Increments count unless the count is 0 or dead |
| 92 | * @lockref: pointer to lockref structure | 92 | * @lockref: pointer to lockref structure |
| 93 | * Return: 1 if count updated successfully or 0 if count was zero | 93 | * Return: 1 if count updated successfully or 0 if count was zero |
| 94 | * and we got the lock instead. | 94 | * and we got the lock instead. |
| @@ -97,14 +97,14 @@ int lockref_get_or_lock(struct lockref *lockref) | |||
| 97 | { | 97 | { |
| 98 | CMPXCHG_LOOP( | 98 | CMPXCHG_LOOP( |
| 99 | new.count++; | 99 | new.count++; |
| 100 | if (!old.count) | 100 | if (old.count <= 0) |
| 101 | break; | 101 | break; |
| 102 | , | 102 | , |
| 103 | return 1; | 103 | return 1; |
| 104 | ); | 104 | ); |
| 105 | 105 | ||
| 106 | spin_lock(&lockref->lock); | 106 | spin_lock(&lockref->lock); |
| 107 | if (!lockref->count) | 107 | if (lockref->count <= 0) |
| 108 | return 0; | 108 | return 0; |
| 109 | lockref->count++; | 109 | lockref->count++; |
| 110 | spin_unlock(&lockref->lock); | 110 | spin_unlock(&lockref->lock); |
| @@ -113,6 +113,26 @@ int lockref_get_or_lock(struct lockref *lockref) | |||
| 113 | EXPORT_SYMBOL(lockref_get_or_lock); | 113 | EXPORT_SYMBOL(lockref_get_or_lock); |
| 114 | 114 | ||
| 115 | /** | 115 | /** |
| 116 | * lockref_put_return - Decrement reference count if possible | ||
| 117 | * @lockref: pointer to lockref structure | ||
| 118 | * | ||
| 119 | * Decrement the reference count and return the new value. | ||
| 120 | * If the lockref was dead or locked, return an error. | ||
| 121 | */ | ||
| 122 | int lockref_put_return(struct lockref *lockref) | ||
| 123 | { | ||
| 124 | CMPXCHG_LOOP( | ||
| 125 | new.count--; | ||
| 126 | if (old.count <= 0) | ||
| 127 | return -1; | ||
| 128 | , | ||
| 129 | return new.count; | ||
| 130 | ); | ||
| 131 | return -1; | ||
| 132 | } | ||
| 133 | EXPORT_SYMBOL(lockref_put_return); | ||
| 134 | |||
| 135 | /** | ||
| 116 | * lockref_put_or_lock - decrements count unless count <= 1 before decrement | 136 | * lockref_put_or_lock - decrements count unless count <= 1 before decrement |
| 117 | * @lockref: pointer to lockref structure | 137 | * @lockref: pointer to lockref structure |
| 118 | * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken | 138 | * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken |
| @@ -158,7 +178,7 @@ int lockref_get_not_dead(struct lockref *lockref) | |||
| 158 | 178 | ||
| 159 | CMPXCHG_LOOP( | 179 | CMPXCHG_LOOP( |
| 160 | new.count++; | 180 | new.count++; |
| 161 | if ((int)old.count < 0) | 181 | if (old.count < 0) |
| 162 | return 0; | 182 | return 0; |
| 163 | , | 183 | , |
| 164 | return 1; | 184 | return 1; |
| @@ -166,7 +186,7 @@ int lockref_get_not_dead(struct lockref *lockref) | |||
| 166 | 186 | ||
| 167 | spin_lock(&lockref->lock); | 187 | spin_lock(&lockref->lock); |
| 168 | retval = 0; | 188 | retval = 0; |
| 169 | if ((int) lockref->count >= 0) { | 189 | if (lockref->count >= 0) { |
| 170 | lockref->count++; | 190 | lockref->count++; |
| 171 | retval = 1; | 191 | retval = 1; |
| 172 | } | 192 | } |
diff --git a/security/commoncap.c b/security/commoncap.c index 2915d8503054..f66713bd7450 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -434,7 +434,6 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data | |||
| 434 | */ | 434 | */ |
| 435 | static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap) | 435 | static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap) |
| 436 | { | 436 | { |
| 437 | struct dentry *dentry; | ||
| 438 | int rc = 0; | 437 | int rc = 0; |
| 439 | struct cpu_vfs_cap_data vcaps; | 438 | struct cpu_vfs_cap_data vcaps; |
| 440 | 439 | ||
| @@ -446,9 +445,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c | |||
| 446 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 445 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
| 447 | return 0; | 446 | return 0; |
| 448 | 447 | ||
| 449 | dentry = dget(bprm->file->f_path.dentry); | 448 | rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); |
| 450 | |||
| 451 | rc = get_vfs_caps_from_disk(dentry, &vcaps); | ||
| 452 | if (rc < 0) { | 449 | if (rc < 0) { |
| 453 | if (rc == -EINVAL) | 450 | if (rc == -EINVAL) |
| 454 | printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n", | 451 | printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n", |
| @@ -464,7 +461,6 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c | |||
| 464 | __func__, rc, bprm->filename); | 461 | __func__, rc, bprm->filename); |
| 465 | 462 | ||
| 466 | out: | 463 | out: |
| 467 | dput(dentry); | ||
| 468 | if (rc) | 464 | if (rc) |
| 469 | bprm_clear_caps(bprm); | 465 | bprm_clear_caps(bprm); |
| 470 | 466 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 33db1ad4fd10..1684bcc78b34 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -1195,30 +1195,8 @@ static const struct file_operations sel_commit_bools_ops = { | |||
| 1195 | 1195 | ||
| 1196 | static void sel_remove_entries(struct dentry *de) | 1196 | static void sel_remove_entries(struct dentry *de) |
| 1197 | { | 1197 | { |
| 1198 | struct list_head *node; | 1198 | d_genocide(de); |
| 1199 | 1199 | shrink_dcache_parent(de); | |
| 1200 | spin_lock(&de->d_lock); | ||
| 1201 | node = de->d_subdirs.next; | ||
| 1202 | while (node != &de->d_subdirs) { | ||
| 1203 | struct dentry *d = list_entry(node, struct dentry, d_child); | ||
| 1204 | |||
| 1205 | spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); | ||
| 1206 | list_del_init(node); | ||
| 1207 | |||
| 1208 | if (d->d_inode) { | ||
| 1209 | dget_dlock(d); | ||
| 1210 | spin_unlock(&de->d_lock); | ||
| 1211 | spin_unlock(&d->d_lock); | ||
| 1212 | d_delete(d); | ||
| 1213 | simple_unlink(de->d_inode, d); | ||
| 1214 | dput(d); | ||
| 1215 | spin_lock(&de->d_lock); | ||
| 1216 | } else | ||
| 1217 | spin_unlock(&d->d_lock); | ||
| 1218 | node = de->d_subdirs.next; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | spin_unlock(&de->d_lock); | ||
| 1222 | } | 1200 | } |
| 1223 | 1201 | ||
| 1224 | #define BOOL_DIR_NAME "booleans" | 1202 | #define BOOL_DIR_NAME "booleans" |
| @@ -1668,37 +1646,13 @@ static int sel_make_class_dir_entries(char *classname, int index, | |||
| 1668 | return rc; | 1646 | return rc; |
| 1669 | } | 1647 | } |
| 1670 | 1648 | ||
| 1671 | static void sel_remove_classes(void) | ||
| 1672 | { | ||
| 1673 | struct list_head *class_node; | ||
| 1674 | |||
| 1675 | list_for_each(class_node, &class_dir->d_subdirs) { | ||
| 1676 | struct dentry *class_subdir = list_entry(class_node, | ||
| 1677 | struct dentry, d_child); | ||
| 1678 | struct list_head *class_subdir_node; | ||
| 1679 | |||
| 1680 | list_for_each(class_subdir_node, &class_subdir->d_subdirs) { | ||
| 1681 | struct dentry *d = list_entry(class_subdir_node, | ||
| 1682 | struct dentry, d_child); | ||
| 1683 | |||
| 1684 | if (d->d_inode) | ||
| 1685 | if (d->d_inode->i_mode & S_IFDIR) | ||
| 1686 | sel_remove_entries(d); | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | sel_remove_entries(class_subdir); | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | sel_remove_entries(class_dir); | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | static int sel_make_classes(void) | 1649 | static int sel_make_classes(void) |
| 1696 | { | 1650 | { |
| 1697 | int rc, nclasses, i; | 1651 | int rc, nclasses, i; |
| 1698 | char **classes; | 1652 | char **classes; |
| 1699 | 1653 | ||
| 1700 | /* delete any existing entries */ | 1654 | /* delete any existing entries */ |
| 1701 | sel_remove_classes(); | 1655 | sel_remove_entries(class_dir); |
| 1702 | 1656 | ||
| 1703 | rc = security_get_classes(&classes, &nclasses); | 1657 | rc = security_get_classes(&classes, &nclasses); |
| 1704 | if (rc) | 1658 | if (rc) |
