History

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.

Theodore Ts'o committed 12 years ago

Commit 00a1a051 parent 981e8932 files · +24 −6Browse files

Unified · Split

2 files
  1. fs/ext4/inode.c +9 −6
  2. include/linux/bitops.h +15 −0
fs/ext4/inode.c+9−6
@@ -38,6 +38,7 @@ · 37 unmodified lines
38#include <linux/slab.h>38#include <linux/slab.h>
39#include <linux/ratelimit.h>39#include <linux/ratelimit.h>
40#include <linux/aio.h>40#include <linux/aio.h>
41#include <linux/bitops.h>
41 42
42#include "ext4_jbd2.h"43#include "ext4_jbd2.h"
43#include "xattr.h"44#include "xattr.h"
@@ -3921,18 +3922,20 @@ int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc) · 3877 unmodified lines
3921void ext4_set_inode_flags(struct inode *inode)3922void ext4_set_inode_flags(struct inode *inode)
3922{3923{
3923 unsigned int flags = EXT4_I(inode)->i_flags;3924 unsigned int flags = EXT4_I(inode)->i_flags;
3925 unsigned int new_fl = 0;
3924 3926
3925 inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
3926 if (flags & EXT4_SYNC_FL)3927 if (flags & EXT4_SYNC_FL)
3927 inode->i_flags |= S_SYNC;3928 new_fl |= S_SYNC;
3928 if (flags & EXT4_APPEND_FL)3929 if (flags & EXT4_APPEND_FL)
3929 inode->i_flags |= S_APPEND;3930 new_fl |= S_APPEND;
3930 if (flags & EXT4_IMMUTABLE_FL)3931 if (flags & EXT4_IMMUTABLE_FL)
3931 inode->i_flags |= S_IMMUTABLE;3932 new_fl |= S_IMMUTABLE;
3932 if (flags & EXT4_NOATIME_FL)3933 if (flags & EXT4_NOATIME_FL)
3933 inode->i_flags |= S_NOATIME;3934 new_fl |= S_NOATIME;
3934 if (flags & EXT4_DIRSYNC_FL)3935 if (flags & EXT4_DIRSYNC_FL)
3935 inode->i_flags |= S_DIRSYNC;3936 new_fl |= S_DIRSYNC;
3937 set_mask_bits(&inode->i_flags,
3938 S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl);
3936}3939}
3937 3940
3938/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */3941/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
include/linux/bitops.h+15−0
@@ -196,6 +196,21 @@ static inline unsigned long __ffs64(u64 word) · 195 unmodified lines
196 196
197#ifdef __KERNEL__197#ifdef __KERNEL__
198 198
199#ifndef set_mask_bits
200#define set_mask_bits(ptr, _mask, _bits) \
201({ \
202 const typeof(*ptr) mask = (_mask), bits = (_bits); \
203 typeof(*ptr) old, new; \
204 \
205 do { \
206 old = ACCESS_ONCE(*ptr); \
207 new = (old & ~mask) | bits; \
208 } while (cmpxchg(ptr, old, new) != old); \
209 \
210 new; \
211})
212#endif
213
199#ifndef find_last_bit214#ifndef find_last_bit
200/**215/**
201 * find_last_bit - find the last set bit in a memory region216 * find_last_bit - find the last set bit in a memory region