From: Nick Piggin <npiggin@kernel.dk>
To: linux-fsdevel@vger.kernel.org
Subject: [patch 3/4] fs: introduce inode dirty state helpers
Date: Tue, 23 Nov 2010 00:07:33 +1100 [thread overview]
Message-ID: <20101122130733.GE12716@amd> (raw)
In-Reply-To: <20101122130507.GC12716@amd>
Inode dirty state cannot be securely tested without participating properly
in the inode writeback protocol. Some filesystems need to check this state,
so break out the code into helpers and make them available.
This could also be used to reduce strange interactions between background
writeback and fsync. Currently if we fsync a single page in a file, the
entire file gets requeued to the back of the background IO list, even if
it is due for writeout and has a large number of pages. That's left for
a later time.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Index: linux-2.6/fs/fs-writeback.c
===================================================================
--- linux-2.6.orig/fs/fs-writeback.c 2010-11-22 23:19:38.000000000 +1100
+++ linux-2.6/fs/fs-writeback.c 2010-11-22 23:19:40.000000000 +1100
@@ -299,6 +299,74 @@ static void inode_wait_for_writeback(str
}
}
+int inode_writeback_begin(struct inode *inode, int wait)
+{
+ assert_spin_locked(&inode_lock);
+ if (!atomic_read(&inode->i_count))
+ WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING)));
+ else
+ WARN_ON(inode->i_state & I_WILL_FREE);
+
+ if (inode->i_state & I_SYNC) {
+ /*
+ * If this inode is locked for writeback and we are not doing
+ * writeback-for-data-integrity, skip it.
+ */
+ if (!wait)
+ return 0;
+
+ /*
+ * It's a data-integrity sync. We must wait.
+ */
+ inode_wait_for_writeback(inode);
+ }
+
+ BUG_ON(inode->i_state & I_SYNC);
+
+ inode->i_state |= I_SYNC;
+ inode->i_state &= ~I_DIRTY;
+
+ return 1;
+}
+
+int inode_writeback_end(struct inode *inode)
+{
+ int ret = 1;
+
+ assert_spin_locked(&inode_lock);
+ BUG_ON(!(inode->i_state & I_SYNC));
+
+ if (!(inode->i_state & I_FREEING)) {
+ if (mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
+ /*
+ * We didn't write back all the pages. nfs_writepages()
+ * sometimes bales out without doing anything.
+ */
+ inode->i_state |= I_DIRTY_PAGES;
+ ret = 0;
+ } else if (inode->i_state & I_DIRTY) {
+ /*
+ * Filesystems can dirty the inode during writeback
+ * operations, such as delayed allocation during
+ * submission or metadata updates after data IO
+ * completion.
+ */
+ redirty_tail(inode);
+ } else {
+ /*
+ * The inode is clean. At this point we either have
+ * a reference to the inode or it's on it's way out.
+ * No need to add it back to the LRU.
+ */
+ list_del_init(&inode->i_wb_list);
+ }
+ }
+ inode->i_state &= ~I_SYNC;
+ inode_sync_complete(inode);
+
+ return ret;
+}
+
/*
* Write out an inode's dirty pages. Called under inode_lock. Either the
* caller has ref on the inode (either via __iget or via syscall against an fd)
@@ -319,36 +387,15 @@ writeback_single_inode(struct inode *ino
unsigned dirty;
int ret;
- if (!atomic_read(&inode->i_count))
- WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING)));
- else
- WARN_ON(inode->i_state & I_WILL_FREE);
-
- if (inode->i_state & I_SYNC) {
+ if (!inode_writeback_begin(inode, wbc->sync_mode == WB_SYNC_ALL)) {
/*
- * If this inode is locked for writeback and we are not doing
- * writeback-for-data-integrity, move it to b_more_io so that
- * writeback can proceed with the other inodes on s_io.
- *
* We'll have another go at writing back this inode when we
* completed a full scan of b_io.
*/
- if (wbc->sync_mode != WB_SYNC_ALL) {
- requeue_io(inode);
- return 0;
- }
-
- /*
- * It's a data-integrity sync. We must wait.
- */
- inode_wait_for_writeback(inode);
+ requeue_io(inode);
+ return 0;
}
- BUG_ON(inode->i_state & I_SYNC);
-
- /* Set I_SYNC, reset I_DIRTY_PAGES */
- inode->i_state |= I_SYNC;
- inode->i_state &= ~I_DIRTY_PAGES;
spin_unlock(&inode_lock);
ret = do_writepages(mapping, wbc);
@@ -381,47 +428,24 @@ writeback_single_inode(struct inode *ino
}
spin_lock(&inode_lock);
- inode->i_state &= ~I_SYNC;
- if (!(inode->i_state & I_FREEING)) {
- if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+ if (!inode_writeback_end(inode)) {
+ if (wbc->nr_to_write <= 0) {
/*
- * We didn't write back all the pages. nfs_writepages()
- * sometimes bales out without doing anything.
+ * slice used up: queue for next turn
*/
- inode->i_state |= I_DIRTY_PAGES;
- if (wbc->nr_to_write <= 0) {
- /*
- * slice used up: queue for next turn
- */
- requeue_io(inode);
- } else {
- /*
- * Writeback blocked by something other than
- * congestion. Delay the inode for some time to
- * avoid spinning on the CPU (100% iowait)
- * retrying writeback of the dirty page/inode
- * that cannot be performed immediately.
- */
- redirty_tail(inode);
- }
- } else if (inode->i_state & I_DIRTY) {
- /*
- * Filesystems can dirty the inode during writeback
- * operations, such as delayed allocation during
- * submission or metadata updates after data IO
- * completion.
- */
- redirty_tail(inode);
+ requeue_io(inode);
} else {
/*
- * The inode is clean. At this point we either have
- * a reference to the inode or it's on it's way out.
- * No need to add it back to the LRU.
+ * Writeback blocked by something other than
+ * congestion. Delay the inode for some time to
+ * avoid spinning on the CPU (100% iowait)
+ * retrying writeback of the dirty page/inode
+ * that cannot be performed immediately.
*/
- list_del_init(&inode->i_wb_list);
+ redirty_tail(inode);
}
}
- inode_sync_complete(inode);
+
return ret;
}
next prev parent reply other threads:[~2010-11-22 13:07 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-22 13:05 [patch 1/4] fs: mark_inode_dirty barrier fix Nick Piggin
2010-11-22 13:06 ` [patch 2/4] fs: fsync inode dirty race fix Nick Piggin
2010-11-22 13:23 ` Christoph Hellwig
2010-11-22 13:43 ` Nick Piggin
2010-11-22 13:07 ` Nick Piggin [this message]
2010-11-22 13:25 ` [patch 3/4] fs: introduce inode dirty state helpers Christoph Hellwig
2010-11-22 13:44 ` Nick Piggin
2010-11-22 13:09 ` [patch 4/4] ext2: inode sync fixes Nick Piggin
2010-11-22 13:16 ` [patch 1/4] fs: mark_inode_dirty barrier fix Christoph Hellwig
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=20101122130733.GE12716@amd \
--to=npiggin@kernel.dk \
--cc=linux-fsdevel@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;
as well as URLs for NNTP newsgroup(s).