aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@poochiereds.net>2014-04-30 09:31:47 -0400
committerSteve French <smfrench@gmail.com>2014-05-21 13:18:05 -0400
commit4f73c7d342d57d065bdbc0995cb56d8d1701b0c0 (patch)
tree6933002e316475c879d702ffbb733a24ba4f0561 /fs/cifs/inode.c
parente284e53fdea1dfd66e73c239fa190685985ae465 (diff)
cifs: fix potential races in cifs_revalidate_mapping
The handling of the CIFS_INO_INVALID_MAPPING flag is racy. It's possible for two tasks to attempt to revalidate the mapping at the same time. The first sees that CIFS_INO_INVALID_MAPPING is set. It clears the flag and then calls invalidate_inode_pages2 to start shooting down the pagecache. While that's going on, another task checks the flag and sees that it's clear. It then ends up trusting the pagecache to satisfy a read when it shouldn't. Fix this by adding a bitlock to ensure that the clearing of the flag is atomic with respect to the actual cache invalidation. Also, move the other existing users of cifs_invalidate_mapping to use a new cifs_zap_mapping() function that just sets the INVALID_MAPPING bit and then uses the standard codepath to handle the invalidation. Signed-off-by: Jeff Layton <jlayton@poochiereds.net> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c50
1 files changed, 41 insertions, 9 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ff420b275777..9ff8df8b4d84 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -22,6 +22,7 @@
22#include <linux/stat.h> 22#include <linux/stat.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/pagemap.h> 24#include <linux/pagemap.h>
25#include <linux/freezer.h>
25#include <asm/div64.h> 26#include <asm/div64.h>
26#include "cifsfs.h" 27#include "cifsfs.h"
27#include "cifspdu.h" 28#include "cifspdu.h"
@@ -1762,29 +1763,60 @@ int
1762cifs_invalidate_mapping(struct inode *inode) 1763cifs_invalidate_mapping(struct inode *inode)
1763{ 1764{
1764 int rc = 0; 1765 int rc = 0;
1765 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1766
1767 clear_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags);
1768 1766
1769 if (inode->i_mapping && inode->i_mapping->nrpages != 0) { 1767 if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
1770 rc = invalidate_inode_pages2(inode->i_mapping); 1768 rc = invalidate_inode_pages2(inode->i_mapping);
1771 if (rc) { 1769 if (rc)
1772 cifs_dbg(VFS, "%s: could not invalidate inode %p\n", 1770 cifs_dbg(VFS, "%s: could not invalidate inode %p\n",
1773 __func__, inode); 1771 __func__, inode);
1774 set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags);
1775 }
1776 } 1772 }
1777 1773
1778 cifs_fscache_reset_inode_cookie(inode); 1774 cifs_fscache_reset_inode_cookie(inode);
1779 return rc; 1775 return rc;
1780} 1776}
1781 1777
1778/**
1779 * cifs_wait_bit_killable - helper for functions that are sleeping on bit locks
1780 * @word: long word containing the bit lock
1781 */
1782static int
1783cifs_wait_bit_killable(void *word)
1784{
1785 if (fatal_signal_pending(current))
1786 return -ERESTARTSYS;
1787 freezable_schedule_unsafe();
1788 return 0;
1789}
1790
1782int 1791int
1783cifs_revalidate_mapping(struct inode *inode) 1792cifs_revalidate_mapping(struct inode *inode)
1784{ 1793{
1785 if (test_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(inode)->flags)) 1794 int rc;
1786 return cifs_invalidate_mapping(inode); 1795 unsigned long *flags = &CIFS_I(inode)->flags;
1787 return 0; 1796
1797 rc = wait_on_bit_lock(flags, CIFS_INO_LOCK, cifs_wait_bit_killable,
1798 TASK_KILLABLE);
1799 if (rc)
1800 return rc;
1801
1802 if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) {
1803 rc = cifs_invalidate_mapping(inode);
1804 if (rc)
1805 set_bit(CIFS_INO_INVALID_MAPPING, flags);
1806 }
1807
1808 clear_bit_unlock(CIFS_INO_LOCK, flags);
1809 smp_mb__after_clear_bit();
1810 wake_up_bit(flags, CIFS_INO_LOCK);
1811
1812 return rc;
1813}
1814
1815int
1816cifs_zap_mapping(struct inode *inode)
1817{
1818 set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(inode)->flags);
1819 return cifs_revalidate_mapping(inode);
1788} 1820}
1789 1821
1790int cifs_revalidate_file_attr(struct file *filp) 1822int cifs_revalidate_file_attr(struct file *filp)