Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

enforce ->sync_fs is only called for rw superblock

Make sure a superblock really is writeable by checking MS_RDONLY
under s_umount. sync_filesystems needed some re-arragement for
that, but all but one sync_filesystem caller had the correct locking
already so that we could add that check there. cachefiles grew
s_umount locking.

I've also added a WARN_ON to sync_filesystem to assert this for
future callers.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by

Christoph Hellwig and committed by
Al Viro
5af7926f e5004753

+27 -25
-3
fs/btrfs/super.c
··· 394 394 struct btrfs_root *root = btrfs_sb(sb); 395 395 int ret; 396 396 397 - if (sb->s_flags & MS_RDONLY) 398 - return 0; 399 - 400 397 if (!wait) { 401 398 filemap_flush(root->fs_info->btree_inode->i_mapping); 402 399 return 0;
+2
fs/cachefiles/interface.c
··· 354 354 /* make sure all pages pinned by operations on behalf of the netfs are 355 355 * written to disc */ 356 356 cachefiles_begin_secure(cache, &saved_cred); 357 + down_read(&cache->mnt->mnt_sb->s_umount); 357 358 ret = sync_filesystem(cache->mnt->mnt_sb); 359 + up_read(&cache->mnt->mnt_sb->s_umount); 358 360 cachefiles_end_secure(cache, saved_cred); 359 361 360 362 if (ret == -EIO)
+9 -12
fs/reiserfs/super.c
··· 64 64 65 65 static int reiserfs_sync_fs(struct super_block *s, int wait) 66 66 { 67 - if (!(s->s_flags & MS_RDONLY)) { 68 - struct reiserfs_transaction_handle th; 69 - reiserfs_write_lock(s); 70 - if (!journal_begin(&th, s, 1)) 71 - if (!journal_end_sync(&th, s, 1)) 72 - reiserfs_flush_old_commits(s); 73 - s->s_dirt = 0; /* Even if it's not true. 74 - * We'll loop forever in sync_supers otherwise */ 75 - reiserfs_write_unlock(s); 76 - } else { 77 - s->s_dirt = 0; 78 - } 67 + struct reiserfs_transaction_handle th; 68 + 69 + reiserfs_write_lock(s); 70 + if (!journal_begin(&th, s, 1)) 71 + if (!journal_end_sync(&th, s, 1)) 72 + reiserfs_flush_old_commits(s); 73 + s->s_dirt = 0; /* Even if it's not true. 74 + * We'll loop forever in sync_supers otherwise */ 75 + reiserfs_write_unlock(s); 79 76 return 0; 80 77 } 81 78
+16 -7
fs/sync.c
··· 51 51 { 52 52 int ret; 53 53 54 + /* 55 + * We need to be protected against the filesystem going from 56 + * r/o to r/w or vice versa. 57 + */ 58 + WARN_ON(!rwsem_is_locked(&sb->s_umount)); 59 + 60 + /* 61 + * No point in syncing out anything if the filesystem is read-only. 62 + */ 63 + if (sb->s_flags & MS_RDONLY) 64 + return 0; 65 + 54 66 ret = __sync_filesystem(sb, 0); 55 67 if (ret < 0) 56 68 return ret; ··· 91 79 92 80 mutex_lock(&mutex); /* Could be down_interruptible */ 93 81 spin_lock(&sb_lock); 94 - list_for_each_entry(sb, &super_blocks, s_list) { 95 - if (sb->s_flags & MS_RDONLY) 96 - continue; 82 + list_for_each_entry(sb, &super_blocks, s_list) 97 83 sb->s_need_sync = 1; 98 - } 99 84 100 85 restart: 101 86 list_for_each_entry(sb, &super_blocks, s_list) { 102 87 if (!sb->s_need_sync) 103 88 continue; 104 89 sb->s_need_sync = 0; 105 - if (sb->s_flags & MS_RDONLY) 106 - continue; /* hm. Was remounted r/o meanwhile */ 107 90 sb->s_count++; 108 91 spin_unlock(&sb_lock); 92 + 109 93 down_read(&sb->s_umount); 110 - if (sb->s_root) 94 + if (!(sb->s_flags & MS_RDONLY) && sb->s_root) 111 95 __sync_filesystem(sb, wait); 112 96 up_read(&sb->s_umount); 97 + 113 98 /* restart only when sb is no longer on the list */ 114 99 spin_lock(&sb_lock); 115 100 if (__put_super_and_need_restart(sb))
-3
fs/ubifs/super.c
··· 447 447 if (!wait) 448 448 return 0; 449 449 450 - if (sb->s_flags & MS_RDONLY) 451 - return 0; 452 - 453 450 /* 454 451 * VFS calls '->sync_fs()' before synchronizing all dirty inodes and 455 452 * pages, so synchronize them first, then commit the journal. Strictly