Skip to contentSkip to conversation

Syncthreads support.

PATCH In review Nigel Cunningham 3 participants 5 messages Jul 21, 2005 – Jul 22, 2005

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Syncthreads support.

This patch implements a new PF_SYNCTHREAD flag, which allows upcoming the refrigerator implementation to know that a thread is syncing data to disk. This allows the refrigerator to be more reliable, even under heavy load, because it can separate userspace processes that are submitting I/O from those trying to sync it and freezing the former first. We can thus ensure that syncing processes complete their work more quickly and the refrigerator is far less likely to incorrectly give up (thinking a syncing process is completely failing to enter the refrigerator).

Signed-off by: Nigel Cunningham <[email protected]>

 fs/buffer.c           |   45 +++++++++++++++++++++++++++++++++++++++++++--
 include/linux/sched.h |    2 ++
 2 files changed, 45 insertions(+), 2 deletions(-)
fs/buffer.c +43 -2
diff -ruNp 410-syncthreads.patch-old/fs/buffer.c 410-syncthreads.patch-new/fs/buffer.c
@@ -171,6 +171,15 @@ EXPORT_SYMBOL(sync_blockdev);
  */
 int fsync_super(struct super_block *sb)
 {
+	int ret;
+
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+	
+	current->flags |= PF_SYNCTHREAD;
+
 	sync_inodes_sb(sb, 0);
 	DQUOT_SYNC(sb);
 	lock_super(sb);
@@ -182,7 +191,10 @@ int fsync_super(struct super_block *sb)
 	sync_blockdev(sb->s_bdev);
 	sync_inodes_sb(sb, 1);
 
-	return sync_blockdev(sb->s_bdev);
+	ret = sync_blockdev(sb->s_bdev);
+
+	current->flags &= ~PF_SYNCTHREAD;
+	return ret;
 }
 
 /*
@@ -193,12 +205,21 @@ int fsync_super(struct super_block *sb)
 int fsync_bdev(struct block_device *bdev)
 {
 	struct super_block *sb = get_super(bdev);
+	int ret;
+
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	if (sb) {
 		int res = fsync_super(sb);
 		drop_super(sb);
+		current->flags &= ~PF_SYNCTHREAD;
 		return res;
 	}
-	return sync_blockdev(bdev);
+	ret = sync_blockdev(bdev);
+	current->flags &= ~PF_SYNCTHREAD;
+	return ret;
 }
 
 /**
@@ -278,6 +299,13 @@ EXPORT_SYMBOL(thaw_bdev);
  */
 static void do_sync(unsigned long wait)
 {
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	wakeup_pdflush(0);
 	sync_inodes(0);		/* All mappings, inodes and their blockdevs */
 	DQUOT_SYNC(NULL);
@@ -289,6 +317,8 @@ static void do_sync(unsigned long wait)
 		printk("Emergency Sync complete\n");
 	if (unlikely(laptop_mode))
 		laptop_sync_completion();
+
+	current->flags &= ~PF_SYNCTHREAD;
 }
 
 asmlinkage long sys_sync(void)
@@ -314,6 +344,10 @@ int file_fsync(struct file *filp, struct
 	struct super_block * sb;
 	int ret, err;
 
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	/* sync the inode to buffers */
 	ret = write_inode_now(inode, 0);
 
@@ -328,6 +362,8 @@ int file_fsync(struct file *filp, struct
 	err = sync_blockdev(sb->s_bdev);
 	if (!ret)
 		ret = err;
+
+	current->flags &= ~PF_SYNCTHREAD;
 	return ret;
 }
 
@@ -337,6 +373,10 @@ static long do_fsync(unsigned int fd, in
 	struct address_space *mapping;
 	int ret, err;
 
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	ret = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -370,6 +410,7 @@ static long do_fsync(unsigned int fd, in
 out_putf:
 	fput(file);
 out:
+	current->flags &= ~PF_SYNCTHREAD;
 	return ret;
 }
 
include/linux/sched.h +2 -0
diff -ruNp 410-syncthreads.patch-old/include/linux/sched.h 410-syncthreads.patch-new/include/linux/sched.h
@@ -829,6 +829,8 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
 #define PF_BORROWED_MM	0x00400000	/* I am a kthread doing use_mm */
 #define PF_RANDOMIZE	0x00800000	/* randomize virtual address space */
+#define PF_SYNCTHREAD	0x01000000	/* this thread can start activity during the 
++ 					   early part of freezing processes */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
Signature · 4 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
#1 lore raw

Hi!

Quoted 8 lines

This patch implements a new PF_SYNCTHREAD flag, which allows upcoming the refrigerator implementation to know that a thread is syncing data to disk. This allows the refrigerator to be more reliable, even under heavy load, because it can separate userspace processes that are submitting I/O from those trying to sync it and freezing the former first. We can thus ensure that syncing processes complete their work more quickly and the refrigerator is far less likely to incorrectly give up (thinking a syncing process is completely failing to enter the refrigerator).

This patch is ****, and pretty intrusive too. Ouch and then it is unneccessary. We have been over this before, and explained to you in person. Greg explained it to you, too. This one is NOT GOING IN. Drop it from your patches, trying to submit it 10 times will not get it accepted.

[For the record, simple solution for this one is

sys_sync();

and only then start refrigeration].

Pavel

[Patch left here for your amusement.]

Quoted 134 lines

Signed-off by: Nigel Cunningham <[email protected]>

 fs/buffer.c           |   45 +++++++++++++++++++++++++++++++++++++++++++--
 include/linux/sched.h |    2 ++
 2 files changed, 45 insertions(+), 2 deletions(-)

diff -ruNp 410-syncthreads.patch-old/fs/buffer.c 410-syncthreads.patch-new/fs/buffer.c

fs/buffer.c +43 -2
@@ -171,6 +171,15 @@ EXPORT_SYMBOL(sync_blockdev);
  */
 int fsync_super(struct super_block *sb)
 {
+	int ret;
+
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+	
+	current->flags |= PF_SYNCTHREAD;
+
 	sync_inodes_sb(sb, 0);
 	DQUOT_SYNC(sb);
 	lock_super(sb);
@@ -182,7 +191,10 @@ int fsync_super(struct super_block *sb)
 	sync_blockdev(sb->s_bdev);
 	sync_inodes_sb(sb, 1);
 
-	return sync_blockdev(sb->s_bdev);
+	ret = sync_blockdev(sb->s_bdev);
+
+	current->flags &= ~PF_SYNCTHREAD;
+	return ret;
 }
 
 /*
@@ -193,12 +205,21 @@ int fsync_super(struct super_block *sb)
 int fsync_bdev(struct block_device *bdev)
 {
 	struct super_block *sb = get_super(bdev);
+	int ret;
+
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	if (sb) {
 		int res = fsync_super(sb);
 		drop_super(sb);
+		current->flags &= ~PF_SYNCTHREAD;
 		return res;
 	}
-	return sync_blockdev(bdev);
+	ret = sync_blockdev(bdev);
+	current->flags &= ~PF_SYNCTHREAD;
+	return ret;
 }
 
 /**
@@ -278,6 +299,13 @@ EXPORT_SYMBOL(thaw_bdev);
  */
 static void do_sync(unsigned long wait)
 {
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	wakeup_pdflush(0);
 	sync_inodes(0);		/* All mappings, inodes and their blockdevs */
 	DQUOT_SYNC(NULL);
@@ -289,6 +317,8 @@ static void do_sync(unsigned long wait)
 		printk("Emergency Sync complete\n");
 	if (unlikely(laptop_mode))
 		laptop_sync_completion();
+
+	current->flags &= ~PF_SYNCTHREAD;
 }
 
 asmlinkage long sys_sync(void)
@@ -314,6 +344,10 @@ int file_fsync(struct file *filp, struct
 	struct super_block * sb;
 	int ret, err;
 
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	/* sync the inode to buffers */
 	ret = write_inode_now(inode, 0);
 
@@ -328,6 +362,8 @@ int file_fsync(struct file *filp, struct
 	err = sync_blockdev(sb->s_bdev);
 	if (!ret)
 		ret = err;
+
+	current->flags &= ~PF_SYNCTHREAD;
 	return ret;
 }
 
@@ -337,6 +373,10 @@ static long do_fsync(unsigned int fd, in
 	struct address_space *mapping;
 	int ret, err;
 
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	ret = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -370,6 +410,7 @@ static long do_fsync(unsigned int fd, in
 out_putf:
 	fput(file);
 out:
+	current->flags &= ~PF_SYNCTHREAD;
 	return ret;
 }
 

diff -ruNp 410-syncthreads.patch-old/include/linux/sched.h 410-syncthreads.patch-new/include/linux/sched.h

include/linux/sched.h +2 -0
@@ -829,6 +829,8 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
 #define PF_BORROWED_MM	0x00400000	/* I am a kthread doing use_mm */
 #define PF_RANDOMIZE	0x00800000	/* randomize virtual address space */
+#define PF_SYNCTHREAD	0x01000000	/* this thread can start activity during the 
++ 					   early part of freezing processes */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#2 lore raw

Hi.

Quoted 17 lines · Pavel Machek

Hi!

Quoted 8 lines

This patch implements a new PF_SYNCTHREAD flag, which allows upcoming the refrigerator implementation to know that a thread is syncing data to disk. This allows the refrigerator to be more reliable, even under heavy load, because it can separate userspace processes that are submitting I/O from those trying to sync it and freezing the former first. We can thus ensure that syncing processes complete their work more quickly and the refrigerator is far less likely to incorrectly give up (thinking a syncing process is completely failing to enter the refrigerator).

This patch is ****, and pretty intrusive too. Ouch and then it is unneccessary. We have been over this before, and explained to you in person. Greg explained it to you, too. This one is NOT GOING IN. Drop it from your patches, trying to submit it 10 times will not get it accepted.

Quoted 5 lines

[For the record, simple solution for this one is

sys_sync();

and only then start refrigeration].

That's not right.

Greg said he believed the right thing to do was to sync in the kernel, but he also said he agreed with you. I thought at the time he was confused about who was suggesting what - let's check with him.

Anyway, we discussed before that sync_sync before starting refrigerating is insufficient. Remember that since processes aren't refrigerated yet, there is absolutely nothing to stop other processes submitting I/O between the two actions and thus making the sync pointless. The sync needs to be done after the userspace processes that might submit I/O have been frozen, to ensure that all the dirty data is actually synced to disk.

Remember also that it is important that we do need to sync all dirty buffers. In the case of not resuming, data loss should nil.

Regards,

Nigel

Signature · 4 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
#3 lore raw
In reply to Nigel Cunningham
Quoted 8 lines · Nigel Cunningham

This patch implements a new PF_SYNCTHREAD flag, which allows upcoming the refrigerator implementation to know that a thread is syncing data to disk. This allows the refrigerator to be more reliable, even under heavy load, because it can separate userspace processes that are submitting I/O from those trying to sync it and freezing the former first. We can thus ensure that syncing processes complete their work more quickly and the refrigerator is far less likely to incorrectly give up (thinking a syncing process is completely failing to enter the refrigerator).

I don't have any strong feelings for this, one way or another. It seems kinda hacky, and it needs to be discussed publically, and it seems like it definitely seems like it doesn't need to go in immediately.

I have just a couple of suggestions below..

fs/buffer.c EXPORT_SYMBOL(sync_blockdev); · line 179

Quoted 8 lines

int fsync_super(struct super_block *sb)
{

fs/buffer.c +6 -0
+	int ret;
+
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));

Please do not add any new BUG()s. Figure out another way to gracefully fail, perhaps some place else.

Review

Quoted 1 line
(quoted diff) +1 -0
+	current->flags |= PF_SYNCTHREAD;

Is all the modification of current->flags safe? It seems like you could be pre-empted in the middle and things could get wacky.

Another note is that these changes will have to go through Al Viro, who might have some suggestions on the Right(tm) way to do it.

Pat

#4 lore raw

Hi.

Quoted 11 lines · Patrick Mochel
Quoted 8 lines · Nigel Cunningham

This patch implements a new PF_SYNCTHREAD flag, which allows upcoming the refrigerator implementation to know that a thread is syncing data to disk. This allows the refrigerator to be more reliable, even under heavy load, because it can separate userspace processes that are submitting I/O from those trying to sync it and freezing the former first. We can thus ensure that syncing processes complete their work more quickly and the refrigerator is far less likely to incorrectly give up (thinking a syncing process is completely failing to enter the refrigerator).

Quoted 3 lines

I don't have any strong feelings for this, one way or another. It seems kinda hacky, and it needs to be discussed publically, and it seems like it definitely seems like it doesn't need to go in immediately.

I'm concerned about reducing the potential data loss (if the user doesn't resume) to nil, so I'd argue that it's important.

Quoted 13 lines

I have just a couple of suggestions below..

fs/buffer.c EXPORT_SYMBOL(sync_blockdev); · line 179

Quoted 8 lines

int fsync_super(struct super_block *sb)
{

fs/buffer.c +6 -0
+	int ret;
+
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));

Please do not add any new BUG()s. Figure out another way to gracefully fail, perhaps some place else.

In the case of Suspend2, if we let the call continue, we are potentially overwriting valid data. I think that's important enough for a BUG_ON. I don't add them lightly!

Quoted 4 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	current->flags |= PF_SYNCTHREAD;

Is all the modification of current->flags safe? It seems like you could be pre-empted in the middle and things could get wacky.

In the middle of setting the flag or in the middle of the routine? If we're preempted prior to setting the flag, get refrigerated and don't continue with the call until post resume (can this happen?), it won't matter.

Quoted 2 lines

Another note is that these changes will have to go through Al Viro, who might have some suggestions on the Right(tm) way to do it.

Ok. I'll wait to see the feedback from Greg before sending to Al. Hopefully he'll either convince me I'm wrong or tell Pavel he's wrong. Whatever the case, if Greg says no, I'll not bother anymore with submitting it - even if I still disagree.

Regards,

Nigel

Signature · 4 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.