The patch titled Subject: writeback: put unused inodes to LRU after writeback completion has been added to the -mm tree. Its filename is writeback-put-unused-inodes-to-lru-after-writeback-completion.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Jan Kara <jack@xxxxxxx> Subject: writeback: put unused inodes to LRU after writeback completion Commit 169ebd90 ("writeback: Avoid iput() from flusher thread") removed iget-iput pair from inode writeback. As a side effect, inodes that are dirty during iput_final() call won't be ever added to inode LRU (iput_final() doesn't add dirty inodes to LRU and later when the inode is cleaned there's noone to add the inode there). Thus inodes are effectively unreclaimable until someone looks them up again. Practical effect of this bug is limited by the fact that inodes are pinned by a dentry for long enough that the inode gets cleaned. But still the bug can have nasty consequences leading up to OOM conditions under certain circumstances. Following can easily reproduce the problem: for (( i = 0; i < 1000; i++ )); do mkdir $i for (( j = 0; j < 1000; j++ )); do touch $i/$j echo 2 > /proc/sys/vm/drop_caches done done then one needs to run 'sync; ls -lR' to make inodes reclaimable again. We fix the issue by inserting unused clean inodes into the LRU after writeback finishes in inode_sync_complete(). Signed-off-by: Jan Kara <jack@xxxxxxx> Reported-by: OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx> Cc: Wu Fengguang <fengguang.wu@xxxxxxxxx> Cc: Dave Chinner <david@xxxxxxxxxxxxx> Cc: <stable@xxxxxxxxxxxxxxx> [3.5+] Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- fs/fs-writeback.c | 2 ++ fs/inode.c | 16 ++++++++++++++-- fs/internal.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff -puN fs/fs-writeback.c~writeback-put-unused-inodes-to-lru-after-writeback-completion fs/fs-writeback.c --- a/fs/fs-writeback.c~writeback-put-unused-inodes-to-lru-after-writeback-completion +++ a/fs/fs-writeback.c @@ -228,6 +228,8 @@ static void requeue_io(struct inode *ino static void inode_sync_complete(struct inode *inode) { inode->i_state &= ~I_SYNC; + /* If inode is clean an unused, put it into LRU now... */ + inode_add_lru(inode); /* Waiters must see I_SYNC cleared before being woken up */ smp_mb(); wake_up_bit(&inode->i_state, __I_SYNC); diff -puN fs/inode.c~writeback-put-unused-inodes-to-lru-after-writeback-completion fs/inode.c --- a/fs/inode.c~writeback-put-unused-inodes-to-lru-after-writeback-completion +++ a/fs/inode.c @@ -408,6 +408,19 @@ static void inode_lru_list_add(struct in spin_unlock(&inode->i_sb->s_inode_lru_lock); } +/* + * Add inode to LRU if needed (inode is unused and clean). + * + * Needs inode->i_lock held. + */ +void inode_add_lru(struct inode *inode) +{ + if (!(inode->i_state & (I_DIRTY | I_SYNC | I_FREEING | I_WILL_FREE)) && + !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE) + inode_lru_list_add(inode); +} + + static void inode_lru_list_del(struct inode *inode) { spin_lock(&inode->i_sb->s_inode_lru_lock); @@ -1390,8 +1403,7 @@ static void iput_final(struct inode *ino if (!drop && (sb->s_flags & MS_ACTIVE)) { inode->i_state |= I_REFERENCED; - if (!(inode->i_state & (I_DIRTY|I_SYNC))) - inode_lru_list_add(inode); + inode_add_lru(inode); spin_unlock(&inode->i_lock); return; } diff -puN fs/internal.h~writeback-put-unused-inodes-to-lru-after-writeback-completion fs/internal.h --- a/fs/internal.h~writeback-put-unused-inodes-to-lru-after-writeback-completion +++ a/fs/internal.h @@ -110,6 +110,7 @@ extern int open_check_o_direct(struct fi * inode.c */ extern spinlock_t inode_sb_list_lock; +extern void inode_add_lru(struct inode *inode); /* * fs-writeback.c _ Patches currently in -mm which might be from jack@xxxxxxx are origin.patch linux-next.patch writeback-put-unused-inodes-to-lru-after-writeback-completion.patch fs-change-return-values-from-eacces-to-eperm.patch mm-add-comment-on-storage-key-dirty-bit-semantics.patch mm-print-out-information-of-file-affected-by-memory-error.patch hfsplus-avoid-crash-on-failed-block-map-free.patch hfsplus-add-on-disk-layout-declarations-related-to-attributes-tree.patch hfsplus-add-functionality-of-manipulating-by-records-in-attributes-tree.patch hfsplus-rework-functionality-of-getting-setting-and-deleting-of-extended-attributes.patch hfsplus-add-support-of-manipulation-by-attributes-file.patch fat-provide-option-for-setting-timezone-offset.patch fat-fix-mount-option-parsing.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html