[PATCH 3/3] fat: Fix truncate() write ordering

From: hirofumi
Date: Sun Jan 29 2006 - 10:47:38 EST



The truncate() should write the file size before writing the new EOF entry.
This patch fixes it.

This bug was pointed out by Machida Hiroyuki.

Signed-off-by: OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx>
---

fs/fat/file.c | 50 +++++++++++++++++++++++---------------------------
1 file changed, 23 insertions(+), 27 deletions(-)

diff -puN fs/fat/file.c~fat_truncate-sync-fix fs/fat/file.c
--- linux-2.6/fs/fat/file.c~fat_truncate-sync-fix 2006-01-12 21:53:06.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/file.c 2006-01-12 21:53:06.000000000 +0900
@@ -210,10 +210,30 @@ static int fat_free(struct inode *inode,
if (MSDOS_I(inode)->i_start == 0)
return 0;

- /*
- * Write a new EOF, and get the remaining cluster chain for freeing.
- */
+ fat_cache_inval_inode(inode);
+
wait = IS_DIRSYNC(inode);
+ i_start = free_start = MSDOS_I(inode)->i_start;
+ i_logstart = MSDOS_I(inode)->i_logstart;
+
+ /* First, we write the new file size. */
+ if (!skip) {
+ MSDOS_I(inode)->i_start = 0;
+ MSDOS_I(inode)->i_logstart = 0;
+ }
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ if (wait) {
+ err = fat_sync_inode(inode);
+ if (err) {
+ MSDOS_I(inode)->i_start = i_start;
+ MSDOS_I(inode)->i_logstart = i_logstart;
+ return err;
+ }
+ } else
+ mark_inode_dirty(inode);
+
+ /* Write a new EOF, and get the remaining cluster chain for freeing. */
if (skip) {
struct fat_entry fatent;
int ret, fclus, dclus;
@@ -244,35 +264,11 @@ static int fat_free(struct inode *inode,
return ret;

free_start = ret;
- i_start = i_logstart = 0;
- fat_cache_inval_inode(inode);
- } else {
- fat_cache_inval_inode(inode);
-
- i_start = free_start = MSDOS_I(inode)->i_start;
- i_logstart = MSDOS_I(inode)->i_logstart;
- MSDOS_I(inode)->i_start = 0;
- MSDOS_I(inode)->i_logstart = 0;
}
- MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
- if (wait) {
- err = fat_sync_inode(inode);
- if (err)
- goto error;
- } else
- mark_inode_dirty(inode);
inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);

/* Freeing the remained cluster chain */
return fat_free_clusters(inode, free_start);
-
-error:
- if (i_start) {
- MSDOS_I(inode)->i_start = i_start;
- MSDOS_I(inode)->i_logstart = i_logstart;
- }
- return err;
}

void fat_truncate(struct inode *inode)
_
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/