Skip to content

Commit

Permalink
fat: Fix the race of read/write the FAT12 entry
Browse files Browse the repository at this point in the history
FAT12 entry is 12bits, so it needs 2 phase to update the value.  And
writer and reader access it without any lock, so reader can get the
half updated value.

This fixes the long standing race condition by adding a global
spinlock to only FAT12 for avoiding any impact against FAT16/32.

Signed-off-by: OGAWA Hirofumi <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
OGAWAHirofumi authored and Linus Torvalds committed Jul 16, 2007
1 parent 347e03d commit 98283bb
Showing 1 changed file with 7 additions and 0 deletions.
7 changes: 7 additions & 0 deletions fs/fat/fatent.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ struct fatent_operations {
int (*ent_next)(struct fat_entry *);
};

static DEFINE_SPINLOCK(fat12_entry_lock);

static void fat12_ent_blocknr(struct super_block *sb, int entry,
int *offset, sector_t *blocknr)
{
Expand Down Expand Up @@ -116,10 +118,13 @@ static int fat12_ent_get(struct fat_entry *fatent)
u8 **ent12_p = fatent->u.ent12_p;
int next;

spin_lock(&fat12_entry_lock);
if (fatent->entry & 1)
next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4);
else
next = (*ent12_p[1] << 8) | *ent12_p[0];
spin_unlock(&fat12_entry_lock);

next &= 0x0fff;
if (next >= BAD_FAT12)
next = FAT_ENT_EOF;
Expand Down Expand Up @@ -151,13 +156,15 @@ static void fat12_ent_put(struct fat_entry *fatent, int new)
if (new == FAT_ENT_EOF)
new = EOF_FAT12;

spin_lock(&fat12_entry_lock);
if (fatent->entry & 1) {
*ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f);
*ent12_p[1] = new >> 4;
} else {
*ent12_p[0] = new & 0xff;
*ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8);
}
spin_unlock(&fat12_entry_lock);

mark_buffer_dirty(fatent->bhs[0]);
if (fatent->nr_bhs == 2)
Expand Down

0 comments on commit 98283bb

Please sign in to comment.