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 | { |
