|
@@ -196,7 +196,7 @@ static void redirty_tail(struct inode *inode)
|
|
|
struct inode *tail_inode;
|
|
|
|
|
|
tail_inode = list_entry(sb->s_dirty.next, struct inode, i_list);
|
|
|
- if (!time_after_eq(inode->dirtied_when,
|
|
|
+ if (time_before(inode->dirtied_when,
|
|
|
tail_inode->dirtied_when))
|
|
|
inode->dirtied_when = jiffies;
|
|
|
}
|
|
@@ -220,6 +220,21 @@ static void inode_sync_complete(struct inode *inode)
|
|
|
wake_up_bit(&inode->i_state, __I_SYNC);
|
|
|
}
|
|
|
|
|
|
+static bool inode_dirtied_after(struct inode *inode, unsigned long t)
|
|
|
+{
|
|
|
+ bool ret = time_after(inode->dirtied_when, t);
|
|
|
+#ifndef CONFIG_64BIT
|
|
|
+ /*
|
|
|
+ * For inodes being constantly redirtied, dirtied_when can get stuck.
|
|
|
+ * It _appears_ to be in the future, but is actually in distant past.
|
|
|
+ * This test is necessary to prevent such wrapped-around relative times
|
|
|
+ * from permanently stopping the whole pdflush writeback.
|
|
|
+ */
|
|
|
+ ret = ret && time_before_eq(inode->dirtied_when, jiffies);
|
|
|
+#endif
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Move expired dirty inodes from @delaying_queue to @dispatch_queue.
|
|
|
*/
|
|
@@ -231,7 +246,7 @@ static void move_expired_inodes(struct list_head *delaying_queue,
|
|
|
struct inode *inode = list_entry(delaying_queue->prev,
|
|
|
struct inode, i_list);
|
|
|
if (older_than_this &&
|
|
|
- time_after(inode->dirtied_when, *older_than_this))
|
|
|
+ inode_dirtied_after(inode, *older_than_this))
|
|
|
break;
|
|
|
list_move(&inode->i_list, dispatch_queue);
|
|
|
}
|
|
@@ -492,8 +507,11 @@ void generic_sync_sb_inodes(struct super_block *sb,
|
|
|
continue; /* blockdev has wrong queue */
|
|
|
}
|
|
|
|
|
|
- /* Was this inode dirtied after sync_sb_inodes was called? */
|
|
|
- if (time_after(inode->dirtied_when, start))
|
|
|
+ /*
|
|
|
+ * Was this inode dirtied after sync_sb_inodes was called?
|
|
|
+ * This keeps sync from extra jobs and livelock.
|
|
|
+ */
|
|
|
+ if (inode_dirtied_after(inode, start))
|
|
|
break;
|
|
|
|
|
|
/* Is another pdflush already flushing this queue? */
|