diff options
author | Theodore Ts'o <tytso@mit.edu> | 2014-03-24 14:43:12 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-03-24 14:43:12 -0400 |
commit | 5f16f3225b06242a9ee876f07c1c9b6ed36a22b6 (patch) | |
tree | cebecf399c2d9ef5b0a24902638cb37d2e9e092b /fs/inode.c | |
parent | ed3654eb981fd44694b4d2a636e13f998bc10e7f (diff) |
ext4: atomically set inode->i_flags in ext4_set_inode_flags()
Use cmpxchg() to atomically set i_flags instead of clearing out the
S_IMMUTABLE, S_APPEND, etc. flags and then setting them from the
EXT4_IMMUTABLE_FL, EXT4_APPEND_FL flags, since this opens up a race
where an immutable file has the immutable flag cleared for a brief
window of time.
Reported-by: John Sullivan <jsrhbz@kanargh.force9.co.uk>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: stable@kernel.org
Diffstat (limited to 'fs/inode.c')
-rw-r--r-- | fs/inode.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/fs/inode.c b/fs/inode.c index 4bcdad3c9361..26f95ceb6250 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -1899,3 +1899,34 @@ void inode_dio_done(struct inode *inode) | |||
1899 | wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); | 1899 | wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); |
1900 | } | 1900 | } |
1901 | EXPORT_SYMBOL(inode_dio_done); | 1901 | EXPORT_SYMBOL(inode_dio_done); |
1902 | |||
1903 | /* | ||
1904 | * inode_set_flags - atomically set some inode flags | ||
1905 | * | ||
1906 | * Note: the caller should be holding i_mutex, or else be sure that | ||
1907 | * they have exclusive access to the inode structure (i.e., while the | ||
1908 | * inode is being instantiated). The reason for the cmpxchg() loop | ||
1909 | * --- which wouldn't be necessary if all code paths which modify | ||
1910 | * i_flags actually followed this rule, is that there is at least one | ||
1911 | * code path which doesn't today --- for example, | ||
1912 | * __generic_file_aio_write() calls file_remove_suid() without holding | ||
1913 | * i_mutex --- so we use cmpxchg() out of an abundance of caution. | ||
1914 | * | ||
1915 | * In the long run, i_mutex is overkill, and we should probably look | ||
1916 | * at using the i_lock spinlock to protect i_flags, and then make sure | ||
1917 | * it is so documented in include/linux/fs.h and that all code follows | ||
1918 | * the locking convention!! | ||
1919 | */ | ||
1920 | void inode_set_flags(struct inode *inode, unsigned int flags, | ||
1921 | unsigned int mask) | ||
1922 | { | ||
1923 | unsigned int old_flags, new_flags; | ||
1924 | |||
1925 | WARN_ON_ONCE(flags & ~mask); | ||
1926 | do { | ||
1927 | old_flags = ACCESS_ONCE(inode->i_flags); | ||
1928 | new_flags = (old_flags & ~mask) | flags; | ||
1929 | } while (unlikely(cmpxchg(&inode->i_flags, old_flags, | ||
1930 | new_flags) != old_flags)); | ||
1931 | } | ||
1932 | EXPORT_SYMBOL(inode_set_flags); | ||