introduce I_SYNC

I_LOCK was used for several unrelated purposes, which caused deadlock
situations in certain filesystems as a side effect.  One of the purposes
now uses the new I_SYNC bit.

Also document the various bits and change their order from historical to
logical.

[bunk@stusta.de: make fs/inode.c:wake_up_inode() static]
Signed-off-by: Joern Engel <joern@wohnheim.fh-wedel.de>
Cc: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Cc: David Chinner <dgc@sgi.com>
Cc: Anton Altaparmakov <aia21@cam.ac.uk>
Cc: Al Viro <viro@ftp.linux.org.uk>
Cc: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Joern Engel 2007-10-16 23:30:44 -07:00 committed by Linus Torvalds
parent 2e6883bdf4
commit 1c0eeaf569
8 changed files with 116 additions and 42 deletions

View file

@ -100,11 +100,11 @@ void __mark_inode_dirty(struct inode *inode, int flags)
inode->i_state |= flags;
/*
* If the inode is locked, just update its dirty state.
* If the inode is being synced, just update its dirty state.
* The unlocker will place the inode on the appropriate
* superblock list, based upon its state.
*/
if (inode->i_state & I_LOCK)
if (inode->i_state & I_SYNC)
goto out;
/*
@ -172,6 +172,15 @@ static void requeue_io(struct inode *inode)
list_move(&inode->i_list, &inode->i_sb->s_more_io);
}
static void inode_sync_complete(struct inode *inode)
{
/*
* Prevent speculative execution through spin_unlock(&inode_lock);
*/
smp_mb();
wake_up_bit(&inode->i_state, __I_SYNC);
}
/*
* Move expired dirty inodes from @delaying_queue to @dispatch_queue.
*/
@ -225,11 +234,11 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
int wait = wbc->sync_mode == WB_SYNC_ALL;
int ret;
BUG_ON(inode->i_state & I_LOCK);
BUG_ON(inode->i_state & I_SYNC);
/* Set I_LOCK, reset I_DIRTY */
/* Set I_SYNC, reset I_DIRTY */
dirty = inode->i_state & I_DIRTY;
inode->i_state |= I_LOCK;
inode->i_state |= I_SYNC;
inode->i_state &= ~I_DIRTY;
spin_unlock(&inode_lock);
@ -250,7 +259,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
}
spin_lock(&inode_lock);
inode->i_state &= ~I_LOCK;
inode->i_state &= ~I_SYNC;
if (!(inode->i_state & I_FREEING)) {
if (!(inode->i_state & I_DIRTY) &&
mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
@ -305,7 +314,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
list_move(&inode->i_list, &inode_unused);
}
}
wake_up_inode(inode);
inode_sync_complete(inode);
return ret;
}
@ -324,7 +333,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
else
WARN_ON(inode->i_state & I_WILL_FREE);
if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_LOCK)) {
if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_SYNC)) {
struct address_space *mapping = inode->i_mapping;
int ret;
@ -350,16 +359,16 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
/*
* It's a data-integrity sync. We must wait.
*/
if (inode->i_state & I_LOCK) {
DEFINE_WAIT_BIT(wq, &inode->i_state, __I_LOCK);
if (inode->i_state & I_SYNC) {
DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC);
wqh = bit_waitqueue(&inode->i_state, __I_LOCK);
wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
do {
spin_unlock(&inode_lock);
__wait_on_bit(wqh, &wq, inode_wait,
TASK_UNINTERRUPTIBLE);
spin_lock(&inode_lock);
} while (inode->i_state & I_LOCK);
} while (inode->i_state & I_SYNC);
}
return __sync_single_inode(inode, wbc);
}
@ -392,7 +401,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
* The inodes to be written are parked on sb->s_io. They are moved back onto
* sb->s_dirty as they are selected for writing. This way, none can be missed
* on the writer throttling path, and we get decent balancing between many
* throttled threads: we don't want them all piling up on __wait_on_inode.
* throttled threads: we don't want them all piling up on inode_sync_wait.
*/
static void
sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
@ -661,7 +670,7 @@ int write_inode_now(struct inode *inode, int sync)
ret = __writeback_single_inode(inode, &wbc);
spin_unlock(&inode_lock);
if (sync)
wait_on_inode(inode);
inode_sync_wait(inode);
return ret;
}
EXPORT_SYMBOL(write_inode_now);
@ -736,7 +745,7 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int
err = err2;
}
else
wait_on_inode(inode);
inode_sync_wait(inode);
return err;
}