aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Blunck <jblunck@suse.de>2010-04-14 08:38:38 -0400
committerJan Kara <jack@suse.cz>2010-05-21 13:30:39 -0400
commitc15271f4e74cd6dbdf461335d6d1450949c4b956 (patch)
tree585738bde9a80e580686072d02cd6c1e5d261c1e
parent4c96a68bfc110d87b28bcee4c395a7b4d26ed67a (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>
-rw-r--r--fs/ext2/inode.c2
-rw-r--r--fs/ext2/super.c27
-rw-r--r--fs/ext2/xattr.c2
-rw-r--r--include/linux/ext2_fs_sb.h9
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 */
87void ext2_update_dynamic_rev(struct super_block *sb) 92void 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
1155static int ext2_sync_fs(struct super_block *sb, int wait) 1168static 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
111static inline spinlock_t * 120static inline spinlock_t *