From: "Theodore Ts'o" <tytso@mit.edu>
To: Ext4 Developers List <linux-ext4@vger.kernel.org>,
Linux Kernel Developers List <linux-kernel@vger.kernel.org>
Cc: Jan Kara <jack@suse.cz>,
"Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>,
Mingming Cao <cmm@us.ibm.com>, "Theodore Ts'o" <tytso@mit.edu>
Subject: [PATCH 39/52] ext4: Use new framework for data=ordered mode in JBD2
Date: Sat, 5 Jul 2008 13:36:05 -0400 [thread overview]
Message-ID: <1215279378-30504-40-git-send-email-tytso@mit.edu> (raw)
In-Reply-To: <1215279378-30504-39-git-send-email-tytso@mit.edu>
From: Jan Kara <jack@suse.cz>
This patch makes ext4 use inode-based implementation of data=ordered mode
in JBD2. It allows us to unify some data=ordered and data=writeback paths
(especially writepage since we don't have to start a transaction anymore)
and remove some buffer walking.
Updated fix from Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
to fix file system hang due to corrupt jinode values.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
fs/ext4/ext4_i.h | 1 +
fs/ext4/ext4_jbd2.h | 7 ++-
fs/ext4/inode.c | 158 ++++++++++++++++-----------------------------------
fs/ext4/super.c | 5 +-
4 files changed, 59 insertions(+), 112 deletions(-)
diff --git a/fs/ext4/ext4_i.h b/fs/ext4/ext4_i.h
index abf2744..c2903ef 100644
--- a/fs/ext4/ext4_i.h
+++ b/fs/ext4/ext4_i.h
@@ -150,6 +150,7 @@ struct ext4_inode_info {
*/
struct rw_semaphore i_data_sem;
struct inode vfs_inode;
+ struct jbd2_inode jinode;
unsigned long i_ext_generation;
struct ext4_ext_cache i_cached_extent;
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 9255a7d..bd6e272 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -154,8 +154,6 @@ int __ext4_journal_dirty_metadata(const char *where,
#define ext4_journal_forget(handle, bh) \
__ext4_journal_forget(__FUNCTION__, (handle), (bh))
-int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
-
handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
int __ext4_journal_stop(const char *where, handle_t *handle);
@@ -192,6 +190,11 @@ static inline int ext4_journal_force_commit(journal_t *journal)
return jbd2_journal_force_commit(journal);
}
+static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode)
+{
+ return jbd2_journal_file_inode(handle, &EXT4_I(inode)->jinode);
+}
+
/* super.c */
int ext4_force_commit(struct super_block *sb);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index d698844..3af9cd7 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -39,6 +39,13 @@
#include "xattr.h"
#include "acl.h"
+static inline int ext4_begin_ordered_truncate(struct inode *inode,
+ loff_t new_size)
+{
+ return jbd2_journal_begin_ordered_truncate(&EXT4_I(inode)->jinode,
+ new_size);
+}
+
/*
* Test whether an inode is a fast symlink.
*/
@@ -181,6 +188,8 @@ void ext4_delete_inode (struct inode * inode)
{
handle_t *handle;
+ if (ext4_should_order_data(inode))
+ ext4_begin_ordered_truncate(inode, 0);
truncate_inode_pages(&inode->i_data, 0);
if (is_bad_inode(inode))
@@ -1273,15 +1282,6 @@ out:
return ret;
}
-int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
-{
- int err = jbd2_journal_dirty_data(handle, bh);
- if (err)
- ext4_journal_abort_handle(__func__, __func__,
- bh, handle, err);
- return err;
-}
-
/* For write_end() in data=journal mode */
static int write_end_fn(handle_t *handle, struct buffer_head *bh)
{
@@ -1311,8 +1311,7 @@ static int ext4_ordered_write_end(struct file *file,
from = pos & (PAGE_CACHE_SIZE - 1);
to = from + len;
- ret = walk_page_buffers(handle, page_buffers(page),
- from, to, NULL, ext4_journal_dirty_data);
+ ret = ext4_jbd2_file_inode(handle, inode);
if (ret == 0) {
/*
@@ -1472,25 +1471,22 @@ static int bput_one(handle_t *handle, struct buffer_head *bh)
return 0;
}
-static int jbd2_journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
-{
- if (buffer_mapped(bh))
- return ext4_journal_dirty_data(handle, bh);
- return 0;
-}
-
static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
{
return !buffer_mapped(bh) || buffer_delay(bh);
}
/*
- * Note that we don't need to start a transaction unless we're journaling
- * data because we should have holes filled from ext4_page_mkwrite(). If
- * we are journaling data, we cannot start transaction directly because
- * transaction start ranks above page lock so we have to do some magic...
+ * Note that we don't need to start a transaction unless we're journaling data
+ * because we should have holes filled from ext4_page_mkwrite(). We even don't
+ * need to file the inode to the transaction's list in ordered mode because if
+ * we are writing back data added by write(), the inode is already there and if
+ * we are writing back data modified via mmap(), noone guarantees in which
+ * transaction the data will hit the disk. In case we are journaling data, we
+ * cannot start transaction directly because transaction start ranks above page
+ * lock so we have to do some magic.
*
- * In all journalling modes block_write_full_page() will start the I/O.
+ * In all journaling modes block_write_full_page() will start the I/O.
*
* Problem:
*
@@ -1533,86 +1529,7 @@ static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh)
* us.
*
*/
-static int __ext4_ordered_writepage(struct page *page,
- struct writeback_control *wbc)
-{
- struct inode *inode = page->mapping->host;
- struct buffer_head *page_bufs;
- handle_t *handle = NULL;
- int ret = 0;
- int err;
-
- if (!page_has_buffers(page)) {
- create_empty_buffers(page, inode->i_sb->s_blocksize,
- (1 << BH_Dirty)|(1 << BH_Uptodate));
- }
- page_bufs = page_buffers(page);
- walk_page_buffers(handle, page_bufs, 0,
- PAGE_CACHE_SIZE, NULL, bget_one);
-
- ret = block_write_full_page(page, ext4_get_block, wbc);
-
- /*
- * The page can become unlocked at any point now, and
- * truncate can then come in and change things. So we
- * can't touch *page from now on. But *page_bufs is
- * safe due to elevated refcount.
- */
-
- /*
- * And attach them to the current transaction. But only if
- * block_write_full_page() succeeded. Otherwise they are unmapped,
- * and generally junk.
- */
- if (ret == 0) {
- handle = ext4_journal_start(inode,
- ext4_writepage_trans_blocks(inode));
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- goto out_put;
- }
-
- ret = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE,
- NULL, jbd2_journal_dirty_data_fn);
- err = ext4_journal_stop(handle);
- if (!ret)
- ret = err;
- }
-out_put:
- walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL,
- bput_one);
- return ret;
-}
-
-static int ext4_ordered_writepage(struct page *page,
- struct writeback_control *wbc)
-{
- struct inode *inode = page->mapping->host;
- loff_t size = i_size_read(inode);
- loff_t len;
-
- J_ASSERT(PageLocked(page));
- J_ASSERT(page_has_buffers(page));
- if (page->index == size >> PAGE_CACHE_SHIFT)
- len = size & ~PAGE_CACHE_MASK;
- else
- len = PAGE_CACHE_SIZE;
- BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL,
- ext4_bh_unmapped_or_delay));
-
- /*
- * We give up here if we're reentered, because it might be for a
- * different filesystem.
- */
- if (!ext4_journal_current_handle())
- return __ext4_ordered_writepage(page, wbc);
-
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
- return 0;
-}
-
-static int __ext4_writeback_writepage(struct page *page,
+static int __ext4_normal_writepage(struct page *page,
struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
@@ -1624,7 +1541,7 @@ static int __ext4_writeback_writepage(struct page *page,
}
-static int ext4_writeback_writepage(struct page *page,
+static int ext4_normal_writepage(struct page *page,
struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
@@ -1641,7 +1558,7 @@ static int ext4_writeback_writepage(struct page *page,
ext4_bh_unmapped_or_delay));
if (!ext4_journal_current_handle())
- return __ext4_writeback_writepage(page, wbc);
+ return __ext4_normal_writepage(page, wbc);
redirty_page_for_writepage(wbc, page);
unlock_page(page);
@@ -1877,7 +1794,7 @@ static int ext4_journalled_set_page_dirty(struct page *page)
static const struct address_space_operations ext4_ordered_aops = {
.readpage = ext4_readpage,
.readpages = ext4_readpages,
- .writepage = ext4_ordered_writepage,
+ .writepage = ext4_normal_writepage,
.sync_page = block_sync_page,
.write_begin = ext4_write_begin,
.write_end = ext4_ordered_write_end,
@@ -1891,7 +1808,7 @@ static const struct address_space_operations ext4_ordered_aops = {
static const struct address_space_operations ext4_writeback_aops = {
.readpage = ext4_readpage,
.readpages = ext4_readpages,
- .writepage = ext4_writeback_writepage,
+ .writepage = ext4_normal_writepage,
.sync_page = block_sync_page,
.write_begin = ext4_write_begin,
.write_end = ext4_writeback_write_end,
@@ -2019,7 +1936,7 @@ int ext4_block_truncate_page(handle_t *handle,
err = ext4_journal_dirty_metadata(handle, bh);
} else {
if (ext4_should_order_data(inode))
- err = ext4_journal_dirty_data(handle, bh);
+ err = ext4_jbd2_file_inode(handle, inode);
mark_buffer_dirty(bh);
}
@@ -3149,7 +3066,14 @@ int ext4_write_inode(struct inode *inode, int wait)
* be freed, so we have a strong guarantee that no future commit will
* leave these blocks visible to the user.)
*
- * Called with inode->sem down.
+ * Another thing we have to assure is that if we are in ordered mode
+ * and inode is still attached to the committing transaction, we must
+ * we start writeout of all the dirty pages which are being truncated.
+ * This way we are sure that all the data written in the previous
+ * transaction are already on disk (truncate waits for pages under
+ * writeback).
+ *
+ * Called with inode->i_mutex down.
*/
int ext4_setattr(struct dentry *dentry, struct iattr *attr)
{
@@ -3215,6 +3139,22 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
if (!error)
error = rc;
ext4_journal_stop(handle);
+
+ if (ext4_should_order_data(inode)) {
+ error = ext4_begin_ordered_truncate(inode,
+ attr->ia_size);
+ if (error) {
+ /* Do as much error cleanup as possible */
+ handle = ext4_journal_start(inode, 3);
+ if (IS_ERR(handle)) {
+ ext4_orphan_del(NULL, inode);
+ goto err_out;
+ }
+ ext4_orphan_del(handle, inode);
+ ext4_journal_stop(handle);
+ goto err_out;
+ }
+ }
}
rc = inode_setattr(inode, attr);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 1b330cd..629d0fa 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -573,6 +573,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
INIT_LIST_HEAD(&ei->i_prealloc_list);
spin_lock_init(&ei->i_prealloc_lock);
+ jbd2_journal_init_jbd_inode(&ei->jinode, &ei->vfs_inode);
return &ei->vfs_inode;
}
@@ -637,6 +638,8 @@ static void ext4_clear_inode(struct inode *inode)
EXT4_I(inode)->i_block_alloc_info = NULL;
if (unlikely(rsv))
kfree(rsv);
+ jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal,
+ &EXT4_I(inode)->jinode);
}
static inline void ext4_show_quota_options(struct seq_file *seq, struct super_block *sb)
@@ -3378,7 +3381,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
err = ext4_journal_dirty_metadata(handle, bh);
else {
/* Always do at least ordered writes for quotas */
- err = ext4_journal_dirty_data(handle, bh);
+ err = ext4_jbd2_file_inode(handle, inode);
mark_buffer_dirty(bh);
}
brelse(bh);
--
1.5.6.rc3.1.g36b7.dirty
next prev parent reply other threads:[~2008-07-05 17:48 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-07-05 17:35 Ext4 patches for the next merge window Theodore Ts'o
2008-07-05 17:35 ` [PATCH 01/52] ext4: fix comments to say "ext4" Theodore Ts'o
2008-07-05 17:35 ` [PATCH 02/52] ext4: start searching for the right extent from the goal group Theodore Ts'o
2008-07-05 17:35 ` [PATCH 03/52] ext4: Use BUG_ON() instead of BUG() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 04/52] ext4: switch to seq_files Theodore Ts'o
2008-07-05 17:35 ` [PATCH 05/52] ext4: improve some code in rb tree part of dir.c Theodore Ts'o
2008-07-05 17:35 ` [PATCH 06/52] ext4: Fix ext4_mb_init_cache return error Theodore Ts'o
2008-07-05 17:35 ` [PATCH 07/52] ext4: add error processing when calling ext4_mb_init_cache in mballoc Theodore Ts'o
2008-07-05 17:35 ` [PATCH 08/52] ext4: miscellaneous error checks and coding cleanups for mballoc Theodore Ts'o
2008-07-05 17:35 ` [PATCH 09/52] ext4: remove double definitions of xattr macros Theodore Ts'o
2008-07-05 17:35 ` [PATCH 10/52] ext4: Rename read_block_bitmap() to ext4_read_block_bitmap() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 11/52] ext4: Remove unused variable from ext4_show_options Theodore Ts'o
2008-07-05 17:35 ` [PATCH 12/52] jbd2: Add commit time into the commit block Theodore Ts'o
2008-07-05 17:35 ` [PATCH 13/52] ext4: New inode allocation for FLEX_BG meta-data groups Theodore Ts'o
2008-07-05 17:35 ` [PATCH 14/52] jbd2: fix race between jbd2_journal_try_to_free_buffers() and jbd2 commit transaction Theodore Ts'o
2008-07-05 17:35 ` [PATCH 15/52] ext4: remove redundant code in ext4_fill_super() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 16/52] ext4: remove quota allocation when ext4_mb_new_blocks fails Theodore Ts'o
2008-07-05 17:35 ` [PATCH 17/52] ext4: Update i_disksize properly when allocating from fallocate area Theodore Ts'o
2008-07-05 17:35 ` [PATCH 18/52] ext4: return error when calling ext4_ext_split failed Theodore Ts'o
2008-07-05 17:35 ` [PATCH 19/52] ext4: Make ext4_ext_find_extent fills ext_path completely Theodore Ts'o
2008-07-05 17:35 ` [PATCH 20/52] ext4: Fix ext4_ext_journal_restart() to reflect errors up to the caller Theodore Ts'o
2008-07-05 17:35 ` [PATCH 21/52] ext4: cleanup never-used magic numbers from htree code Theodore Ts'o
2008-07-05 17:35 ` [PATCH 22/52] ext4: Fix sparse warning Theodore Ts'o
2008-07-05 17:35 ` [PATCH 23/52] ext4: fix ext4_init_block_bitmap() for metablock block group Theodore Ts'o
2008-07-05 17:35 ` [PATCH 24/52] ext4: Use inode preallocation with -o noextents Theodore Ts'o
2008-07-05 17:35 ` [PATCH 25/52] ext4: cleanup block allocator Theodore Ts'o
2008-07-05 17:35 ` [PATCH 26/52] ext4: call blkdev_issue_flush on fsync Theodore Ts'o
2008-07-05 17:35 ` [PATCH 27/52] ext4: mballoc avoid use root reserved blocks for non root allocation Theodore Ts'o
2008-07-05 17:35 ` [PATCH 28/52] ext4: Set journal pointer to NULL when journal is released Theodore Ts'o
2008-07-05 17:35 ` [PATCH 29/52] ext4: use atomic functions to set bh_state Theodore Ts'o
2008-07-05 17:35 ` [PATCH 30/52] ext4: Add missing unlock to an error path in ext4_quota_write() Theodore Ts'o
2008-07-05 17:35 ` [PATCH 31/52] ext4: fix online resize with mballoc Theodore Ts'o
2008-07-05 17:35 ` [PATCH 32/52] ext4: Documentation updates Theodore Ts'o
2008-07-05 17:35 ` [PATCH 33/52] ext4: Use page_mkwrite vma_operations to get mmap write notification Theodore Ts'o
2008-07-05 17:36 ` [PATCH 34/52] vfs: Move mark_inode_dirty() from under page lock in generic_write_end() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 35/52] ext4: Invert the locking order of page_lock and transaction start Theodore Ts'o
2008-07-05 17:36 ` [PATCH 36/52] ext4: Fix lock inversion in ext4_ext_truncate() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 37/52] vfs: export filemap_fdatawrite_range() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 38/52] jbd2: Implement data=ordered mode handling via inodes Theodore Ts'o
2008-07-05 17:36 ` Theodore Ts'o [this message]
2008-07-05 17:36 ` [PATCH 40/52] jbd2: Remove data=ordered mode support using jbd buffer heads Theodore Ts'o
2008-07-05 17:36 ` [PATCH 41/52] vfs: add basic delayed allocation support Theodore Ts'o
2008-07-05 17:36 ` [PATCH 42/52] ext4: Add " Theodore Ts'o
2008-07-05 17:36 ` [PATCH 43/52] percpu_counter: new function percpu_counter_sum_and_set Theodore Ts'o
2008-07-05 17:36 ` [PATCH 44/52] ext4: delayed allocation ENOSPC handling Theodore Ts'o
2008-07-05 17:36 ` [PATCH 45/52] mm: Add range_cont mode for writeback Theodore Ts'o
2008-07-05 17:36 ` [PATCH 46/52] ext4: Invert lock ordering of page_lock and transaction start in delalloc Theodore Ts'o
2008-07-05 17:36 ` [PATCH 47/52] ext4: Add ordered mode support for delalloc Theodore Ts'o
2008-07-05 17:36 ` [PATCH 48/52] ext4: Handle page without buffers in ext4_*_writepage() Theodore Ts'o
2008-07-05 17:36 ` [PATCH 49/52] ext4: fix delalloc i_disksize early update issue Theodore Ts'o
2008-07-05 17:36 ` [PATCH 50/52] ext4: Enable delalloc by default Theodore Ts'o
2008-07-05 17:36 ` [PATCH 51/52] ext4: Don't allow nonextenst mount option for large filesystem Theodore Ts'o
2008-07-05 17:36 ` [PATCH 52/52] ext4: Documention update for new ordered mode and delayed allocation Theodore Ts'o
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1215279378-30504-40-git-send-email-tytso@mit.edu \
--to=tytso@mit.edu \
--cc=aneesh.kumar@linux.vnet.ibm.com \
--cc=cmm@us.ibm.com \
--cc=jack@suse.cz \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®