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;
        }
        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.
  */
                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);
        }
                        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? */