Commit 5af7926ff33b68b3ba46531471c6e0564b285efc
Committed by
Al Viro
1 parent
e500475338
Exists in
master
and in
4 other branches
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>
Showing 5 changed files with 27 additions and 25 deletions Side-by-side Diff
fs/btrfs/super.c
fs/cachefiles/interface.c
... | ... | @@ -354,7 +354,9 @@ |
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) |
fs/reiserfs/super.c
... | ... | @@ -64,18 +64,15 @@ |
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 |
fs/sync.c
... | ... | @@ -51,6 +51,18 @@ |
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; |
57 | 69 | |
58 | 70 | |
59 | 71 | |
60 | 72 | |
61 | 73 | |
... | ... | @@ -79,25 +91,22 @@ |
79 | 91 | |
80 | 92 | mutex_lock(&mutex); /* Could be down_interruptible */ |
81 | 93 | spin_lock(&sb_lock); |
82 | - list_for_each_entry(sb, &super_blocks, s_list) { | |
83 | - if (sb->s_flags & MS_RDONLY) | |
84 | - continue; | |
94 | + list_for_each_entry(sb, &super_blocks, s_list) | |
85 | 95 | sb->s_need_sync = 1; |
86 | - } | |
87 | 96 | |
88 | 97 | restart: |
89 | 98 | list_for_each_entry(sb, &super_blocks, s_list) { |
90 | 99 | if (!sb->s_need_sync) |
91 | 100 | continue; |
92 | 101 | sb->s_need_sync = 0; |
93 | - if (sb->s_flags & MS_RDONLY) | |
94 | - continue; /* hm. Was remounted r/o meanwhile */ | |
95 | 102 | sb->s_count++; |
96 | 103 | spin_unlock(&sb_lock); |
104 | + | |
97 | 105 | down_read(&sb->s_umount); |
98 | - if (sb->s_root) | |
106 | + if (!(sb->s_flags & MS_RDONLY) && sb->s_root) | |
99 | 107 | __sync_filesystem(sb, wait); |
100 | 108 | up_read(&sb->s_umount); |
109 | + | |
101 | 110 | /* restart only when sb is no longer on the list */ |
102 | 111 | spin_lock(&sb_lock); |
103 | 112 | if (__put_super_and_need_restart(sb)) |
fs/ubifs/super.c