diff options
author | Theodore Ts'o <tytso@mit.edu> | 2014-03-30 10:20:01 -0400 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2014-04-09 02:20:44 +0100 |
commit | 630176c5033a4ed19a0fc6608980344657ba69af (patch) | |
tree | c17836439326d14eaedced9087a655e4534ede90 /include/linux | |
parent | f0a9fdec2b5a1f82a72a845b09a4ff09c4e7e1ea (diff) | |
download | lwn-630176c5033a4ed19a0fc6608980344657ba69af.tar.gz lwn-630176c5033a4ed19a0fc6608980344657ba69af.zip |
ext4: atomically set inode->i_flags in ext4_set_inode_flags()
commit 00a1a053ebe5febcfc2ec498bd894f035ad2aa06 upstream.
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>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/bitops.h | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/include/linux/bitops.h b/include/linux/bitops.h index fc8a3ffce320..87a375f4e051 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -168,6 +168,21 @@ static inline unsigned long __ffs64(u64 word) #ifdef __KERNEL__ +#ifndef set_mask_bits +#define set_mask_bits(ptr, _mask, _bits) \ +({ \ + const typeof(*ptr) mask = (_mask), bits = (_bits); \ + typeof(*ptr) old, new; \ + \ + do { \ + old = ACCESS_ONCE(*ptr); \ + new = (old & ~mask) | bits; \ + } while (cmpxchg(ptr, old, new) != old); \ + \ + new; \ +}) +#endif + #ifndef find_last_bit /** * find_last_bit - find the last set bit in a memory region |