diff options
Diffstat (limited to 'fs/ext2')
-rw-r--r-- | fs/ext2/dir.c | 2 | ||||
-rw-r--r-- | fs/ext2/ext2.h | 1 | ||||
-rw-r--r-- | fs/ext2/file.c | 21 | ||||
-rw-r--r-- | fs/ext2/super.c | 22 |
4 files changed, 43 insertions, 3 deletions
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index fc2bd05d3559..7516957273ed 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c | |||
@@ -721,5 +721,5 @@ const struct file_operations ext2_dir_operations = { | |||
721 | #ifdef CONFIG_COMPAT | 721 | #ifdef CONFIG_COMPAT |
722 | .compat_ioctl = ext2_compat_ioctl, | 722 | .compat_ioctl = ext2_compat_ioctl, |
723 | #endif | 723 | #endif |
724 | .fsync = simple_fsync, | 724 | .fsync = ext2_fsync, |
725 | }; | 725 | }; |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index da318b0fa637..061914add3cf 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -155,6 +155,7 @@ extern void ext2_write_super (struct super_block *); | |||
155 | extern const struct file_operations ext2_dir_operations; | 155 | extern const struct file_operations ext2_dir_operations; |
156 | 156 | ||
157 | /* file.c */ | 157 | /* file.c */ |
158 | extern int ext2_fsync(struct file *file, struct dentry *dentry, int datasync); | ||
158 | extern const struct inode_operations ext2_file_inode_operations; | 159 | extern const struct inode_operations ext2_file_inode_operations; |
159 | extern const struct file_operations ext2_file_operations; | 160 | extern const struct file_operations ext2_file_operations; |
160 | extern const struct file_operations ext2_xip_file_operations; | 161 | extern const struct file_operations ext2_xip_file_operations; |
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index a2f3afd1a1c1..586e3589d4c2 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
@@ -19,6 +19,7 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/time.h> | 21 | #include <linux/time.h> |
22 | #include <linux/pagemap.h> | ||
22 | #include "ext2.h" | 23 | #include "ext2.h" |
23 | #include "xattr.h" | 24 | #include "xattr.h" |
24 | #include "acl.h" | 25 | #include "acl.h" |
@@ -38,6 +39,22 @@ static int ext2_release_file (struct inode * inode, struct file * filp) | |||
38 | return 0; | 39 | return 0; |
39 | } | 40 | } |
40 | 41 | ||
42 | int ext2_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
43 | { | ||
44 | int ret; | ||
45 | struct super_block *sb = dentry->d_inode->i_sb; | ||
46 | struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; | ||
47 | |||
48 | ret = simple_fsync(file, dentry, datasync); | ||
49 | if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { | ||
50 | /* We don't really know where the IO error happened... */ | ||
51 | ext2_error(sb, __func__, | ||
52 | "detected IO error when writing metadata buffers"); | ||
53 | ret = -EIO; | ||
54 | } | ||
55 | return ret; | ||
56 | } | ||
57 | |||
41 | /* | 58 | /* |
42 | * We have mostly NULL's here: the current defaults are ok for | 59 | * We have mostly NULL's here: the current defaults are ok for |
43 | * the ext2 filesystem. | 60 | * the ext2 filesystem. |
@@ -55,7 +72,7 @@ const struct file_operations ext2_file_operations = { | |||
55 | .mmap = generic_file_mmap, | 72 | .mmap = generic_file_mmap, |
56 | .open = generic_file_open, | 73 | .open = generic_file_open, |
57 | .release = ext2_release_file, | 74 | .release = ext2_release_file, |
58 | .fsync = simple_fsync, | 75 | .fsync = ext2_fsync, |
59 | .splice_read = generic_file_splice_read, | 76 | .splice_read = generic_file_splice_read, |
60 | .splice_write = generic_file_splice_write, | 77 | .splice_write = generic_file_splice_write, |
61 | }; | 78 | }; |
@@ -72,7 +89,7 @@ const struct file_operations ext2_xip_file_operations = { | |||
72 | .mmap = xip_file_mmap, | 89 | .mmap = xip_file_mmap, |
73 | .open = generic_file_open, | 90 | .open = generic_file_open, |
74 | .release = ext2_release_file, | 91 | .release = ext2_release_file, |
75 | .fsync = simple_fsync, | 92 | .fsync = ext2_fsync, |
76 | }; | 93 | }; |
77 | #endif | 94 | #endif |
78 | 95 | ||
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 1388802b7803..f9cb54a585ce 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -1105,9 +1105,30 @@ failed_sbi: | |||
1105 | return ret; | 1105 | return ret; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | static void ext2_clear_super_error(struct super_block *sb) | ||
1109 | { | ||
1110 | struct buffer_head *sbh = EXT2_SB(sb)->s_sbh; | ||
1111 | |||
1112 | if (buffer_write_io_error(sbh)) { | ||
1113 | /* | ||
1114 | * Oh, dear. A previous attempt to write the | ||
1115 | * superblock failed. This could happen because the | ||
1116 | * USB device was yanked out. Or it could happen to | ||
1117 | * be a transient write error and maybe the block will | ||
1118 | * be remapped. Nothing we can do but to retry the | ||
1119 | * write and hope for the best. | ||
1120 | */ | ||
1121 | printk(KERN_ERR "EXT2-fs: %s previous I/O error to " | ||
1122 | "superblock detected", sb->s_id); | ||
1123 | clear_buffer_write_io_error(sbh); | ||
1124 | set_buffer_uptodate(sbh); | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1108 | static void ext2_commit_super (struct super_block * sb, | 1128 | static void ext2_commit_super (struct super_block * sb, |
1109 | struct ext2_super_block * es) | 1129 | struct ext2_super_block * es) |
1110 | { | 1130 | { |
1131 | ext2_clear_super_error(sb); | ||
1111 | es->s_wtime = cpu_to_le32(get_seconds()); | 1132 | es->s_wtime = cpu_to_le32(get_seconds()); |
1112 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); | 1133 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); |
1113 | sb->s_dirt = 0; | 1134 | sb->s_dirt = 0; |
@@ -1115,6 +1136,7 @@ static void ext2_commit_super (struct super_block * sb, | |||
1115 | 1136 | ||
1116 | static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) | 1137 | static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) |
1117 | { | 1138 | { |
1139 | ext2_clear_super_error(sb); | ||
1118 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); | 1140 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); |
1119 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); | 1141 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); |
1120 | es->s_wtime = cpu_to_le32(get_seconds()); | 1142 | es->s_wtime = cpu_to_le32(get_seconds()); |