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) |