diff options
author | Jan Blunck <jblunck@suse.de> | 2010-04-14 08:38:38 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2010-05-21 13:30:39 -0400 |
commit | c15271f4e74cd6dbdf461335d6d1450949c4b956 (patch) | |
tree | 585738bde9a80e580686072d02cd6c1e5d261c1e /fs/ext2 | |
parent | 4c96a68bfc110d87b28bcee4c395a7b4d26ed67a (diff) |
ext2: Add ext2_sb_info s_lock spinlock
Add a spinlock that protects against concurrent modifications of
s_mount_state, s_blocks_last, s_overhead_last and the content of the
superblock's buffer pointed to by sbi->s_es. The spinlock is now used in
ext2_xattr_update_super_block() which was setting the
EXT2_FEATURE_COMPAT_EXT_ATTR flag on the superblock without protection
before. Likewise the spinlock is used in ext2_show_options() to have a
consistent view of the mount options.
This is a preparation patch for removing the BKL from ext2 in the next
patch.
Signed-off-by: Jan Blunck <jblunck@suse.de>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Jan Kara <jack@suse.cz>
Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext2')
-rw-r--r-- | fs/ext2/inode.c | 2 | ||||
-rw-r--r-- | fs/ext2/super.c | 27 | ||||
-rw-r--r-- | fs/ext2/xattr.c | 2 |
3 files changed, 30 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 | } |