From e643692138cfa33528f054b071ba2583509bb217 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Mar 2013 14:39:05 +0100 Subject: ext3: fix data=journal fast mount/umount hang In data=journal mode, if we unmount the file system before a transaction has a chance to complete, when the journal inode is being evicted, we can end up calling into log_wait_commit() for the last transaction, after the journalling machinery has been shut down. That triggers the WARN_ONCE in __log_start_commit(). Arguably we should adjust ext3_should_journal_data() to return FALSE for the journal inode, but the only place it matters is ext3_evict_inode(), and so it's to save a bit of CPU time, and to make the patch much more obviously correct by inspection(tm), we'll fix it by explicitly not trying to waiting for a journal commit when we are evicting the journal inode, since it's guaranteed to never succeed in this case. This can be easily replicated via: mount -t ext3 -o data=journal /dev/vdb /vdb ; umount /vdb This is a port of ext4 fix from Ted Ts'o. Signed-off-by: Jan Kara --- fs/ext3/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index d512c4bc4ad7..d706dbfa6220 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -218,7 +218,8 @@ void ext3_evict_inode (struct inode *inode) */ if (inode->i_nlink && ext3_should_journal_data(inode) && EXT3_SB(inode->i_sb)->s_journal && - (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) { + (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode)) && + inode->i_ino != EXT3_JOURNAL_INO) { tid_t commit_tid = atomic_read(&ei->i_datasync_tid); journal_t *journal = EXT3_SB(inode->i_sb)->s_journal; -- cgit v1.2.3 From e678a4f0f50d4fa4f7aaa6de8eb3f071513356a0 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 27 Mar 2013 17:30:59 +0100 Subject: jbd: don't wait (forever) for stale tid caused by wraparound In the case where an inode has a very stale transaction id (tid) in i_datasync_tid or i_sync_tid, it's possible that after a very large (2**31) number of transactions, that the tid number space might wrap, causing tid_geq()'s calculations to fail. Commit d9b0193 "jbd: fix fsync() tid wraparound bug" attempted to fix this problem, but it only avoided kjournald spinning forever by fixing the logic in jbd_log_start_commit(). Signed-off-by: Jan Kara --- fs/jbd/journal.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 81cc7eaff863..81880c6d6b5e 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -564,6 +564,16 @@ int log_wait_commit(journal_t *journal, tid_t tid) spin_unlock(&journal->j_state_lock); #endif spin_lock(&journal->j_state_lock); + /* + * Not running or committing trans? Must be already committed. This + * saves us from waiting for a *long* time when tid overflows. + */ + if (!((journal->j_running_transaction && + journal->j_running_transaction->t_tid == tid) || + (journal->j_committing_transaction && + journal->j_committing_transaction->t_tid == tid))) + goto out_unlock; + if (!tid_geq(journal->j_commit_waited, tid)) journal->j_commit_waited = tid; while (tid_gt(tid, journal->j_commit_sequence)) { @@ -575,6 +585,7 @@ int log_wait_commit(journal_t *journal, tid_t tid) !tid_gt(tid, journal->j_commit_sequence)); spin_lock(&journal->j_state_lock); } +out_unlock: spin_unlock(&journal->j_state_lock); if (unlikely(is_journal_aborted(journal))) { -- cgit v1.2.3 From e162b2f835eeda0d255bd463753b5eb823735205 Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Fri, 12 Apr 2013 02:24:06 +0000 Subject: jbd: use kmem_cache_zalloc instead of kmem_cache_alloc/memset Now jbd_alloc_handle is only called by new_handle. So this commit uses kmem_cache_zalloc instead of kmem_cache_alloc/memset. Signed-off-by: Zheng Liu Signed-off-by: Jan Kara --- fs/jbd/transaction.c | 1 - include/linux/jbd.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 071d6905f0dd..e3e255c0a509 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -245,7 +245,6 @@ static handle_t *new_handle(int nblocks) handle_t *handle = jbd_alloc_handle(GFP_NOFS); if (!handle) return NULL; - memset(handle, 0, sizeof(*handle)); handle->h_buffer_credits = nblocks; handle->h_ref = 1; diff --git a/include/linux/jbd.h b/include/linux/jbd.h index c8f32975f0e4..7e0b622503c4 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -887,7 +887,7 @@ extern struct kmem_cache *jbd_handle_cache; static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags) { - return kmem_cache_alloc(jbd_handle_cache, gfp_flags); + return kmem_cache_zalloc(jbd_handle_cache, gfp_flags); } static inline void jbd_free_handle(handle_t *handle) -- cgit v1.2.3 From 8bb9da943a62f4ffaabba1ad745990260fbb39df Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Mon, 29 Apr 2013 17:08:51 +0800 Subject: jbd: use kmem_cache_zalloc for allocating journal head This commit tries to use kmem_cache_zalloc instead of kmem_cache_alloc/ memset when a new journal head is alloctated. Signed-off-by: Zheng Liu Cc: Jan Kara Signed-off-by: Jan Kara --- fs/jbd/journal.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 81880c6d6b5e..726a4432cbb1 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1856,7 +1856,7 @@ static struct journal_head *journal_alloc_journal_head(void) #ifdef CONFIG_JBD_DEBUG atomic_inc(&nr_journal_heads); #endif - ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + ret = kmem_cache_zalloc(journal_head_cache, GFP_NOFS); if (ret == NULL) { jbd_debug(1, "out of memory for journal_head\n"); printk_ratelimited(KERN_NOTICE "ENOMEM in %s, retrying.\n", @@ -1864,7 +1864,7 @@ static struct journal_head *journal_alloc_journal_head(void) while (ret == NULL) { yield(); - ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + ret = kmem_cache_zalloc(journal_head_cache, GFP_NOFS); } } return ret; @@ -1926,10 +1926,8 @@ struct journal_head *journal_add_journal_head(struct buffer_head *bh) struct journal_head *new_jh = NULL; repeat: - if (!buffer_jbd(bh)) { + if (!buffer_jbd(bh)) new_jh = journal_alloc_journal_head(); - memset(new_jh, 0, sizeof(*new_jh)); - } jbd_lock_bh_journal_head(bh); if (buffer_jbd(bh)) { -- cgit v1.2.3