diff options
-rw-r--r-- | fs/ext2/inode.c | 2 | ||||
-rw-r--r-- | fs/ext2/super.c | 27 | ||||
-rw-r--r-- | fs/ext2/xattr.c | 2 | ||||
-rw-r--r-- | include/linux/ext2_fs_sb.h | 9 |
4 files changed, 39 insertions, 1 deletions
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index fc13cc119aad..5d15442abbd0 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -1407,9 +1407,11 @@ static int __ext2_write_inode(struct inode *inode, int do_sync) | |||
1407 | * created, add a flag to the superblock. | 1407 | * created, add a flag to the superblock. |
1408 | */ | 1408 | */ |
1409 | lock_kernel(); | 1409 | lock_kernel(); |
1410 | spin_lock(&EXT2_SB(sb)->s_lock); | ||
1410 | ext2_update_dynamic_rev(sb); | 1411 | ext2_update_dynamic_rev(sb); |
1411 | EXT2_SET_RO_COMPAT_FEATURE(sb, | 1412 | EXT2_SET_RO_COMPAT_FEATURE(sb, |
1412 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE); | 1413 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE); |
1414 | spin_unlock(&EXT2_SB(sb)->s_lock); | ||
1413 | unlock_kernel(); | 1415 | unlock_kernel(); |
1414 | ext2_write_super(sb); | 1416 | ext2_write_super(sb); |
1415 | } | 1417 | } |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index f28a7ad02af9..28f65609589d 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -52,8 +52,10 @@ void ext2_error (struct super_block * sb, const char * function, | |||
52 | struct ext2_super_block *es = sbi->s_es; | 52 | struct ext2_super_block *es = sbi->s_es; |
53 | 53 | ||
54 | if (!(sb->s_flags & MS_RDONLY)) { | 54 | if (!(sb->s_flags & MS_RDONLY)) { |
55 | spin_lock(&sbi->s_lock); | ||
55 | sbi->s_mount_state |= EXT2_ERROR_FS; | 56 | sbi->s_mount_state |= EXT2_ERROR_FS; |
56 | es->s_state |= cpu_to_le16(EXT2_ERROR_FS); | 57 | es->s_state |= cpu_to_le16(EXT2_ERROR_FS); |
58 | spin_unlock(&sbi->s_lock); | ||
57 | ext2_sync_super(sb, es, 1); | 59 | ext2_sync_super(sb, es, 1); |
58 | } | 60 | } |
59 | 61 | ||
@@ -84,6 +86,9 @@ void ext2_msg(struct super_block *sb, const char *prefix, | |||
84 | va_end(args); | 86 | va_end(args); |
85 | } | 87 | } |
86 | 88 | ||
89 | /* | ||
90 | * This must be called with sbi->s_lock held. | ||
91 | */ | ||
87 | void ext2_update_dynamic_rev(struct super_block *sb) | 92 | void ext2_update_dynamic_rev(struct super_block *sb) |
88 | { | 93 | { |
89 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; | 94 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; |
@@ -124,7 +129,9 @@ static void ext2_put_super (struct super_block * sb) | |||
124 | if (!(sb->s_flags & MS_RDONLY)) { | 129 | if (!(sb->s_flags & MS_RDONLY)) { |
125 | struct ext2_super_block *es = sbi->s_es; | 130 | struct ext2_super_block *es = sbi->s_es; |
126 | 131 | ||
132 | spin_lock(&sbi->s_lock); | ||
127 | es->s_state = cpu_to_le16(sbi->s_mount_state); | 133 | es->s_state = cpu_to_le16(sbi->s_mount_state); |
134 | spin_unlock(&sbi->s_lock); | ||
128 | ext2_sync_super(sb, es, 1); | 135 | ext2_sync_super(sb, es, 1); |
129 | } | 136 | } |
130 | db_count = sbi->s_gdb_count; | 137 | db_count = sbi->s_gdb_count; |
@@ -209,6 +216,7 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
209 | struct ext2_super_block *es = sbi->s_es; | 216 | struct ext2_super_block *es = sbi->s_es; |
210 | unsigned long def_mount_opts; | 217 | unsigned long def_mount_opts; |
211 | 218 | ||
219 | spin_lock(&sbi->s_lock); | ||
212 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); | 220 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); |
213 | 221 | ||
214 | if (sbi->s_sb_block != 1) | 222 | if (sbi->s_sb_block != 1) |
@@ -281,6 +289,7 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
281 | if (!test_opt(sb, RESERVATION)) | 289 | if (!test_opt(sb, RESERVATION)) |
282 | seq_puts(seq, ",noreservation"); | 290 | seq_puts(seq, ",noreservation"); |
283 | 291 | ||
292 | spin_unlock(&sbi->s_lock); | ||
284 | return 0; | 293 | return 0; |
285 | } | 294 | } |
286 | 295 | ||
@@ -766,6 +775,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
766 | sb->s_fs_info = sbi; | 775 | sb->s_fs_info = sbi; |
767 | sbi->s_sb_block = sb_block; | 776 | sbi->s_sb_block = sb_block; |
768 | 777 | ||
778 | spin_lock_init(&sbi->s_lock); | ||
779 | |||
769 | /* | 780 | /* |
770 | * See what the current blocksize for the device is, and | 781 | * See what the current blocksize for the device is, and |
771 | * use that as the blocksize. Otherwise (or if the blocksize | 782 | * use that as the blocksize. Otherwise (or if the blocksize |
@@ -1132,9 +1143,12 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es, | |||
1132 | int wait) | 1143 | int wait) |
1133 | { | 1144 | { |
1134 | ext2_clear_super_error(sb); | 1145 | ext2_clear_super_error(sb); |
1146 | spin_lock(&EXT2_SB(sb)->s_lock); | ||
1135 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); | 1147 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); |
1136 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); | 1148 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); |
1137 | es->s_wtime = cpu_to_le32(get_seconds()); | 1149 | es->s_wtime = cpu_to_le32(get_seconds()); |
1150 | /* unlock before we do IO */ | ||
1151 | spin_unlock(&EXT2_SB(sb)->s_lock); | ||
1138 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); | 1152 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); |
1139 | if (wait) | 1153 | if (wait) |
1140 | sync_dirty_buffer(EXT2_SB(sb)->s_sbh); | 1154 | sync_dirty_buffer(EXT2_SB(sb)->s_sbh); |
@@ -1151,16 +1165,18 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es, | |||
1151 | * may have been checked while mounted and e2fsck may have | 1165 | * may have been checked while mounted and e2fsck may have |
1152 | * set s_state to EXT2_VALID_FS after some corrections. | 1166 | * set s_state to EXT2_VALID_FS after some corrections. |
1153 | */ | 1167 | */ |
1154 | |||
1155 | static int ext2_sync_fs(struct super_block *sb, int wait) | 1168 | static int ext2_sync_fs(struct super_block *sb, int wait) |
1156 | { | 1169 | { |
1170 | struct ext2_sb_info *sbi = EXT2_SB(sb); | ||
1157 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; | 1171 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; |
1158 | 1172 | ||
1159 | lock_kernel(); | 1173 | lock_kernel(); |
1174 | spin_lock(&sbi->s_lock); | ||
1160 | if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { | 1175 | if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { |
1161 | ext2_debug("setting valid to 0\n"); | 1176 | ext2_debug("setting valid to 0\n"); |
1162 | es->s_state &= cpu_to_le16(~EXT2_VALID_FS); | 1177 | es->s_state &= cpu_to_le16(~EXT2_VALID_FS); |
1163 | } | 1178 | } |
1179 | spin_unlock(&sbi->s_lock); | ||
1164 | ext2_sync_super(sb, es, wait); | 1180 | ext2_sync_super(sb, es, wait); |
1165 | unlock_kernel(); | 1181 | unlock_kernel(); |
1166 | 1182 | ||
@@ -1186,6 +1202,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1186 | int err; | 1202 | int err; |
1187 | 1203 | ||
1188 | lock_kernel(); | 1204 | lock_kernel(); |
1205 | spin_lock(&sbi->s_lock); | ||
1189 | 1206 | ||
1190 | /* Store the old options */ | 1207 | /* Store the old options */ |
1191 | old_sb_flags = sb->s_flags; | 1208 | old_sb_flags = sb->s_flags; |
@@ -1224,12 +1241,14 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1224 | sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; | 1241 | sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; |
1225 | } | 1242 | } |
1226 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { | 1243 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { |
1244 | spin_unlock(&sbi->s_lock); | ||
1227 | unlock_kernel(); | 1245 | unlock_kernel(); |
1228 | return 0; | 1246 | return 0; |
1229 | } | 1247 | } |
1230 | if (*flags & MS_RDONLY) { | 1248 | if (*flags & MS_RDONLY) { |
1231 | if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || | 1249 | if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || |
1232 | !(sbi->s_mount_state & EXT2_VALID_FS)) { | 1250 | !(sbi->s_mount_state & EXT2_VALID_FS)) { |
1251 | spin_unlock(&sbi->s_lock); | ||
1233 | unlock_kernel(); | 1252 | unlock_kernel(); |
1234 | return 0; | 1253 | return 0; |
1235 | } | 1254 | } |
@@ -1239,6 +1258,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1239 | */ | 1258 | */ |
1240 | es->s_state = cpu_to_le16(sbi->s_mount_state); | 1259 | es->s_state = cpu_to_le16(sbi->s_mount_state); |
1241 | es->s_mtime = cpu_to_le32(get_seconds()); | 1260 | es->s_mtime = cpu_to_le32(get_seconds()); |
1261 | spin_unlock(&sbi->s_lock); | ||
1242 | ext2_sync_super(sb, es, 1); | 1262 | ext2_sync_super(sb, es, 1); |
1243 | } else { | 1263 | } else { |
1244 | __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, | 1264 | __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, |
@@ -1259,6 +1279,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
1259 | sbi->s_mount_state = le16_to_cpu(es->s_state); | 1279 | sbi->s_mount_state = le16_to_cpu(es->s_state); |
1260 | if (!ext2_setup_super (sb, es, 0)) | 1280 | if (!ext2_setup_super (sb, es, 0)) |
1261 | sb->s_flags &= ~MS_RDONLY; | 1281 | sb->s_flags &= ~MS_RDONLY; |
1282 | spin_unlock(&sbi->s_lock); | ||
1262 | ext2_write_super(sb); | 1283 | ext2_write_super(sb); |
1263 | } | 1284 | } |
1264 | unlock_kernel(); | 1285 | unlock_kernel(); |
@@ -1268,6 +1289,7 @@ restore_opts: | |||
1268 | sbi->s_resuid = old_opts.s_resuid; | 1289 | sbi->s_resuid = old_opts.s_resuid; |
1269 | sbi->s_resgid = old_opts.s_resgid; | 1290 | sbi->s_resgid = old_opts.s_resgid; |
1270 | sb->s_flags = old_sb_flags; | 1291 | sb->s_flags = old_sb_flags; |
1292 | spin_unlock(&sbi->s_lock); | ||
1271 | unlock_kernel(); | 1293 | unlock_kernel(); |
1272 | return err; | 1294 | return err; |
1273 | } | 1295 | } |
@@ -1279,6 +1301,8 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) | |||
1279 | struct ext2_super_block *es = sbi->s_es; | 1301 | struct ext2_super_block *es = sbi->s_es; |
1280 | u64 fsid; | 1302 | u64 fsid; |
1281 | 1303 | ||
1304 | spin_lock(&sbi->s_lock); | ||
1305 | |||
1282 | if (test_opt (sb, MINIX_DF)) | 1306 | if (test_opt (sb, MINIX_DF)) |
1283 | sbi->s_overhead_last = 0; | 1307 | sbi->s_overhead_last = 0; |
1284 | else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { | 1308 | else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { |
@@ -1333,6 +1357,7 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) | |||
1333 | le64_to_cpup((void *)es->s_uuid + sizeof(u64)); | 1357 | le64_to_cpup((void *)es->s_uuid + sizeof(u64)); |
1334 | buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; | 1358 | buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; |
1335 | buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; | 1359 | buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; |
1360 | spin_unlock(&sbi->s_lock); | ||
1336 | return 0; | 1361 | return 0; |
1337 | } | 1362 | } |
1338 | 1363 | ||
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index e44dc92609be..3b96045a00ce 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c | |||
@@ -345,7 +345,9 @@ static void ext2_xattr_update_super_block(struct super_block *sb) | |||
345 | if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR)) | 345 | if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR)) |
346 | return; | 346 | return; |
347 | 347 | ||
348 | spin_lock(&EXT2_SB(sb)->s_lock); | ||
348 | EXT2_SET_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR); | 349 | EXT2_SET_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR); |
350 | spin_unlock(&EXT2_SB(sb)->s_lock); | ||
349 | sb->s_dirt = 1; | 351 | sb->s_dirt = 1; |
350 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); | 352 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); |
351 | } | 353 | } |
diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h index 1cdb66367c98..db4d9f586bb6 100644 --- a/include/linux/ext2_fs_sb.h +++ b/include/linux/ext2_fs_sb.h | |||
@@ -106,6 +106,15 @@ struct ext2_sb_info { | |||
106 | spinlock_t s_rsv_window_lock; | 106 | spinlock_t s_rsv_window_lock; |
107 | struct rb_root s_rsv_window_root; | 107 | struct rb_root s_rsv_window_root; |
108 | struct ext2_reserve_window_node s_rsv_window_head; | 108 | struct ext2_reserve_window_node s_rsv_window_head; |
109 | /* | ||
110 | * s_lock protects against concurrent modifications of s_mount_state, | ||
111 | * s_blocks_last, s_overhead_last and the content of superblock's | ||
112 | * buffer pointed to by sbi->s_es. | ||
113 | * | ||
114 | * Note: It is used in ext2_show_options() to provide a consistent view | ||
115 | * of the mount options. | ||
116 | */ | ||
117 | spinlock_t s_lock; | ||
109 | }; | 118 | }; |
110 | 119 | ||
111 | static inline spinlock_t * | 120 | static inline spinlock_t * |