Remove I_WILL_FREE
Subsystems (9)
PATCH 1/1 Remove I_WILL_FREE
I_WILL_FREE does not really add any new functionality over I_FREEING. If I_WILL_FREE is set, it will be replaced by I_FREEING under the inode lock. And they always appear in the same if statement. We can set I_FREEING a little bit earlier to achieve the same result.
--- fs/block_dev.c | 2 +- fs/btrfs/inode.c | 3 +-- fs/drop_caches.c | 2 +- fs/ext4/inode.c | 4 ++-- fs/fs-writeback.c | 14 +++++--------- fs/gfs2/inode.c | 2 +- fs/inode.c | 20 +++++++++----------- fs/notify/inode_mark.c | 6 +++--- fs/ocfs2/inode.c | 3 +-- fs/quota/dquot.c | 2 +- include/linux/fs.h | 29 ++++++++++++----------------- include/trace/events/writeback.h | 1 - 12 files changed, 37 insertions(+), 51 deletions(-)
fs/block_dev.c +1 -1
@@ -1808,7 +1808,7 @@ void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg)struct address_space *mapping = inode->i_mapping;spin_lock (&inode->i_lock); -if (inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW ) || +if (inode->i_state & (I_FREEING |I_NEW ) || mapping->nrpages ==0 ) {spin_unlock (&inode->i_lock);continue ;
fs/btrfs/inode.c +1 -2
@@ -5433,8 +5433,7 @@ static void inode_tree_add(struct inode *inode)else if (ino >btrfs_ino (&entry->vfs_inode)) p = &parent->rb_right;else { -WARN_ON (!(entry->vfs_inode.i_state & - (I_WILL_FREE |I_FREEING ))); +WARN_ON (!(entry->vfs_inode.i_state &I_FREEING ));rb_replace_node (parent, new, &root->inode_tree);RB_CLEAR_NODE (parent);spin_unlock (&root->inode_lock);
fs/drop_caches.c +1 -1
@@ -20,7 +20,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)spin_lock (&sb->s_inode_list_lock);list_for_each_entry (inode, &sb->s_inodes, i_sb_list) {spin_lock (&inode->i_lock); -if ((inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW )) || +if ((inode->i_state & (I_FREEING |I_NEW )) || (inode->i_mapping->nrpages ==0 )) {spin_unlock (&inode->i_lock);continue ;
fs/ext4/inode.c +2 -2
@@ -4367,12 +4367,12 @@ static int other_inode_match(struct inode * inode, unsigned long ino,struct other_inode *oi = (struct other_inode *) data;if ((inode->i_ino != ino) || - (inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW | + (inode->i_state & (I_FREEING |I_NEW |I_DIRTY_SYNC |I_DIRTY_DATASYNC )) || ((inode->i_state &I_DIRTY_TIME ) ==0 ))return 0 ;spin_lock (&inode->i_lock); -if (((inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW | +if (((inode->i_state & (I_FREEING |I_NEW |I_DIRTY_SYNC |I_DIRTY_DATASYNC )) ==0 ) && (inode->i_state &I_DIRTY_TIME )) {struct ext4_inode_info *ei =EXT4_I (inode);
fs/fs-writeback.c +5 -9
@@ -1298,7 +1298,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)/* * Write out an inode's dirty pages. Either the caller has an active reference -* on the inode or the inode has I_WILL_FREE set. +* on the inode or the inode has I_FREEING set. * * This function is designed to be called for writing back one inode which * we go e.g. from filesystem. Flusher thread uses __writeback_single_inode()
@@ -1311,17 +1311,13 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,int ret =0 ;spin_lock (&inode->i_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 (wbc->sync_mode !=WB_SYNC_ALL ) goto out;/* * It's a data-integrity sync. We must wait. Since callers hold -* inode reference or inode has I_WILL_FREE set, it cannot go +* inode reference or inode has I_FREEING set, it cannot go * away under us. */ __inode_wait_for_writeback (inode);
@@ -1446,7 +1442,7 @@ static long writeback_sb_inodes(struct super_block *sb,* kind writeout is handled by the freer. */ spin_lock (&inode->i_lock); -if (inode->i_state & (I_NEW |I_FREEING |I_WILL_FREE )) { +if (inode->i_state & (I_NEW |I_FREEING )) {spin_unlock (&inode->i_lock);redirty_tail (inode, wb);continue ;
@@ -2130,7 +2126,7 @@ static void wait_sb_inodes(struct super_block *sb)struct address_space *mapping = inode->i_mapping;spin_lock (&inode->i_lock); -if ((inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW )) || +if ((inode->i_state & (I_FREEING |I_NEW )) || (mapping->nrpages ==0 )) {spin_unlock (&inode->i_lock);continue ;
@@ -2301,7 +2297,7 @@ EXPORT_SYMBOL(sync_inodes_sb);* This function commits an inode to disk immediately if it is dirty. This is * primarily needed by knfsd. * -* The caller must either have a ref on the inode or must have set I_WILL_FREE. +* The caller must either have a ref on the inode or must have set I_FREEING. */ int write_inode_now (struct inode *inode,int sync) {
fs/gfs2/inode.c +1 -1
@@ -50,7 +50,7 @@ static int iget_test(struct inode *inode, void *opaque)if (ip->i_no_addr == data->no_addr) {if (data->non_block && - inode->i_state & (I_FREEING |I_CLEAR |I_WILL_FREE )) { + inode->i_state & (I_FREEING |I_CLEAR )) { data->skipped =1 ;return 0 ; }
fs/inode.c +9 -11
@@ -405,7 +405,7 @@ static void inode_lru_list_add(struct inode *inode)void inode_add_lru (struct inode *inode) {if (!(inode->i_state & (I_DIRTY_ALL |I_SYNC | -I_FREEING |I_WILL_FREE )) && +I_FREEING )) && !atomic_read (&inode->i_count) && inode->i_sb->s_flags &MS_ACTIVE )inode_lru_list_add (inode); }
@@ -600,7 +600,7 @@ again:continue ;spin_lock (&inode->i_lock); -if (inode->i_state & (I_NEW |I_FREEING |I_WILL_FREE )) { +if (inode->i_state & (I_NEW |I_FREEING )) {spin_unlock (&inode->i_lock);continue ; }
@@ -646,7 +646,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)spin_lock (&sb->s_inode_list_lock);list_for_each_entry_safe (inode, next, &sb->s_inodes, i_sb_list) {spin_lock (&inode->i_lock); -if (inode->i_state & (I_NEW |I_FREEING |I_WILL_FREE )) { +if (inode->i_state & (I_NEW |I_FREEING )) {spin_unlock (&inode->i_lock);continue ; }
@@ -783,7 +783,7 @@ repeat:if (!test (inode, data))continue ;spin_lock (&inode->i_lock); -if (inode->i_state & (I_FREEING |I_WILL_FREE )) { +if (inode->i_state & (I_FREEING )) {__wait_on_freeing_inode (inode); goto repeat; }
@@ -810,7 +810,7 @@ repeat:if (inode->i_sb != sb)continue ;spin_lock (&inode->i_lock); -if (inode->i_state & (I_FREEING |I_WILL_FREE )) { +if (inode->i_state &I_FREEING ) {__wait_on_freeing_inode (inode); goto repeat; }
@@ -1191,7 +1191,7 @@ EXPORT_SYMBOL(iunique);struct inode *igrab (struct inode *inode) {spin_lock (&inode->i_lock); -if (!(inode->i_state & (I_FREEING |I_WILL_FREE ))) { +if (!(inode->i_state &I_FREEING )) {__iget (inode);spin_unlock (&inode->i_lock); }else {
@@ -1353,7 +1353,7 @@ int insert_inode_locked(struct inode *inode)if (old->i_sb != sb)continue ;spin_lock (&old->i_lock); -if (old->i_state & (I_FREEING |I_WILL_FREE )) { +if (old->i_state &I_FREEING ) {spin_unlock (&old->i_lock);continue ; }
@@ -1396,7 +1396,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,if (!test (old, data))continue ;spin_lock (&old->i_lock); -if (old->i_state & (I_FREEING |I_WILL_FREE )) { +if (old->i_state &I_FREEING ) {spin_unlock (&old->i_lock);continue ; }
@@ -1460,16 +1460,14 @@ static void iput_final(struct inode *inode)return ; } + inode->i_state |=I_FREEING ;if (!drop) { - inode->i_state |=I_WILL_FREE ;spin_unlock (&inode->i_lock);write_inode_now (inode,1 );spin_lock (&inode->i_lock);WARN_ON (inode->i_state &I_NEW ); - inode->i_state &= ~I_WILL_FREE ; } - inode->i_state |=I_FREEING ;if (!list_empty (&inode->i_lru))inode_lru_list_del (inode);spin_unlock (&inode->i_lock);
fs/notify/inode_mark.c +3 -3
@@ -158,11 +158,11 @@ void fsnotify_unmount_inodes(struct super_block *sb)/* * We cannot __iget() an inode in state I_FREEING, -* I_WILL_FREE, or I_NEW which is fine because by that point +* or I_NEW which is fine because by that point * the inode cannot have any associated watches. */ spin_lock (&inode->i_lock); -if (inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW )) { +if (inode->i_state & (I_FREEING |I_NEW )) {spin_unlock (&inode->i_lock);continue ; }
@@ -191,7 +191,7 @@ void fsnotify_unmount_inodes(struct super_block *sb)/* In case the dropping of a reference would nuke next_i. */ while (&next_i->i_sb_list != &sb->s_inodes) {spin_lock (&next_i->i_lock); -if (!(next_i->i_state & (I_FREEING |I_WILL_FREE )) && +if (!(next_i->i_state &I_FREEING ) &&atomic_read (&next_i->i_count)) {__iget (next_i); need_iput = next_i;
fs/ocfs2/inode.c +1 -2
@@ -1205,12 +1205,11 @@ int ocfs2_drop_inode(struct inode *inode) inode->i_nlink, oi->ip_flags);assert_spin_locked (&inode->i_lock); - inode->i_state |=I_WILL_FREE ; + inode->i_state |=I_FREEING ;spin_unlock (&inode->i_lock);write_inode_now (inode,1 );spin_lock (&inode->i_lock);WARN_ON (inode->i_state &I_NEW ); - inode->i_state &= ~I_WILL_FREE ;return 1 ; }
fs/quota/dquot.c +1 -1
@@ -931,7 +931,7 @@ static void add_dquot_ref(struct super_block *sb, int type)spin_lock (&sb->s_inode_list_lock);list_for_each_entry (inode, &sb->s_inodes, i_sb_list) {spin_lock (&inode->i_lock); -if ((inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW )) || +if ((inode->i_state & (I_FREEING |I_NEW )) || !atomic_read (&inode->i_writecount) || !dqinit_needed (inode, type)) {spin_unlock (&inode->i_lock);
include/linux/fs.h +12 -17
@@ -1785,7 +1785,7 @@ struct super_operations {* I_DIRTY_DATASYNC and I_DIRTY_PAGES. * * Four bits define the lifetime of an inode. Initially, inodes are I_NEW, -* until that flag is cleared. I_WILL_FREE, I_FREEING and I_CLEAR are set at +* until that flag is cleared. I_FREEING and I_CLEAR are set at * various stages of removing an inode. * * Two bits are used for locking and completion notification, I_NEW and I_SYNC.
@@ -1801,20 +1801,17 @@ struct super_operations {* New inodes set I_NEW. If two processes both create * the same inode, one of them will release its inode and * wait for I_NEW to be released before returning. -* Inodes in I_WILL_FREE, I_FREEING or I_CLEAR state can +* Inodes in I_FREEING or I_CLEAR state can * also cause waiting on I_NEW, without I_NEW actually * being set. find_inode() uses this to prevent returning * nearly-dead inodes. -* I_WILL_FREE Must be set when calling write_inode_now() if i_count -* is zero. I_FREEING must be set when I_WILL_FREE is -* cleared. * I_FREEING Set when inode is about to be freed but still has dirty * pages or buffers attached or the inode itself is still * dirty. * I_CLEAR Added by clear_inode(). In this state the inode is * clean and can be destroyed. Inode keeps I_FREEING. * -* Inodes that are I_WILL_FREE, I_FREEING or I_CLEAR are +* Inodes that are I_FREEING or I_CLEAR are * prohibited for many purposes. iget() must wait for * the inode to be completely released, then create it * anew. Other functions will just ignore such inodes,
@@ -1834,26 +1831,24 @@ struct super_operations {* wb stat updates to grab mapping->tree_lock. See * inode_switch_wb_work_fn() for details. * -* Q: What is the difference between I_WILL_FREE and I_FREEING? */ #define I_DIRTY_SYNC (1 << 0)#define I_DIRTY_DATASYNC (1 << 1)#define I_DIRTY_PAGES (1 << 2)#define __I_NEW 3#define I_NEW (1 << __I_NEW) -#define I_WILL_FREE (1 << 4) -#define I_FREEING (1 << 5) -#define I_CLEAR (1 << 6) -#define __I_SYNC 7 +#define I_FREEING (1 << 4) +#define I_CLEAR (1 << 5) +#define __I_SYNC 6#define I_SYNC (1 << __I_SYNC) -#define I_REFERENCED (1 << 8) -#define __I_DIO_WAKEUP 9 +#define I_REFERENCED (1 << 7) +#define __I_DIO_WAKEUP 8#define I_DIO_WAKEUP (1 << __I_DIO_WAKEUP) -#define I_LINKABLE (1 << 10) -#define I_DIRTY_TIME (1 << 11) -#define __I_DIRTY_TIME_EXPIRED 12 +#define I_LINKABLE (1 << 9) +#define I_DIRTY_TIME (1 << 10) +#define __I_DIRTY_TIME_EXPIRED 11#define I_DIRTY_TIME_EXPIRED (1 << __I_DIRTY_TIME_EXPIRED) -#define I_WB_SWITCH (1 << 13) +#define I_WB_SWITCH (1 << 12)#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)#define I_DIRTY_ALL (I_DIRTY | I_DIRTY_TIME)
include/trace/events/writeback.h +0 -1
@@ -14,7 +14,6 @@ {I_DIRTY_DATASYNC, "I_DIRTY_DATASYNC"}, \ {I_DIRTY_PAGES, "I_DIRTY_PAGES"}, \ {I_NEW, "I_NEW"}, \ - {I_WILL_FREE, "I_WILL_FREE"}, \ {I_FREEING, "I_FREEING"}, \ {I_CLEAR, "I_CLEAR"}, \ {I_SYNC, "I_SYNC"}, \
Signature · 1 line
1.9.1
Al Viro
maintainerQuoted 3 lines · Zhihui Zhang
I_WILL_FREEdoes not really add any new functionality overI_FREEING. IfI_WILL_FREEis set, it will be replaced byI_FREEINGunder the inode lock. And they always appear in the same if statement.
Do they? Consider
fs/fs-writeback.c:351: if (unlikely(inode->i_state & I_FREEING)) fs/fs-writeback.c:472: if (inode->i_state & (I_WB_SWITCH | I_FREEING) || fs/fs-writeback.c:1161: if (inode->i_state & I_FREEING)fs/fs-writeback.c:2049: if (inode->i_state & I_FREEING)
for a few counterexamples...
You are right, I was thinking from the perspective of I_WILL_FREE.
However, for the examples in fs-writeback.c and a few in ext4/btrfs/inode.c, we can argue that they really should check I_WILL_FREE as well. In theory, bad things can happen if they don't because as soon as I_WILL_FREE is set, the inode is going to be evicted. For example, in fs-writeback.c:
471 spin_lock(&inode->i_lock);
472 if (inode->i_state & (I_WB_SWITCH | I_FREEING) ||
<-- Assume I_WILL_FREE is set
at this point.
473 inode_to_wb(inode) == isw->new_wb) {
474 spin_unlock(&inode->i_lock);
475 goto out_free;
476 } 477 inode->i_state |= I_WB_SWITCH; 478 spin_unlock(&inode->i_lock);
479
480 ihold(inode); <-- This will cause a warning because of i_count.
thanks,
-Zhihui
Quoted 13 lines · Al Viro
Quoted 3 lines · Zhihui Zhang
I_WILL_FREEdoes not really add any new functionality overI_FREEING. IfI_WILL_FREEis set, it will be replaced byI_FREEINGunder the inode lock. And they always appear in the same if statement.Do they? Consider
fs/fs-writeback.c:351: if (unlikely(inode->i_state & I_FREEING))fs/fs-writeback.c:472: if (inode->i_state& (I_WB_SWITCH|I_FREEING) ||fs/fs-writeback.c:1161: if (inode->i_state&I_FREEING)fs/fs-writeback.c:2049: if (inode->i_state&I_FREEING)for a few counterexamples...
Al Viro
maintainer[akpm Cc'd]
Quoted 14 lines · Zhihui Zhang
You are right, I was thinking from the perspective of
I_WILL_FREE.However, for the examples in
fs-writeback.cand a few inext4/btrfs/inode.c, we can argue that they really should checkI_WILL_FREEas well. In theory, bad things can happen if they don't because as soon asI_WILL_FREEis set, the inode is going to be evicted. For example, infs-writeback.c:471
spin_lock(&inode->i_lock);
472 if (inode->i_state& (I_WB_SWITCH|I_FREEING) ||<-- Assume
I_WILL_FREEis set
at this point.
Quoted 8 lines
473
inode_to_wb(inode)==isw->new_wb) {
474spin_unlock(&inode->i_lock);
475 gotoout_free;476 } 477 inode->i_state |= I_WB_SWITCH; 478 spin_unlock(&inode->i_lock);479
480 ihold(inode); <-- This will cause a warning because ofi_count.
Hmm... That ihold() is actually a lot more recent than original
introduction of I_WILL_FREE, but looking at the state of the tree back when it was originally introduced... I'm trying to recall what made us go for a separate flag, but so far I've got nothing definite. Hell knows - it had been 10 years ago, and I have a gap from late 2004 to September 2005 in mailboxes, so those are no help either... I _think_ it got discussed with akpm, maybe he would be able to help reconstructing what happened.
It looks like you are right regarding the current state of the tree, but I really wonder if there's something subtle that got missed during one of rewrites in those ten years... OTOH, it's quite possible that there had been no good reason for using a separate flag from the very beginning.
Andrew, do you have any memories of (or, better yet, archived mails relevant to) that thing?
I_WILL_FREE was introduced by the following commit:
$ git show 991114c6fa6a21d1fa4d544abe78592352860c82 commit 991114c6fa6a21d1fa4d544abe78592352860c82 Author: Alexander Viro <[email protected]> Date: Thu Jun 23 00:09:01 2005 -0700
[PATCH] fix for prune_icache()/forced final iput() races
To me, the only reason we need it now is because we might drop inode lock before evict it finally. So we set a flag saying: leave it alone please.
thanks,
-Zhihui
Quoted 41 lines · Al Viro
[akpm Cc'd]
Quoted 14 lines · Zhihui Zhang
You are right, I was thinking from the perspective of
I_WILL_FREE.However, for the examples in
fs-writeback.cand a few inext4/btrfs/inode.c, we can argue that they really should checkI_WILL_FREEas well. In theory, bad things can happen if they don't because as soon asI_WILL_FREEis set, the inode is going to be evicted. For example, infs-writeback.c:471
spin_lock(&inode->i_lock);
472 if (inode->i_state& (I_WB_SWITCH|I_FREEING) ||<-- Assume
I_WILL_FREEis set
at this point.Quoted 8 lines
473
inode_to_wb(inode)==isw->new_wb) {
474spin_unlock(&inode->i_lock);
475 gotoout_free;476 } 477 inode->i_state |= I_WB_SWITCH; 478 spin_unlock(&inode->i_lock);479
480 ihold(inode); <-- This will cause a warning because ofi_count.Hmm... That
ihold()is actually a lot more recent than original
introduction ofI_WILL_FREE, but looking at the state of the tree back when it was originally introduced... I'm trying to recall what made us go for a separate flag, but so far I've got nothing definite. Hell knows - it had been 10 years ago, and I have a gap from late 2004 to September 2005 in mailboxes, so those are no help either... I _think_ it got discussed with akpm, maybe he would be able to help reconstructing what happened.It looks like you are right regarding the current state of the tree, but I really wonder if there's something subtle that got missed during one of rewrites in those ten years... OTOH, it's quite possible that there had been no good reason for using a separate flag from the very beginning.
Andrew, do you have any memories of (or, better yet, archived mails relevant to) that thing?
Jan Kara
maintainerQuoted 34 lines · Al Viro
[akpm Cc'd]
Quoted 14 lines · Zhihui Zhang
You are right, I was thinking from the perspective of
I_WILL_FREE.However, for the examples in
fs-writeback.cand a few inext4/btrfs/inode.c, we can argue that they really should checkI_WILL_FREEas well. In theory, bad things can happen if they don't because as soon asI_WILL_FREEis set, the inode is going to be evicted. For example, infs-writeback.c:471
spin_lock(&inode->i_lock);
472 if (inode->i_state& (I_WB_SWITCH|I_FREEING) ||<-- Assume
I_WILL_FREEis set
at this point.Quoted 8 lines
473
inode_to_wb(inode)==isw->new_wb) {
474spin_unlock(&inode->i_lock);
475 gotoout_free;476 } 477 inode->i_state |= I_WB_SWITCH; 478 spin_unlock(&inode->i_lock);479
480 ihold(inode); <-- This will cause a warning because ofi_count.Hmm... That
ihold()is actually a lot more recent than original
introduction ofI_WILL_FREE, but looking at the state of the tree back when it was originally introduced... I'm trying to recall what made us go for a separate flag, but so far I've got nothing definite. Hell knows - it had been 10 years ago, and I have a gap from late 2004 to September 2005 in mailboxes, so those are no help either... I _think_ it got discussed with akpm, maybe he would be able to help reconstructing what happened.
Quoted 4 lines
It looks like you are right regarding the current state of the tree, but I really wonder if there's something subtle that got missed during one of rewrites in those ten years... OTOH, it's quite possible that there had been no good reason for using a separate flag from the very beginning.
Just for record, I don't see a reason for distinguishing between I_FREEING and I_WILL_FREE either. There could have been some difference back then when pdflush was still grabbing inode references to writeback inodes and there was no other explicit writeback barrier when evicting inodes (these days we have inode_wait_for_writeback() in evict()). But it's all just guessing.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR