Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0dc83bd3 authored by Jan Kara's avatar Jan Kara
Browse files

Revert "writeback: do not sync data dirtied after sync start"



This reverts commit c4a391b5. Dave
Chinner <david@fromorbit.com> has reported the commit may cause some
inodes to be left out from sync(2). This is because we can call
redirty_tail() for some inode (which sets i_dirtied_when to current time)
after sync(2) has started or similarly requeue_inode() can set
i_dirtied_when to current time if writeback had to skip some pages. The
real problem is in the functions clobbering i_dirtied_when but fixing
that isn't trivial so revert is a safer choice for now.

CC: stable@vger.kernel.org # >= 3.13
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 1362f4ea
Loading
Loading
Loading
Loading
+11 −22
Original line number Diff line number Diff line
@@ -40,18 +40,13 @@
struct wb_writeback_work {
	long nr_pages;
	struct super_block *sb;
	/*
	 * Write only inodes dirtied before this time. Don't forget to set
	 * older_than_this_is_set when you set this.
	 */
	unsigned long older_than_this;
	unsigned long *older_than_this;
	enum writeback_sync_modes sync_mode;
	unsigned int tagged_writepages:1;
	unsigned int for_kupdate:1;
	unsigned int range_cyclic:1;
	unsigned int for_background:1;
	unsigned int for_sync:1;	/* sync(2) WB_SYNC_ALL writeback */
	unsigned int older_than_this_is_set:1;
	enum wb_reason reason;		/* why was writeback initiated? */

	struct list_head list;		/* pending work list */
@@ -252,10 +247,10 @@ static int move_expired_inodes(struct list_head *delaying_queue,
	int do_sb_sort = 0;
	int moved = 0;

	WARN_ON_ONCE(!work->older_than_this_is_set);
	while (!list_empty(delaying_queue)) {
		inode = wb_inode(delaying_queue->prev);
		if (inode_dirtied_after(inode, work->older_than_this))
		if (work->older_than_this &&
		    inode_dirtied_after(inode, *work->older_than_this))
			break;
		list_move(&inode->i_wb_list, &tmp);
		moved++;
@@ -742,8 +737,6 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
		.sync_mode	= WB_SYNC_NONE,
		.range_cyclic	= 1,
		.reason		= reason,
		.older_than_this = jiffies,
		.older_than_this_is_set = 1,
	};

	spin_lock(&wb->list_lock);
@@ -802,13 +795,12 @@ static long wb_writeback(struct bdi_writeback *wb,
{
	unsigned long wb_start = jiffies;
	long nr_pages = work->nr_pages;
	unsigned long oldest_jif;
	struct inode *inode;
	long progress;

	if (!work->older_than_this_is_set) {
		work->older_than_this = jiffies;
		work->older_than_this_is_set = 1;
	}
	oldest_jif = jiffies;
	work->older_than_this = &oldest_jif;

	spin_lock(&wb->list_lock);
	for (;;) {
@@ -842,10 +834,10 @@ static long wb_writeback(struct bdi_writeback *wb,
		 * safe.
		 */
		if (work->for_kupdate) {
			work->older_than_this = jiffies -
			oldest_jif = jiffies -
				msecs_to_jiffies(dirty_expire_interval * 10);
		} else if (work->for_background)
			work->older_than_this = jiffies;
			oldest_jif = jiffies;

		trace_writeback_start(wb->bdi, work);
		if (list_empty(&wb->b_io))
@@ -1358,20 +1350,17 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb);
/**
 * sync_inodes_sb	-	sync sb inode pages
 * @sb: the superblock
 * @older_than_this:	timestamp
 *
 * This function writes and waits on any dirty inode belonging to this
 * superblock that has been dirtied before given timestamp.
 * super_block.
 */
void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this)
void sync_inodes_sb(struct super_block *sb)
{
	DECLARE_COMPLETION_ONSTACK(done);
	struct wb_writeback_work work = {
		.sb		= sb,
		.sync_mode	= WB_SYNC_ALL,
		.nr_pages	= LONG_MAX,
		.older_than_this = older_than_this,
		.older_than_this_is_set = 1,
		.range_cyclic	= 0,
		.done		= &done,
		.reason		= WB_REASON_SYNC,
+6 −9
Original line number Diff line number Diff line
@@ -27,11 +27,10 @@
 * wait == 1 case since in that case write_inode() functions do
 * sync_dirty_buffer() and thus effectively write one block at a time.
 */
static int __sync_filesystem(struct super_block *sb, int wait,
			     unsigned long start)
static int __sync_filesystem(struct super_block *sb, int wait)
{
	if (wait)
		sync_inodes_sb(sb, start);
		sync_inodes_sb(sb);
	else
		writeback_inodes_sb(sb, WB_REASON_SYNC);

@@ -48,7 +47,6 @@ static int __sync_filesystem(struct super_block *sb, int wait,
int sync_filesystem(struct super_block *sb)
{
	int ret;
	unsigned long start = jiffies;

	/*
	 * We need to be protected against the filesystem going from
@@ -62,17 +60,17 @@ int sync_filesystem(struct super_block *sb)
	if (sb->s_flags & MS_RDONLY)
		return 0;

	ret = __sync_filesystem(sb, 0, start);
	ret = __sync_filesystem(sb, 0);
	if (ret < 0)
		return ret;
	return __sync_filesystem(sb, 1, start);
	return __sync_filesystem(sb, 1);
}
EXPORT_SYMBOL_GPL(sync_filesystem);

static void sync_inodes_one_sb(struct super_block *sb, void *arg)
{
	if (!(sb->s_flags & MS_RDONLY))
		sync_inodes_sb(sb, *((unsigned long *)arg));
		sync_inodes_sb(sb);
}

static void sync_fs_one_sb(struct super_block *sb, void *arg)
@@ -104,10 +102,9 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
SYSCALL_DEFINE0(sync)
{
	int nowait = 0, wait = 1;
	unsigned long start = jiffies;

	wakeup_flusher_threads(0, WB_REASON_SYNC);
	iterate_supers(sync_inodes_one_sb, &start);
	iterate_supers(sync_inodes_one_sb, NULL);
	iterate_supers(sync_fs_one_sb, &nowait);
	iterate_supers(sync_fs_one_sb, &wait);
	iterate_bdevs(fdatawrite_one_bdev, NULL);
+1 −1
Original line number Diff line number Diff line
@@ -913,7 +913,7 @@ xfs_flush_inodes(
	struct super_block	*sb = mp->m_super;

	if (down_read_trylock(&sb->s_umount)) {
		sync_inodes_sb(sb, jiffies);
		sync_inodes_sb(sb);
		up_read(&sb->s_umount);
	}
}
+1 −1
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ void writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
				  enum wb_reason reason);
void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this);
void sync_inodes_sb(struct super_block *);
void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
void inode_wait_for_writeback(struct inode *inode);

+3 −3
Original line number Diff line number Diff line
@@ -287,11 +287,11 @@ TRACE_EVENT(writeback_queue_io,
		__field(int,		reason)
	),
	TP_fast_assign(
		unsigned long older_than_this = work->older_than_this;
		unsigned long *older_than_this = work->older_than_this;
		strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
		__entry->older	= older_than_this;
		__entry->older	= older_than_this ?  *older_than_this : 0;
		__entry->age	= older_than_this ?
				  (jiffies - older_than_this) * 1000 / HZ : -1;
				  (jiffies - *older_than_this) * 1000 / HZ : -1;
		__entry->moved	= moved;
		__entry->reason	= work->reason;
	),