diff options
Diffstat (limited to 'fs/ext2/super.c')
-rw-r--r-- | fs/ext2/super.c | 99 |
1 files changed, 41 insertions, 58 deletions
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 42e4a303b675..71e9eb1fa696 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/random.h> | 26 | #include <linux/random.h> |
27 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
28 | #include <linux/exportfs.h> | 28 | #include <linux/exportfs.h> |
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/vfs.h> | 29 | #include <linux/vfs.h> |
31 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
32 | #include <linux/mount.h> | 31 | #include <linux/mount.h> |
@@ -39,7 +38,7 @@ | |||
39 | #include "xip.h" | 38 | #include "xip.h" |
40 | 39 | ||
41 | static void ext2_sync_super(struct super_block *sb, | 40 | static void ext2_sync_super(struct super_block *sb, |
42 | struct ext2_super_block *es); | 41 | struct ext2_super_block *es, int wait); |
43 | static int ext2_remount (struct super_block * sb, int * flags, char * data); | 42 | static int ext2_remount (struct super_block * sb, int * flags, char * data); |
44 | static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf); | 43 | static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf); |
45 | static int ext2_sync_fs(struct super_block *sb, int wait); | 44 | static int ext2_sync_fs(struct super_block *sb, int wait); |
@@ -52,9 +51,11 @@ void ext2_error (struct super_block * sb, const char * function, | |||
52 | struct ext2_super_block *es = sbi->s_es; | 51 | struct ext2_super_block *es = sbi->s_es; |
53 | 52 | ||
54 | if (!(sb->s_flags & MS_RDONLY)) { | 53 | if (!(sb->s_flags & MS_RDONLY)) { |
54 | spin_lock(&sbi->s_lock); | ||
55 | sbi->s_mount_state |= EXT2_ERROR_FS; | 55 | sbi->s_mount_state |= EXT2_ERROR_FS; |
56 | es->s_state |= cpu_to_le16(EXT2_ERROR_FS); | 56 | es->s_state |= cpu_to_le16(EXT2_ERROR_FS); |
57 | ext2_sync_super(sb, es); | 57 | spin_unlock(&sbi->s_lock); |
58 | ext2_sync_super(sb, es, 1); | ||
58 | } | 59 | } |
59 | 60 | ||
60 | va_start(args, fmt); | 61 | va_start(args, fmt); |
@@ -84,6 +85,9 @@ void ext2_msg(struct super_block *sb, const char *prefix, | |||
84 | va_end(args); | 85 | va_end(args); |
85 | } | 86 | } |
86 | 87 | ||
88 | /* | ||
89 | * This must be called with sbi->s_lock held. | ||
90 | */ | ||
87 | void ext2_update_dynamic_rev(struct super_block *sb) | 91 | void ext2_update_dynamic_rev(struct super_block *sb) |
88 | { | 92 | { |
89 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; | 93 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; |
@@ -115,8 +119,6 @@ static void ext2_put_super (struct super_block * sb) | |||
115 | int i; | 119 | int i; |
116 | struct ext2_sb_info *sbi = EXT2_SB(sb); | 120 | struct ext2_sb_info *sbi = EXT2_SB(sb); |
117 | 121 | ||
118 | lock_kernel(); | ||
119 | |||
120 | if (sb->s_dirt) | 122 | if (sb->s_dirt) |
121 | ext2_write_super(sb); | 123 | ext2_write_super(sb); |
122 | 124 | ||
@@ -124,8 +126,10 @@ static void ext2_put_super (struct super_block * sb) | |||
124 | if (!(sb->s_flags & MS_RDONLY)) { | 126 | if (!(sb->s_flags & MS_RDONLY)) { |
125 | struct ext2_super_block *es = sbi->s_es; | 127 | struct ext2_super_block *es = sbi->s_es; |
126 | 128 | ||
129 | spin_lock(&sbi->s_lock); | ||
127 | es->s_state = cpu_to_le16(sbi->s_mount_state); | 130 | es->s_state = cpu_to_le16(sbi->s_mount_state); |
128 | ext2_sync_super(sb, es); | 131 | spin_unlock(&sbi->s_lock); |
132 | ext2_sync_super(sb, es, 1); | ||
129 | } | 133 | } |
130 | db_count = sbi->s_gdb_count; | 134 | db_count = sbi->s_gdb_count; |
131 | for (i = 0; i < db_count; i++) | 135 | for (i = 0; i < db_count; i++) |
@@ -140,8 +144,6 @@ static void ext2_put_super (struct super_block * sb) | |||
140 | sb->s_fs_info = NULL; | 144 | sb->s_fs_info = NULL; |
141 | kfree(sbi->s_blockgroup_lock); | 145 | kfree(sbi->s_blockgroup_lock); |
142 | kfree(sbi); | 146 | kfree(sbi); |
143 | |||
144 | unlock_kernel(); | ||
145 | } | 147 | } |
146 | 148 | ||
147 | static struct kmem_cache * ext2_inode_cachep; | 149 | static struct kmem_cache * ext2_inode_cachep; |
@@ -209,6 +211,7 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
209 | struct ext2_super_block *es = sbi->s_es; | 211 | struct ext2_super_block *es = sbi->s_es; |
210 | unsigned long def_mount_opts; | 212 | unsigned long def_mount_opts; |
211 | 213 | ||
214 | spin_lock(&sbi->s_lock); | ||
212 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); | 215 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); |
213 | 216 | ||
214 | if (sbi->s_sb_block != 1) | 217 | if (sbi->s_sb_block != 1) |
@@ -281,6 +284,7 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
281 | if (!test_opt(sb, RESERVATION)) | 284 | if (!test_opt(sb, RESERVATION)) |
282 | seq_puts(seq, ",noreservation"); | 285 | seq_puts(seq, ",noreservation"); |
283 | 286 | ||
287 | spin_unlock(&sbi->s_lock); | ||
284 | return 0; | 288 | return 0; |
285 | } | 289 | } |
286 | 290 | ||
@@ -606,7 +610,6 @@ static int ext2_setup_super (struct super_block * sb, | |||
606 | if (!le16_to_cpu(es->s_max_mnt_count)) | 610 | if (!le16_to_cpu(es->s_max_mnt_count)) |
607 | es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); | 611 | es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); |
608 | le16_add_cpu(&es->s_mnt_count, 1); | 612 | le16_add_cpu(&es->s_mnt_count, 1); |
609 | ext2_write_super(sb); | ||
610 | if (test_opt (sb, DEBUG)) | 613 | if (test_opt (sb, DEBUG)) |
611 | ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, fs=%lu, gc=%lu, " | 614 | ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, fs=%lu, gc=%lu, " |
612 | "bpg=%lu, ipg=%lu, mo=%04lx]", | 615 | "bpg=%lu, ipg=%lu, mo=%04lx]", |
@@ -767,6 +770,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
767 | sb->s_fs_info = sbi; | 770 | sb->s_fs_info = sbi; |
768 | sbi->s_sb_block = sb_block; | 771 | sbi->s_sb_block = sb_block; |
769 | 772 | ||
773 | spin_lock_init(&sbi->s_lock); | ||
774 | |||
770 | /* | 775 | /* |
771 | * See what the current blocksize for the device is, and | 776 | * See what the current blocksize for the device is, and |
772 | * use that as the blocksize. Otherwise (or if the blocksize | 777 | * use that as the blocksize. Otherwise (or if the blocksize |
@@ -1079,7 +1084,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
1079 | if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) | 1084 | if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) |
1080 | ext2_msg(sb, KERN_WARNING, | 1085 | ext2_msg(sb, KERN_WARNING, |
1081 | "warning: mounting ext3 filesystem as ext2"); | 1086 | "warning: mounting ext3 filesystem as ext2"); |
1082 | ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); | 1087 | if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY)) |
1088 | sb->s_flags |= MS_RDONLY; | ||
1089 | ext2_write_super(sb); | ||
1083 | return 0; | 1090 | return 0; |
1084 | 1091 | ||
1085 | cantfind_ext2: | 1092 | cantfind_ext2: |
@@ -1120,30 +1127,26 @@ static void ext2_clear_super_error(struct super_block *sb) | |||
1120 | * be remapped. Nothing we can do but to retry the | 1127 | * be remapped. Nothing we can do but to retry the |
1121 | * write and hope for the best. | 1128 | * write and hope for the best. |
1122 | */ | 1129 | */ |
1123 | printk(KERN_ERR "EXT2-fs: %s previous I/O error to " | 1130 | ext2_msg(sb, KERN_ERR, |
1124 | "superblock detected", sb->s_id); | 1131 | "previous I/O error to superblock detected\n"); |
1125 | clear_buffer_write_io_error(sbh); | 1132 | clear_buffer_write_io_error(sbh); |
1126 | set_buffer_uptodate(sbh); | 1133 | set_buffer_uptodate(sbh); |
1127 | } | 1134 | } |
1128 | } | 1135 | } |
1129 | 1136 | ||
1130 | static void ext2_commit_super (struct super_block * sb, | 1137 | static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es, |
1131 | struct ext2_super_block * es) | 1138 | int wait) |
1132 | { | ||
1133 | ext2_clear_super_error(sb); | ||
1134 | es->s_wtime = cpu_to_le32(get_seconds()); | ||
1135 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); | ||
1136 | sb->s_dirt = 0; | ||
1137 | } | ||
1138 | |||
1139 | static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) | ||
1140 | { | 1139 | { |
1141 | ext2_clear_super_error(sb); | 1140 | ext2_clear_super_error(sb); |
1141 | spin_lock(&EXT2_SB(sb)->s_lock); | ||
1142 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); | 1142 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); |
1143 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); | 1143 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); |
1144 | es->s_wtime = cpu_to_le32(get_seconds()); | 1144 | es->s_wtime = cpu_to_le32(get_seconds()); |
1145 | /* unlock before we do IO */ | ||
1146 | spin_unlock(&EXT2_SB(sb)->s_lock); | ||
1145 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); | 1147 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); |
1146 | sync_dirty_buffer(EXT2_SB(sb)->s_sbh); | 1148 | if (wait) |
1149 | sync_dirty_buffer(EXT2_SB(sb)->s_sbh); | ||
1147 | sb->s_dirt = 0; | 1150 | sb->s_dirt = 0; |
1148 | } | 1151 | } |
1149 | 1152 | ||
@@ -1157,43 +1160,18 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) | |||
1157 | * may have been checked while mounted and e2fsck may have | 1160 | * may have been checked while mounted and e2fsck may have |
1158 | * set s_state to EXT2_VALID_FS after some corrections. | 1161 | * set s_state to EXT2_VALID_FS after some corrections. |
1159 | */ | 1162 | */ |
1160 | |||
1161 | static int ext2_sync_fs(struct super_block *sb, int wait) | 1163 | static int ext2_sync_fs(struct super_block *sb, int wait) |
1162 | { | 1164 | { |
1165 | struct ext2_sb_info *sbi = EXT2_SB(sb); | ||
1163 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; | 1166 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; |
1164 | struct buffer_head *sbh = EXT2_SB(sb)->s_sbh; | ||
1165 | |||
1166 | lock_kernel(); | ||
1167 | if (buffer_write_io_error(sbh)) { | ||
1168 | /* | ||
1169 | * Oh, dear. A previous attempt to write the | ||
1170 | * superblock failed. This could happen because the | ||
1171 | * USB device was yanked out. Or it could happen to | ||
1172 | * be a transient write error and maybe the block will | ||
1173 | * be remapped. Nothing we can do but to retry the | ||
1174 | * write and hope for the best. | ||
1175 | */ | ||
1176 | ext2_msg(sb, KERN_ERR, | ||
1177 | "previous I/O error to superblock detected\n"); | ||
1178 | clear_buffer_write_io_error(sbh); | ||
1179 | set_buffer_uptodate(sbh); | ||
1180 | } | ||
1181 | 1167 | ||
1168 | spin_lock(&sbi->s_lock); | ||
1182 | if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { | 1169 | if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { |
1183 | ext2_debug("setting valid to 0\n"); | 1170 | ext2_debug("setting valid to 0\n"); |
1184 | es->s_state &= cpu_to_le16(~EXT2_VALID_FS); | 1171 | es->s_state &= cpu_to_le16(~EXT2_VALID_FS); |
1185 | es->s_free_blocks_count = | ||
1186 | cpu_to_le32(ext2_count_free_blocks(sb)); | ||
1187 | es->s_free_inodes_count = | ||
1188 | cpu_to_le32(ext2_count_free_inodes(sb)); | ||
1189 | es->s_mtime = cpu_to_le32(get_seconds()); | ||
1190 | ext2_sync_super(sb, es); | ||
1191 | } else { | ||
1192 | ext2_commit_super(sb, es); | ||
1193 | } | 1172 | } |
1194 | sb->s_dirt = 0; | 1173 | spin_unlock(&sbi->s_lock); |
1195 | unlock_kernel(); | 1174 | ext2_sync_super(sb, es, wait); |
1196 | |||
1197 | return 0; | 1175 | return 0; |
1198 | } | 1176 | } |
1199 | 1177 | ||
@@ -1215,7 +1193,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1215 | unsigned long old_sb_flags; | 1193 | unsigned long old_sb_flags; |
1216 | int err; | 1194 | int err; |
1217 | 1195 | ||
1218 | lock_kernel(); | 1196 | spin_lock(&sbi->s_lock); |
1219 | 1197 | ||
1220 | /* Store the old options */ | 1198 | /* Store the old options */ |
1221 | old_sb_flags = sb->s_flags; | 1199 | old_sb_flags = sb->s_flags; |
@@ -1254,13 +1232,13 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1254 | sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; | 1232 | sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; |
1255 | } | 1233 | } |
1256 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { | 1234 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { |
1257 | unlock_kernel(); | 1235 | spin_unlock(&sbi->s_lock); |
1258 | return 0; | 1236 | return 0; |
1259 | } | 1237 | } |
1260 | if (*flags & MS_RDONLY) { | 1238 | if (*flags & MS_RDONLY) { |
1261 | if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || | 1239 | if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || |
1262 | !(sbi->s_mount_state & EXT2_VALID_FS)) { | 1240 | !(sbi->s_mount_state & EXT2_VALID_FS)) { |
1263 | unlock_kernel(); | 1241 | spin_unlock(&sbi->s_lock); |
1264 | return 0; | 1242 | return 0; |
1265 | } | 1243 | } |
1266 | /* | 1244 | /* |
@@ -1269,6 +1247,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1269 | */ | 1247 | */ |
1270 | es->s_state = cpu_to_le16(sbi->s_mount_state); | 1248 | es->s_state = cpu_to_le16(sbi->s_mount_state); |
1271 | es->s_mtime = cpu_to_le32(get_seconds()); | 1249 | es->s_mtime = cpu_to_le32(get_seconds()); |
1250 | spin_unlock(&sbi->s_lock); | ||
1251 | ext2_sync_super(sb, es, 1); | ||
1272 | } else { | 1252 | } else { |
1273 | __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, | 1253 | __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, |
1274 | ~EXT2_FEATURE_RO_COMPAT_SUPP); | 1254 | ~EXT2_FEATURE_RO_COMPAT_SUPP); |
@@ -1288,16 +1268,16 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1288 | sbi->s_mount_state = le16_to_cpu(es->s_state); | 1268 | sbi->s_mount_state = le16_to_cpu(es->s_state); |
1289 | if (!ext2_setup_super (sb, es, 0)) | 1269 | if (!ext2_setup_super (sb, es, 0)) |
1290 | sb->s_flags &= ~MS_RDONLY; | 1270 | sb->s_flags &= ~MS_RDONLY; |
1271 | spin_unlock(&sbi->s_lock); | ||
1272 | ext2_write_super(sb); | ||
1291 | } | 1273 | } |
1292 | ext2_sync_super(sb, es); | ||
1293 | unlock_kernel(); | ||
1294 | return 0; | 1274 | return 0; |
1295 | restore_opts: | 1275 | restore_opts: |
1296 | sbi->s_mount_opt = old_opts.s_mount_opt; | 1276 | sbi->s_mount_opt = old_opts.s_mount_opt; |
1297 | sbi->s_resuid = old_opts.s_resuid; | 1277 | sbi->s_resuid = old_opts.s_resuid; |
1298 | sbi->s_resgid = old_opts.s_resgid; | 1278 | sbi->s_resgid = old_opts.s_resgid; |
1299 | sb->s_flags = old_sb_flags; | 1279 | sb->s_flags = old_sb_flags; |
1300 | unlock_kernel(); | 1280 | spin_unlock(&sbi->s_lock); |
1301 | return err; | 1281 | return err; |
1302 | } | 1282 | } |
1303 | 1283 | ||
@@ -1308,6 +1288,8 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) | |||
1308 | struct ext2_super_block *es = sbi->s_es; | 1288 | struct ext2_super_block *es = sbi->s_es; |
1309 | u64 fsid; | 1289 | u64 fsid; |
1310 | 1290 | ||
1291 | spin_lock(&sbi->s_lock); | ||
1292 | |||
1311 | if (test_opt (sb, MINIX_DF)) | 1293 | if (test_opt (sb, MINIX_DF)) |
1312 | sbi->s_overhead_last = 0; | 1294 | sbi->s_overhead_last = 0; |
1313 | else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { | 1295 | else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { |
@@ -1362,6 +1344,7 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) | |||
1362 | le64_to_cpup((void *)es->s_uuid + sizeof(u64)); | 1344 | le64_to_cpup((void *)es->s_uuid + sizeof(u64)); |
1363 | buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; | 1345 | buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; |
1364 | buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; | 1346 | buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; |
1347 | spin_unlock(&sbi->s_lock); | ||
1365 | return 0; | 1348 | return 0; |
1366 | } | 1349 | } |
1367 | 1350 | ||