diff options
-rw-r--r-- | fs/ext4/super.c | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 551cb8e2110c..7b636ceb878a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -242,27 +242,44 @@ static void ext4_put_nojournal(handle_t *handle) | |||
242 | * journal_end calls result in the superblock being marked dirty, so | 242 | * journal_end calls result in the superblock being marked dirty, so |
243 | * that sync() will call the filesystem's write_super callback if | 243 | * that sync() will call the filesystem's write_super callback if |
244 | * appropriate. | 244 | * appropriate. |
245 | * | ||
246 | * To avoid j_barrier hold in userspace when a user calls freeze(), | ||
247 | * ext4 prevents a new handle from being started by s_frozen, which | ||
248 | * is in an upper layer. | ||
245 | */ | 249 | */ |
246 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) | 250 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) |
247 | { | 251 | { |
248 | journal_t *journal; | 252 | journal_t *journal; |
253 | handle_t *handle; | ||
249 | 254 | ||
250 | if (sb->s_flags & MS_RDONLY) | 255 | if (sb->s_flags & MS_RDONLY) |
251 | return ERR_PTR(-EROFS); | 256 | return ERR_PTR(-EROFS); |
252 | 257 | ||
253 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
254 | /* Special case here: if the journal has aborted behind our | ||
255 | * backs (eg. EIO in the commit thread), then we still need to | ||
256 | * take the FS itself readonly cleanly. */ | ||
257 | journal = EXT4_SB(sb)->s_journal; | 258 | journal = EXT4_SB(sb)->s_journal; |
258 | if (journal) { | 259 | handle = ext4_journal_current_handle(); |
259 | if (is_journal_aborted(journal)) { | 260 | |
260 | ext4_abort(sb, "Detected aborted journal"); | 261 | /* |
261 | return ERR_PTR(-EROFS); | 262 | * If a handle has been started, it should be allowed to |
262 | } | 263 | * finish, otherwise deadlock could happen between freeze |
263 | return jbd2_journal_start(journal, nblocks); | 264 | * and others(e.g. truncate) due to the restart of the |
265 | * journal handle if the filesystem is forzen and active | ||
266 | * handles are not stopped. | ||
267 | */ | ||
268 | if (!handle) | ||
269 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
270 | |||
271 | if (!journal) | ||
272 | return ext4_get_nojournal(); | ||
273 | /* | ||
274 | * Special case here: if the journal has aborted behind our | ||
275 | * backs (eg. EIO in the commit thread), then we still need to | ||
276 | * take the FS itself readonly cleanly. | ||
277 | */ | ||
278 | if (is_journal_aborted(journal)) { | ||
279 | ext4_abort(sb, "Detected aborted journal"); | ||
280 | return ERR_PTR(-EROFS); | ||
264 | } | 281 | } |
265 | return ext4_get_nojournal(); | 282 | return jbd2_journal_start(journal, nblocks); |
266 | } | 283 | } |
267 | 284 | ||
268 | /* | 285 | /* |
@@ -4146,6 +4163,11 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
4146 | /* | 4163 | /* |
4147 | * LVM calls this function before a (read-only) snapshot is created. This | 4164 | * LVM calls this function before a (read-only) snapshot is created. This |
4148 | * gives us a chance to flush the journal completely and mark the fs clean. | 4165 | * gives us a chance to flush the journal completely and mark the fs clean. |
4166 | * | ||
4167 | * Note that only this function cannot bring a filesystem to be in a clean | ||
4168 | * state independently, because ext4 prevents a new handle from being started | ||
4169 | * by @sb->s_frozen, which stays in an upper layer. It thus needs help from | ||
4170 | * the upper layer. | ||
4149 | */ | 4171 | */ |
4150 | static int ext4_freeze(struct super_block *sb) | 4172 | static int ext4_freeze(struct super_block *sb) |
4151 | { | 4173 | { |