diff options
author | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2014-03-25 22:55:26 +0900 |
---|---|---|
committer | Daniel Phillips <daniel@tux3.org> | 2014-03-25 22:55:26 +0900 |
commit | 9d190848f26c1b07332d9872cf973f09bf2746f7 (patch) | |
tree | 4d0ee0d7e723d23e7ed9de2f8f169a658bb96701 | |
parent | 9b8da2c37b75acb68de614ce9a0340303db92226 (diff) | |
download | linux-tux3-9d190848f26c1b07332d9872cf973f09bf2746f7.tar.gz |
tux3: Fix deferred inode deletion locking
We defer inode deletion from itree and in-core inode destroy. To
defer, we dirty inode when inode refcount became 0.
But, iput_final() is not expecting to dirty inode. So, for now, we are
using a dirty way to defer. I.e. set dirty inode and return false from
->drop_inode(). (this is fragile, and can have issue)
Well, so, to dirty inode, we want to call mark_inode_dirty(). But
mark_inode_dirty() is not callable from iput_final() (by reason of
locking order).
To workaround this locking order, we unlock inode->i_lock
temporary. But unlocking inode->i_lock makes chance to freeing inode
again by cache reclaim. To avoid, cache reclaimer frees the inode, we
set I_WILL_FREE before drop inode->i_lock.
[FIXME:
- ->drop_inode() can't prevent to be freed while umount. So, if vfs
(like fsnotify) is taking refcount of inode while umount, inodes may
not be flushed by last sync_system(), and we may have problem.
- I_WILL_FREE affects to igrab which we don't want to affect.]
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
-rw-r--r-- | fs/tux3/writeback_inodedelete.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/fs/tux3/writeback_inodedelete.c b/fs/tux3/writeback_inodedelete.c index 87aa176534aaef..b14523bde51ed7 100644 --- a/fs/tux3/writeback_inodedelete.c +++ b/fs/tux3/writeback_inodedelete.c @@ -22,10 +22,7 @@ static int tux3_inode_is_dead(struct tux3_inode *tuxnode) (tuxnode->flags & TUX3_INODE_DEAD); } -/* - * Mark inode dirty to delete. (called from ->drop_inode()). - * Caller must hold inode->i_lock. - */ +/* Mark inode dirty to delete. (called from ->drop_inode()). */ static void __tux3_mark_inode_to_delete(struct inode *inode, unsigned delta) { struct tux3_inode *tuxnode = tux_inode(inode); @@ -39,19 +36,12 @@ static void __tux3_mark_inode_to_delete(struct inode *inode, unsigned delta) /* Mark inode dirty to delete on this delta */ tuxnode->flags |= tux3_deadsta_delta(delta); spin_unlock(&tuxnode->lock); - - /* - * Tell dead inode to backend by marking as dirty. - * - * Hack: this is called under inode->i_lock. So, we call - * internal ->dirty_inode(), and change inode->i_flags here - * directly. - */ - tux3_dirty_inode(inode, I_DIRTY_SYNC); - inode->i_state |= I_DIRTY_SYNC; - /* FIXME: we should wake up flusher if inode was clean */ } +/* + * Mark inode dirty to delete. (called from ->drop_inode()). + * Caller must hold inode->i_lock. + */ void tux3_mark_inode_to_delete(struct inode *inode) { struct sb *sb = tux_sb(inode->i_sb); @@ -67,6 +57,31 @@ void tux3_mark_inode_to_delete(struct inode *inode) delta = tux3_inode_delta(inode); __tux3_mark_inode_to_delete(inode, delta); + /* + * Hack: this is called under inode->i_lock. So, we have to + * release inode->i_lock to call mark_inode_dirty_sync(). + * + * FIXME: we want to set I_DIRTY_SYNC (I_DIRTY_SYNC will + * prevent the indo is freed) and wakeup flusher if need, + * while preventing inode is freed. Need better way to do. + */ + if (!(tux3_dirty_flags(inode, delta) & I_DIRTY_SYNC)) { + /* FIXME: I_REFERENCED can't prevent completely */ + //inode->i_state |= I_REFERENCED; + /* FIXME: I_WILL_FREE will bother igrab() grabs reference */ + inode->i_state |= I_WILL_FREE; + spin_unlock(&inode->i_lock); + + /* Tell dead inode to backend by marking as dirty. */ + tux3_mark_inode_dirty_sync(inode); + + spin_lock(&inode->i_lock); + inode->i_state &= ~I_WILL_FREE; +#ifdef __KERNEL__ + wake_up_bit(&inode->i_state, __I_NEW); +#endif + } + change_end_atomic(sb); } |