diff options
Diffstat (limited to 'fs/inode.c')
-rw-r--r-- | fs/inode.c | 54 |
1 files changed, 35 insertions, 19 deletions
diff --git a/fs/inode.c b/fs/inode.c index 0647d80accf6..0b3da4a77704 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/async.h> | 25 | #include <linux/async.h> |
26 | #include <linux/posix_acl.h> | 26 | #include <linux/posix_acl.h> |
27 | #include <linux/ima.h> | 27 | #include <linux/ima.h> |
28 | #include <linux/cred.h> | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * This is needed for the following functions: | 31 | * This is needed for the following functions: |
@@ -84,16 +85,13 @@ static struct hlist_head *inode_hashtable __read_mostly; | |||
84 | DEFINE_SPINLOCK(inode_lock); | 85 | DEFINE_SPINLOCK(inode_lock); |
85 | 86 | ||
86 | /* | 87 | /* |
87 | * iprune_sem provides exclusion between the kswapd or try_to_free_pages | 88 | * iprune_sem provides exclusion between the icache shrinking and the |
88 | * icache shrinking path, and the umount path. Without this exclusion, | 89 | * umount path. |
89 | * by the time prune_icache calls iput for the inode whose pages it has | ||
90 | * been invalidating, or by the time it calls clear_inode & destroy_inode | ||
91 | * from its final dispose_list, the struct super_block they refer to | ||
92 | * (for inode->i_sb->s_op) may already have been freed and reused. | ||
93 | * | 90 | * |
94 | * We make this an rwsem because the fastpath is icache shrinking. In | 91 | * We don't actually need it to protect anything in the umount path, |
95 | * some cases a filesystem may be doing a significant amount of work in | 92 | * but only need to cycle through it to make sure any inode that |
96 | * its inode reclaim code, so this should improve parallelism. | 93 | * prune_icache took off the LRU list has been fully torn down by the |
94 | * time we are past evict_inodes. | ||
97 | */ | 95 | */ |
98 | static DECLARE_RWSEM(iprune_sem); | 96 | static DECLARE_RWSEM(iprune_sem); |
99 | 97 | ||
@@ -516,17 +514,12 @@ void evict_inodes(struct super_block *sb) | |||
516 | struct inode *inode, *next; | 514 | struct inode *inode, *next; |
517 | LIST_HEAD(dispose); | 515 | LIST_HEAD(dispose); |
518 | 516 | ||
519 | down_write(&iprune_sem); | ||
520 | |||
521 | spin_lock(&inode_lock); | 517 | spin_lock(&inode_lock); |
522 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | 518 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { |
523 | if (atomic_read(&inode->i_count)) | 519 | if (atomic_read(&inode->i_count)) |
524 | continue; | 520 | continue; |
525 | 521 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) | |
526 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { | ||
527 | WARN_ON(1); | ||
528 | continue; | 522 | continue; |
529 | } | ||
530 | 523 | ||
531 | inode->i_state |= I_FREEING; | 524 | inode->i_state |= I_FREEING; |
532 | 525 | ||
@@ -542,6 +535,13 @@ void evict_inodes(struct super_block *sb) | |||
542 | spin_unlock(&inode_lock); | 535 | spin_unlock(&inode_lock); |
543 | 536 | ||
544 | dispose_list(&dispose); | 537 | dispose_list(&dispose); |
538 | |||
539 | /* | ||
540 | * Cycle through iprune_sem to make sure any inode that prune_icache | ||
541 | * moved off the list before we took the lock has been fully torn | ||
542 | * down. | ||
543 | */ | ||
544 | down_write(&iprune_sem); | ||
545 | up_write(&iprune_sem); | 545 | up_write(&iprune_sem); |
546 | } | 546 | } |
547 | 547 | ||
@@ -561,8 +561,6 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) | |||
561 | struct inode *inode, *next; | 561 | struct inode *inode, *next; |
562 | LIST_HEAD(dispose); | 562 | LIST_HEAD(dispose); |
563 | 563 | ||
564 | down_write(&iprune_sem); | ||
565 | |||
566 | spin_lock(&inode_lock); | 564 | spin_lock(&inode_lock); |
567 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | 565 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { |
568 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) | 566 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) |
@@ -590,7 +588,6 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) | |||
590 | spin_unlock(&inode_lock); | 588 | spin_unlock(&inode_lock); |
591 | 589 | ||
592 | dispose_list(&dispose); | 590 | dispose_list(&dispose); |
593 | up_write(&iprune_sem); | ||
594 | 591 | ||
595 | return busy; | 592 | return busy; |
596 | } | 593 | } |
@@ -1719,7 +1716,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) | |||
1719 | EXPORT_SYMBOL(init_special_inode); | 1716 | EXPORT_SYMBOL(init_special_inode); |
1720 | 1717 | ||
1721 | /** | 1718 | /** |
1722 | * Init uid,gid,mode for new inode according to posix standards | 1719 | * inode_init_owner - Init uid,gid,mode for new inode according to posix standards |
1723 | * @inode: New inode | 1720 | * @inode: New inode |
1724 | * @dir: Directory inode | 1721 | * @dir: Directory inode |
1725 | * @mode: mode of the new inode | 1722 | * @mode: mode of the new inode |
@@ -1737,3 +1734,22 @@ void inode_init_owner(struct inode *inode, const struct inode *dir, | |||
1737 | inode->i_mode = mode; | 1734 | inode->i_mode = mode; |
1738 | } | 1735 | } |
1739 | EXPORT_SYMBOL(inode_init_owner); | 1736 | EXPORT_SYMBOL(inode_init_owner); |
1737 | |||
1738 | /** | ||
1739 | * inode_owner_or_capable - check current task permissions to inode | ||
1740 | * @inode: inode being checked | ||
1741 | * | ||
1742 | * Return true if current either has CAP_FOWNER to the inode, or | ||
1743 | * owns the file. | ||
1744 | */ | ||
1745 | bool inode_owner_or_capable(const struct inode *inode) | ||
1746 | { | ||
1747 | struct user_namespace *ns = inode_userns(inode); | ||
1748 | |||
1749 | if (current_user_ns() == ns && current_fsuid() == inode->i_uid) | ||
1750 | return true; | ||
1751 | if (ns_capable(ns, CAP_FOWNER)) | ||
1752 | return true; | ||
1753 | return false; | ||
1754 | } | ||
1755 | EXPORT_SYMBOL(inode_owner_or_capable); | ||