> Sheesh... Yes, you are right. It was not a problem with the old buffer
> cache, but now... Arrgh. Races in truncate(), film at 11. Pheeewww...
> Unless I'm seriously misunderstanding what happens you've just dug out a
> race in ext2. It doesn't do bforget() on the data blocks in directories.
> If I'm not mistaken the same scenario applies here just fine.
Here goes quick'n'dirty patch. It does bforget(). It should prevent file
corruption.
Mikulas Patocka
--- linux-2.3.19.tar.gz#utar/linux/fs/ext2/truncate.c Tue Jun 29 18:22:08 1999
+++ linux/fs/ext2/truncate.c Fri Oct 8 18:40:36 1999
@@ -101,6 +101,14 @@
* -- WSH, 1998
*/
+/* M.P.: quick & dirty patch to prevent data corruption */
+
+static void brelse_blocks(struct inode *i, unsigned long block_to_free, unsigned long
+count)
+{
+ while (count--)
+ bforget(get_hash_table(i->i_dev, block_to_free++,
+i->i_sb->s_blocksize));
+}
+
/*
* Check whether any of the slots in an indirect block are
* still in use, and if not free the block.
@@ -184,14 +192,17 @@
else if (block_to_free == tmp - free_count)
free_count++;
else {
+ if (!S_ISREG(inode->i_mode)) brelse_blocks(inode,
+block_to_free, free_count);
ext2_free_blocks (inode, block_to_free, free_count);
free_this:
block_to_free = tmp;
free_count = 1;
}
}
- if (free_count > 0)
+ if (free_count > 0) {
+ if (!S_ISREG(inode->i_mode)) brelse_blocks(inode, block_to_free,
+free_count);
ext2_free_blocks (inode, block_to_free, free_count);
+ }
return retry;
}
@@ -247,14 +258,17 @@
else if (block_to_free == tmp - free_count)
free_count++;
else {
+ if (!S_ISREG(inode->i_mode)) brelse_blocks(inode,
+block_to_free, free_count);
ext2_free_blocks (inode, block_to_free, free_count);
free_this:
block_to_free = tmp;
free_count = 1;
}
}
- if (free_count > 0)
+ if (free_count > 0) {
+ if (!S_ISREG(inode->i_mode)) brelse_blocks(inode, block_to_free,
+free_count);
ext2_free_blocks (inode, block_to_free, free_count);
+ }
/*
* Check the block and dispose of the ind_bh buffer.
*/