diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 61338413d9f3..fbd207c55859 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -392,7 +392,7 @@ extern void fat_ent_access_init(struct super_block *sb); extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry); extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent, - int new, int wait); + int new, int old, int wait); extern int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster); extern int fat_free_clusters(struct inode *inode, int cluster); diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index f0801d99dd62..df23fc85f313 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -413,7 +413,7 @@ static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs, } int fat_ent_write(struct inode *inode, struct fat_entry *fatent, - int new, int wait) + int new, int old, int wait) { struct super_block *sb = inode->i_sb; const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; @@ -422,10 +422,25 @@ int fat_ent_write(struct inode *inode, struct fat_entry *fatent, ops->ent_put(fatent, new); if (wait) { err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs); - if (err) + if (err) { + /* + * bhs are not uptodate after I/O error. So we + * can't simply re-dirty to revert. And it + * would not have value to write again on I/O + * error. + */ return err; + } } - return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs); + + err = fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs); + if (err) { + /* Try to revert if got the error on mirror FAT */ + ops->ent_put(fatent, old); + if (wait) + fat_sync_bhs(fatent->bhs, fatent->nr_bhs); + } + return err; } static inline int fat_ent_next(struct msdos_sb_info *sbi, diff --git a/fs/fat/file.c b/fs/fat/file.c index 1c835ca5f21a..6c475c53334c 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -363,7 +363,8 @@ static int fat_free(struct inode *inode, int skip) __func__, MSDOS_I(inode)->i_pos); ret = -EIO; } else if (ret > 0) { - err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait); + err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, ret, + wait); if (err) ret = err; } diff --git a/fs/fat/misc.c b/fs/fat/misc.c index e79762cf1975..c44296756eae 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -133,11 +133,9 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) ret = fat_ent_read(inode, &fatent, last); if (ret >= 0) { int wait = inode_needs_sync(inode); - int old = ret; - ret = fat_ent_write(inode, &fatent, new_dclus, wait); - if (ret < 0) - fat_ent_write(inode, &fatent, old, wait); + ret = fat_ent_write(inode, &fatent, new_dclus, ret, + wait); fatent_brelse(&fatent); } if (ret < 0)