mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* please revert kthread from loop.c
@ 2006-06-26 18:39 Hugh Dickins
  2006-06-27  5:46 ` Serge E. Hallyn
  0 siblings, 1 reply; 15+ messages in thread
From: Hugh Dickins @ 2006-06-26 18:39 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Serge E. Hallyn, Andrew Morton, linux-kernel

Please revert c7b2eff059fcc2d1b7085ee3d84b79fd657a537b
[PATCH] kthread: update loop.c to use kthread

It seems too little tested: "losetup -d /dev/loop0" fails with
EINVAL because nothing sets lo_thread; but even when you patch
loop_thread() to set lo->lo_thread = current, it can't survive
more than a few dozen iterations of the loop below (with a tmpfs
mounted on /tst): collapses with failed ioctl then BUG_ON(!bio).
I think the original lo_done completion was more subtle and safe
than the kthread conversion has allowed for.

j=0
cp /dev/zero /tst
while :
do
	let j=j+1
	echo "Doing pass $j"
	losetup /dev/loop0 /tst/zero
	mkfs -t ext2 -b 1024 /dev/loop0 >/dev/null 2>&1
	mount -t ext2 /dev/loop0 /mnt
	umount /mnt
	losetup -d /dev/loop0
done

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-06-26 18:39 please revert kthread from loop.c Hugh Dickins
@ 2006-06-27  5:46 ` Serge E. Hallyn
  2006-06-28 18:41   ` Hugh Dickins
  0 siblings, 1 reply; 15+ messages in thread
From: Serge E. Hallyn @ 2006-06-27  5:46 UTC (permalink / raw)
  To: Hugh Dickins; +Cc: Linus Torvalds, Serge E. Hallyn, Andrew Morton, linux-kernel

Quoting Hugh Dickins (hugh@veritas.com):
> Please revert c7b2eff059fcc2d1b7085ee3d84b79fd657a537b
> [PATCH] kthread: update loop.c to use kthread
> 
> It seems too little tested: "losetup -d /dev/loop0" fails with
> EINVAL because nothing sets lo_thread; but even when you patch
> loop_thread() to set lo->lo_thread = current, it can't survive
> more than a few dozen iterations of the loop below (with a tmpfs
> mounted on /tst): collapses with failed ioctl then BUG_ON(!bio).
> I think the original lo_done completion was more subtle and safe
> than the kthread conversion has allowed for.
> 
> j=0
> cp /dev/zero /tst
> while :
> do
> 	let j=j+1
> 	echo "Doing pass $j"
> 	losetup /dev/loop0 /tst/zero
> 	mkfs -t ext2 -b 1024 /dev/loop0 >/dev/null 2>&1
> 	mount -t ext2 /dev/loop0 /mnt
> 	umount /mnt
> 	losetup -d /dev/loop0
> done

Very sorry.


Subject: [PATCH] kthread: convert loop.c to use kthread

Convert loop.c to use kthread in place of the deprecated
kernel_thread.

Update: Keep the lo_done completion to indicate when the
	loop_thread is ready.  Otherwise a user gets the
	go-ahead early and may start an ioctl before
	loop_thread is in fact ready.

	Also fix some other bugs including misnaming the thread,
	found by Andrew Morton, and not setting lo->thread as
	pointed out by Hugh Dickins.

	This version has passed parallel runs of the following
	script (on different devices of course), i.e.

	sh looptorture.sh 3 [ in screen 1 ]
	sh looptorture.sh 5 [ in screen 2 ]

	looptorture.sh contains the following script based
	on the one sent by Hugh Dickins earlier today:

	j=0
	if [ $# > 0 ]; then
	   num=$1
	else
	   num=0
	fi
	echo "starting loop ($num)"
	if [ ! -d /mnt/$num ]; then
		mkdir /mnt/$num
	fi
	dd if=/dev/zero of=/tst/zero$num bs=1M count=100
	while [ $j -lt 100 ]; do
		let j=j+1
		echo "Doing pass $j"
		losetup /dev/loop$num /tst/zero$num
		mkfs -t ext2 -b 1024 /dev/loop$num >/dev/null 2>&1
		mount -t ext2 /dev/loop$num /mnt/$num
		umount /mnt/$num
		losetup -d /dev/loop$num
	done

Signed-off-by: Serge Hallyn <serue@us.ibm.com>

---

 drivers/block/loop.c |   16 ++++++++++------
 include/linux/loop.h |    1 +
 2 files changed, 11 insertions(+), 6 deletions(-)

71c305041760195a3c96aedae52f7d8ce3982d72
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 3c74ea7..b3d1710 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -74,6 +74,7 @@
 #include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
+#include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 
@@ -578,8 +579,7 @@ static int loop_thread(void *data)
 	struct loop_device *lo = data;
 	struct bio *bio;
 
-	daemonize("loop%d", lo->lo_number);
-
+	lo->lo_thread = current;
 	/*
 	 * loop can be used in an encrypted device,
 	 * hence, it mustn't be stopped at all
@@ -629,7 +629,6 @@ static int loop_thread(void *data)
 			break;
 	}
 
-	complete(&lo->lo_done);
 	return 0;
 }
 
@@ -747,6 +746,7 @@ static int loop_set_fd(struct loop_devic
 	int		lo_flags = 0;
 	int		error;
 	loff_t		size;
+	struct task_struct *tsk;
 
 	/* This is safe, since we have a reference from open(). */
 	__module_get(THIS_MODULE);
@@ -839,9 +839,11 @@ static int loop_set_fd(struct loop_devic
 
 	set_blocksize(bdev, lo_blocksize);
 
-	error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
-	if (error < 0)
+	tsk = kthread_run(loop_thread, lo, "loop%d", lo->lo_number);
+	if (IS_ERR(tsk)) {
+		error = PTR_ERR(tsk);
 		goto out_putf;
+	}
 	wait_for_completion(&lo->lo_done);
 	return 0;
 
@@ -911,7 +913,7 @@ static int loop_clr_fd(struct loop_devic
 		complete(&lo->lo_bh_done);
 	spin_unlock_irq(&lo->lo_lock);
 
-	wait_for_completion(&lo->lo_done);
+	kthread_stop(lo->lo_thread);
 
 	lo->lo_backing_file = NULL;
 
@@ -921,6 +923,7 @@ static int loop_clr_fd(struct loop_devic
 	lo->lo_device = NULL;
 	lo->lo_encryption = NULL;
 	lo->lo_offset = 0;
+	lo->lo_thread = NULL;
 	lo->lo_sizelimit = 0;
 	lo->lo_encrypt_key_size = 0;
 	lo->lo_flags = 0;
@@ -1288,6 +1291,7 @@ static int __init loop_init(void)
 		if (!lo->lo_queue)
 			goto out_mem4;
 		mutex_init(&lo->lo_ctl_mutex);
+		lo->lo_thread = NULL;
 		init_completion(&lo->lo_done);
 		init_completion(&lo->lo_bh_done);
 		lo->lo_number = i;
diff --git a/include/linux/loop.h b/include/linux/loop.h
index e76c761..4bd4cde 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -59,6 +59,7 @@ struct loop_device {
 	struct bio 		*lo_bio;
 	struct bio		*lo_biotail;
 	int			lo_state;
+	struct task_struct	*lo_thread;
 	struct completion	lo_done;
 	struct completion	lo_bh_done;
 	struct mutex		lo_ctl_mutex;
-- 
1.1.6

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-06-27  5:46 ` Serge E. Hallyn
@ 2006-06-28 18:41   ` Hugh Dickins
  2006-06-28 19:08     ` Serge E. Hallyn
  2006-07-11 19:49     ` Serge E. Hallyn
  0 siblings, 2 replies; 15+ messages in thread
From: Hugh Dickins @ 2006-06-28 18:41 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: Linus Torvalds, Andrew Morton, linux-kernel

On Tue, 27 Jun 2006, Serge E. Hallyn wrote:
> 
> Very sorry.

No problem, just something I happened to notice, that's all.

> Subject: [PATCH] kthread: convert loop.c to use kthread
> 
> Convert loop.c to use kthread in place of the deprecated
> kernel_thread.
> 
> Update: Keep the lo_done completion to indicate when the
> 	loop_thread is ready.  Otherwise a user gets the
> 	go-ahead early and may start an ioctl before
> 	loop_thread is in fact ready.
> 
> 	Also fix some other bugs including misnaming the thread,
> 	found by Andrew Morton, and not setting lo->thread as
> 	pointed out by Hugh Dickins.
> 
> 	This version has passed parallel runs of the following
> 	script (on different devices of course), i.e.

But not good for me.  Gets further e.g. 170 iterations,
but then hangs while kthread_stop waits for completion.

I haven't investigated further.  Is there really any reason
to be messing with what has worked well for so long here?

Hugh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-06-28 18:41   ` Hugh Dickins
@ 2006-06-28 19:08     ` Serge E. Hallyn
  2006-07-11 19:49     ` Serge E. Hallyn
  1 sibling, 0 replies; 15+ messages in thread
From: Serge E. Hallyn @ 2006-06-28 19:08 UTC (permalink / raw)
  To: Hugh Dickins; +Cc: Serge E. Hallyn, Linus Torvalds, Andrew Morton, linux-kernel

Quoting Hugh Dickins (hugh@veritas.com):
> > 	This version has passed parallel runs of the following
> > 	script (on different devices of course), i.e.
> 
> But not good for me.  Gets further e.g. 170 iterations,
> but then hangs while kthread_stop waits for completion.

Confounded...

> I haven't investigated further.  Is there really any reason
> to be messing with what has worked well for so long here?

Only because loop.c can be compiled as a module, and kernel_thread
is slated to have it's EXPORT_SYMBOL removed.

-serge

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-06-28 18:41   ` Hugh Dickins
  2006-06-28 19:08     ` Serge E. Hallyn
@ 2006-07-11 19:49     ` Serge E. Hallyn
  2006-07-12  0:17       ` Andrew Morton
  2006-07-12 15:13       ` Hugh Dickins
  1 sibling, 2 replies; 15+ messages in thread
From: Serge E. Hallyn @ 2006-07-11 19:49 UTC (permalink / raw)
  To: Hugh Dickins; +Cc: Serge E. Hallyn, Linus Torvalds, Andrew Morton, linux-kernel

> But not good for me.  Gets further e.g. 170 iterations,
> but then hangs while kthread_stop waits for completion.

After getting much more familiar with the code, here is a more invasive,
but pretty heavily tested patch.

> I haven't investigated further.  Is there really any reason
> to be messing with what has worked well for so long here?

If the EXPORT_SYMBOL(kernel_thread) is going to be removed, then
this code will have to be updated.  Otherwise, no, the code as is
doesn't use pids to reference tasks, so the original code would be
fine with me.

thanks,
-serge

From: Serge Hallyn <serue@us.ibm.com>
Subject: [PATCH] kthread: convert loop.c to kthread

Convert loop.c from the deprecated kernel_thread to kthread.
This patch also simplifies the code a bit.  It has passed
vigerous testing.  The following script, looptorture.sh,
which mounts and unmounts loopback device 1000 times,
completes in three terminals simultaneously on different
loop devices.  For example, started up screen, created
three screens, and typed each of the following lines into
a separate screen:
	sh loopback.sh 2
	sh loopback.sh 3
	sh loopback.sh 4

loopback.sh:
	j=0
	if [ $# > 0 ]; then
	   num=$1
	else
	   num="0"
	fi
	echo "starting loop ($num)"
	if [ ! -d /mnt/$num ]; then
		mkdir /mnt/$num
	fi
	dd if=/dev/zero of=/tst/zero$num bs=1M count=100
	while [ $j -lt 1000 ]; do
		let j=j+1
		echo "Doing pass $j"
		losetup /dev/loop$num /tst/zero$num
		mkfs -t ext2 -b 1024 /dev/loop$num >/dev/null 2>&1
		mount -t ext2 /dev/loop$num /mnt/$num
		echo hello > /mnt/$num/hw
		umount /mnt/$num
		losetup -d /dev/loop$num
	done

A partial kernel build on a loopback partition also worked fine.
I have not tested encrypted devices, or suspend to loopback device.

Changes since last attempt:
	Eliminated lo->lo_done and lo->lo_bh_done completions.
	The former is not needed because we can wake up the thread
	when we're ready.  The latter was used for waking the
	loop_thread up when there was something to do or it was
	time to quit, and we no longer need this since we simply
	wake the thread directly when there's data.

	The lo->pending count used to be set at one plus actual
	pending actions, and was reduced to 0 only when it was time
	to quit.  We now use kthread_should_stop() to find out whether
	we're done, though we do not actually stop until there are no
	pending actions.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>

---

 drivers/block/loop.c |   71 ++++++++++++++++++--------------------------------
 include/linux/loop.h |    3 +-
 2 files changed, 27 insertions(+), 47 deletions(-)

b56590212f3050dbb6c630eeea3a44794c9c7439
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ccaada1..bdad531 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -72,6 +72,7 @@
 #include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
+#include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 
@@ -525,12 +526,10 @@ static int loop_make_request(request_que
 	lo->lo_pending++;
 	loop_add_bio(lo, old_bio);
 	spin_unlock_irq(&lo->lo_lock);
-	complete(&lo->lo_bh_done);
+	wake_up_process(lo->lo_thread);
 	return 0;
 
 out:
-	if (lo->lo_pending == 0)
-		complete(&lo->lo_bh_done);
 	spin_unlock_irq(&lo->lo_lock);
 	bio_io_error(old_bio, old_bio->bi_size);
 	return 0;
@@ -576,8 +575,6 @@ static int loop_thread(void *data)
 	struct loop_device *lo = data;
 	struct bio *bio;
 
-	daemonize("loop%d", lo->lo_number);
-
 	/*
 	 * loop can be used in an encrypted device,
 	 * hence, it mustn't be stopped at all
@@ -587,47 +584,28 @@ static int loop_thread(void *data)
 
 	set_user_nice(current, -20);
 
-	lo->lo_state = Lo_bound;
-	lo->lo_pending = 1;
-
-	/*
-	 * complete it, we are running
-	 */
-	complete(&lo->lo_done);
-
 	for (;;) {
-		int pending;
-
-		if (wait_for_completion_interruptible(&lo->lo_bh_done))
-			continue;
-
 		spin_lock_irq(&lo->lo_lock);
+		while (lo->lo_pending) {
+			bio = loop_get_bio(lo);
+			lo->lo_pending--;
 
-		/*
-		 * could be completed because of tear-down, not pending work
-		 */
-		if (unlikely(!lo->lo_pending)) {
 			spin_unlock_irq(&lo->lo_lock);
-			break;
+			BUG_ON(!bio);
+			loop_handle_bio(lo, bio);
+			spin_lock_irq(&lo->lo_lock);
 		}
 
-		bio = loop_get_bio(lo);
-		lo->lo_pending--;
-		pending = lo->lo_pending;
+		if (kthread_should_stop()) {
+			spin_unlock_irq(&lo->lo_lock);
+			break;
+		}
 		spin_unlock_irq(&lo->lo_lock);
 
-		BUG_ON(!bio);
-		loop_handle_bio(lo, bio);
-
-		/*
-		 * upped both for pending work and tear-down, lo_pending
-		 * will hit zero then
-		 */
-		if (unlikely(!pending))
-			break;
+		__set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
 	}
 
-	complete(&lo->lo_done);
 	return 0;
 }
 
@@ -846,10 +824,16 @@ static int loop_set_fd(struct loop_devic
 
 	set_blocksize(bdev, lo_blocksize);
 
-	error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
-	if (error < 0)
+	lo->lo_thread = kthread_create(loop_thread, lo, "loop%d",
+						lo->lo_number);
+	if (IS_ERR(lo->lo_thread)) {
+		error = PTR_ERR(lo->lo_thread);
+		lo->lo_thread = NULL;
 		goto out_putf;
-	wait_for_completion(&lo->lo_done);
+	}
+	lo->lo_pending = 0;
+	lo->lo_state = Lo_bound;
+	wake_up_process(lo->lo_thread);
 	return 0;
 
  out_putf:
@@ -913,12 +897,9 @@ static int loop_clr_fd(struct loop_devic
 
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_rundown;
-	lo->lo_pending--;
-	if (!lo->lo_pending)
-		complete(&lo->lo_bh_done);
 	spin_unlock_irq(&lo->lo_lock);
 
-	wait_for_completion(&lo->lo_done);
+	kthread_stop(lo->lo_thread);
 
 	lo->lo_backing_file = NULL;
 
@@ -928,6 +909,7 @@ static int loop_clr_fd(struct loop_devic
 	lo->lo_device = NULL;
 	lo->lo_encryption = NULL;
 	lo->lo_offset = 0;
+	lo->lo_thread = NULL;
 	lo->lo_sizelimit = 0;
 	lo->lo_encrypt_key_size = 0;
 	lo->lo_flags = 0;
@@ -1293,8 +1275,7 @@ static int __init loop_init(void)
 		if (!lo->lo_queue)
 			goto out_mem4;
 		mutex_init(&lo->lo_ctl_mutex);
-		init_completion(&lo->lo_done);
-		init_completion(&lo->lo_bh_done);
+		lo->lo_thread = NULL;
 		lo->lo_number = i;
 		spin_lock_init(&lo->lo_lock);
 		disk->major = LOOP_MAJOR;
diff --git a/include/linux/loop.h b/include/linux/loop.h
index e76c761..51dee29 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -59,8 +59,7 @@ struct loop_device {
 	struct bio 		*lo_bio;
 	struct bio		*lo_biotail;
 	int			lo_state;
-	struct completion	lo_done;
-	struct completion	lo_bh_done;
+	struct task_struct	*lo_thread;
 	struct mutex		lo_ctl_mutex;
 	int			lo_pending;
 
-- 
1.1.6

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-11 19:49     ` Serge E. Hallyn
@ 2006-07-12  0:17       ` Andrew Morton
  2006-07-12  3:26         ` Serge E. Hallyn
  2006-07-12 15:13       ` Hugh Dickins
  1 sibling, 1 reply; 15+ messages in thread
From: Andrew Morton @ 2006-07-12  0:17 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: hugh, serue, torvalds, linux-kernel

"Serge E. Hallyn" <serue@us.ibm.com> wrote:
>
> Convert loop.c from the deprecated kernel_thread to kthread.
>

I think you have a racelet here:

> +		}
>  		spin_unlock_irq(&lo->lo_lock);
>  
> -		BUG_ON(!bio);
> -		loop_handle_bio(lo, bio);
> -
> -		/*
> -		 * upped both for pending work and tear-down, lo_pending
> -		 * will hit zero then
> -		 */
> -		if (unlikely(!pending))
> -			break;
> +		__set_current_state(TASK_INTERRUPTIBLE);
> +		schedule();
>  	}
>  
> -	complete(&lo->lo_done);
>  	return 0;
>  }


:		if (kthread_should_stop()) {
:			spin_unlock_irq(&lo->lo_lock);
:			break;
:		}
:		spin_unlock_irq(&lo->lo_lock);
:
:		__set_current_state(TASK_INTERRUPTIBLE);
:		schedule();
:

If the wake_up_process() is delivered before the __set_current_state(),
we'll miss the wakeup.

If so, this should plug it.  The same race is not possible against the
loop_set_fd() wakeup because the thread isn't running at that stage, yes?


diff -puN drivers/block/loop.c~kthread-convert-loopc-to-kthread-race-fix drivers/block/loop.c
--- a/drivers/block/loop.c~kthread-convert-loopc-to-kthread-race-fix
+++ a/drivers/block/loop.c
@@ -525,8 +525,8 @@ static int loop_make_request(request_que
 		goto out;
 	lo->lo_pending++;
 	loop_add_bio(lo, old_bio);
-	spin_unlock_irq(&lo->lo_lock);
 	wake_up_process(lo->lo_thread);
+	spin_unlock_irq(&lo->lo_lock);
 	return 0;
 
 out:
@@ -600,9 +600,8 @@ static int loop_thread(void *data)
 			spin_unlock_irq(&lo->lo_lock);
 			break;
 		}
-		spin_unlock_irq(&lo->lo_lock);
-
 		__set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irq(&lo->lo_lock);
 		schedule();
 	}
 
_


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-12  0:17       ` Andrew Morton
@ 2006-07-12  3:26         ` Serge E. Hallyn
  2006-07-12  3:46           ` Andrew Morton
  0 siblings, 1 reply; 15+ messages in thread
From: Serge E. Hallyn @ 2006-07-12  3:26 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Serge E. Hallyn, hugh, torvalds, linux-kernel

Quoting Andrew Morton (akpm@osdl.org):
> "Serge E. Hallyn" <serue@us.ibm.com> wrote:
> >
> > Convert loop.c from the deprecated kernel_thread to kthread.
> >
> 
> I think you have a racelet here:
> 
> > +		}
> >  		spin_unlock_irq(&lo->lo_lock);
> >  
> > -		BUG_ON(!bio);
> > -		loop_handle_bio(lo, bio);
> > -
> > -		/*
> > -		 * upped both for pending work and tear-down, lo_pending
> > -		 * will hit zero then
> > -		 */
> > -		if (unlikely(!pending))
> > -			break;
> > +		__set_current_state(TASK_INTERRUPTIBLE);
> > +		schedule();
> >  	}
> >  
> > -	complete(&lo->lo_done);
> >  	return 0;
> >  }
> 
> 
> :		if (kthread_should_stop()) {
> :			spin_unlock_irq(&lo->lo_lock);
> :			break;
> :		}
> :		spin_unlock_irq(&lo->lo_lock);
> :
> :		__set_current_state(TASK_INTERRUPTIBLE);
> :		schedule();
> :
> 
> If the wake_up_process() is delivered before the __set_current_state(),
> we'll miss the wakeup.

Makes sense, and the patched kernel passes the parallel tests.

Thanks for the patch.

> If so, this should plug it.  The same race is not possible against the
> loop_set_fd() wakeup because the thread isn't running at that stage, yes?

Right, it's not yet running at loop_set_fd().  However what about
kthread_stop() called from loop_clr_fd()?  Unfortunately fixing
that seems hairy.  Need to think about it...

thanks,
-serge

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-12  3:26         ` Serge E. Hallyn
@ 2006-07-12  3:46           ` Andrew Morton
  2006-07-12 14:31             ` Serge E. Hallyn
  2006-07-12 23:02             ` Serge E. Hallyn
  0 siblings, 2 replies; 15+ messages in thread
From: Andrew Morton @ 2006-07-12  3:46 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: serue, hugh, torvalds, linux-kernel

On Tue, 11 Jul 2006 22:26:47 -0500
"Serge E. Hallyn" <serue@us.ibm.com> wrote:

> > If so, this should plug it.  The same race is not possible against the
> > loop_set_fd() wakeup because the thread isn't running at that stage, yes?
> 
> Right, it's not yet running at loop_set_fd().  However what about
> kthread_stop() called from loop_clr_fd()?  Unfortunately fixing
> that seems hairy.  Need to think about it...

Yes, there does seem to be a little race there.

I think it would be sufficient to do


diff -puN drivers/block/loop.c~a drivers/block/loop.c
--- a/drivers/block/loop.c~a
+++ a/drivers/block/loop.c
@@ -602,7 +602,8 @@ static int loop_thread(void *data)
 		}
 		__set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irq(&lo->lo_lock);
-		schedule();
+		if (lo->state != Lo_rundown)
+			schedule();
 	}
 
 	return 0;
@@ -888,12 +889,11 @@ static int loop_clr_fd(struct loop_devic
 	if (filp == NULL)
 		return -EINVAL;
 
+	kthread_stop(lo->lo_thread);
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_rundown;
 	spin_unlock_irq(&lo->lo_lock);
 
-	kthread_stop(lo->lo_thread);
-
 	lo->lo_backing_file = NULL;
 
 	loop_release_xfer(lo);
_

where the tweak to loop_clr_fd() is just there to prevent loop_thread()
from going into a very brief busyloop.

I'm not sure why it's all so tricky in there, really.  Loop is doing a
pretty conventional stop, wakeup, stick-things-on-lists operation and we do
that all over the kernel using pretty well-understood idioms.  But for some
reason, loop is all difficult about it.  I wonder why.  hm.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-12  3:46           ` Andrew Morton
@ 2006-07-12 14:31             ` Serge E. Hallyn
  2006-07-12 23:02             ` Serge E. Hallyn
  1 sibling, 0 replies; 15+ messages in thread
From: Serge E. Hallyn @ 2006-07-12 14:31 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Serge E. Hallyn, hugh, torvalds, linux-kernel

Quoting Andrew Morton (akpm@osdl.org):
> On Tue, 11 Jul 2006 22:26:47 -0500
> "Serge E. Hallyn" <serue@us.ibm.com> wrote:
> 
> > > If so, this should plug it.  The same race is not possible against the
> > > loop_set_fd() wakeup because the thread isn't running at that stage, yes?
> > 
> > Right, it's not yet running at loop_set_fd().  However what about
> > kthread_stop() called from loop_clr_fd()?  Unfortunately fixing
> > that seems hairy.  Need to think about it...
> 
> Yes, there does seem to be a little race there.
> 
> I think it would be sufficient to do
> 
> 
> diff -puN drivers/block/loop.c~a drivers/block/loop.c
> --- a/drivers/block/loop.c~a
> +++ a/drivers/block/loop.c
> @@ -602,7 +602,8 @@ static int loop_thread(void *data)
>  		}
>  		__set_current_state(TASK_INTERRUPTIBLE);
>  		spin_unlock_irq(&lo->lo_lock);
> -		schedule();
> +		if (lo->state != Lo_rundown)
> +			schedule();
>  	}
>  
>  	return 0;
> @@ -888,12 +889,11 @@ static int loop_clr_fd(struct loop_devic
>  	if (filp == NULL)
>  		return -EINVAL;
>  
> +	kthread_stop(lo->lo_thread);
>  	spin_lock_irq(&lo->lo_lock);
>  	lo->lo_state = Lo_rundown;
>  	spin_unlock_irq(&lo->lo_lock);
>  
> -	kthread_stop(lo->lo_thread);
> -
>  	lo->lo_backing_file = NULL;
>  
>  	loop_release_xfer(lo);
> _
> 
> where the tweak to loop_clr_fd() is just there to prevent loop_thread()
> from going into a very brief busyloop.

Why does this fix the problem?  Can't the wake_up_process() in
kthread_stop() still happen right before loop_thread's schedule()?

This also means that after loop_thread() has decided to stop,
make_request() has a chance to make a few more requests.  It
will see lo->lo_state as bound, assume all is well, but when it goes to
wake_up_thread(), the thread will have been put_task_struct()d.

If I'm not entirely wrong above, how about the following alternate fix?  
Unfortunately I guess it doesn't stop the brief busyloop...

> I'm not sure why it's all so tricky in there, really.  Loop is doing a
> pretty conventional stop, wakeup, stick-things-on-lists operation and we do
> that all over the kernel using pretty well-understood idioms.  But for some
> reason, loop is all difficult about it.  I wonder why.  hm.

Perhaps I should give completions another go.

thanks,
-serge

Subject: [PATCH 3/3] kthread: fix loop.c race at thread stop

The wake_up_process() from kthread_stop() could happen
between loop_thread's __set_current_state(TASK_INTERRUPTIBLE)
and schedule().  But we can't put kthread_stop() under the
spin_lock like we did the wake_up_process() in make_request().

So turn the thread stopping into a two-phase process.  Do
a wake_up_process() under spin_lock after setting the
lo_state to Lo_rundown, after which the loop_thread no
long sleeps.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>

---

 drivers/block/loop.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

e972f09b6ca27a7ac3421ab49bde6dba33fca62c
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f944536..df38e05 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -600,9 +600,13 @@ static int loop_thread(void *data)
 			spin_unlock_irq(&lo->lo_lock);
 			break;
 		}
-		__set_current_state(TASK_INTERRUPTIBLE);
+		if (lo->lo_state != Lo_rundown)
+			__set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irq(&lo->lo_lock);
-		schedule();
+		if (lo->lo_state != Lo_rundown)
+			schedule();
+		else
+			__set_current_state(TASK_UNINTERRUPTIBLE);
 	}
 
 	return 0;
@@ -896,6 +900,7 @@ static int loop_clr_fd(struct loop_devic
 
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_rundown;
+	wake_up_process(lo->lo_thread);
 	spin_unlock_irq(&lo->lo_lock);
 
 	kthread_stop(lo->lo_thread);
-- 
1.1.6

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-11 19:49     ` Serge E. Hallyn
  2006-07-12  0:17       ` Andrew Morton
@ 2006-07-12 15:13       ` Hugh Dickins
  1 sibling, 0 replies; 15+ messages in thread
From: Hugh Dickins @ 2006-07-12 15:13 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: Linus Torvalds, Andrew Morton, linux-kernel

On Tue, 11 Jul 2006, Serge E. Hallyn wrote:
> > But not good for me.  Gets further e.g. 170 iterations,
> > but then hangs while kthread_stop waits for completion.
> 
> After getting much more familiar with the code, here is a more invasive,
> but pretty heavily tested patch.

I didn't study your patch in detail: as you say, more invasive,
but if it really does the job then it's an improvement, removing
some mystery from loop_thread().  And it does work fine for me -
well, I tested with your next little race addition, and Andrew's
on top of that (with lo->state typo fixed to lo->lo_state); but
I haven't tried your latest refinement from today.

Thanks,
Hugh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-12  3:46           ` Andrew Morton
  2006-07-12 14:31             ` Serge E. Hallyn
@ 2006-07-12 23:02             ` Serge E. Hallyn
  2006-07-13  9:38               ` Andrew Morton
  1 sibling, 1 reply; 15+ messages in thread
From: Serge E. Hallyn @ 2006-07-12 23:02 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Serge E. Hallyn, hugh, torvalds, linux-kernel

Quoting Andrew Morton (akpm@osdl.org):
> I'm not sure why it's all so tricky in there, really.  Loop is doing a
> pretty conventional stop, wakeup, stick-things-on-lists operation and we do
> that all over the kernel using pretty well-understood idioms.  But for some
> reason, loop is all difficult about it.  I wonder why.  hm.

Does this version, going back to using a completion - lo->lo_wait - seem
a touch simpler?

thanks,
-serge

From: "Serge E. Hallyn" <serue@us.ibm.com>
Subject: [PATCH] kthread: convert loop.c to kthread

Convert loop.c from the deprecated kernel_thread to kthread.

This version goes back to using a completion for waking the
loop_thread when there is work to do.  Ending the loop thread
is done by first setting the state, then waking the thread
using the completion, and finally calling kthread_stop().
The loop_thread is either already awake serving requests,
or is awoken by loop_clr_fd()s complete.  It does one more
loop to serve pending requests, after which it sees it's
state is no longer running, and starts a short busyloop
while waiting to be reaped.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>

---

 drivers/block/loop.c |   73 +++++++++++++++++++-------------------------------
 include/linux/loop.h |    4 +--
 2 files changed, 30 insertions(+), 47 deletions(-)

5aa946838754cc8bd1582ca3f926cf51d7e21df8
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ccaada1..8779194 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -72,6 +72,7 @@
 #include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
+#include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 
@@ -524,13 +525,11 @@ static int loop_make_request(request_que
 		goto out;
 	lo->lo_pending++;
 	loop_add_bio(lo, old_bio);
+	complete(&lo->lo_wait);
 	spin_unlock_irq(&lo->lo_lock);
-	complete(&lo->lo_bh_done);
 	return 0;
 
 out:
-	if (lo->lo_pending == 0)
-		complete(&lo->lo_bh_done);
 	spin_unlock_irq(&lo->lo_lock);
 	bio_io_error(old_bio, old_bio->bi_size);
 	return 0;
@@ -576,8 +575,6 @@ static int loop_thread(void *data)
 	struct loop_device *lo = data;
 	struct bio *bio;
 
-	daemonize("loop%d", lo->lo_number);
-
 	/*
 	 * loop can be used in an encrypted device,
 	 * hence, it mustn't be stopped at all
@@ -587,47 +584,28 @@ static int loop_thread(void *data)
 
 	set_user_nice(current, -20);
 
-	lo->lo_state = Lo_bound;
-	lo->lo_pending = 1;
-
-	/*
-	 * complete it, we are running
-	 */
-	complete(&lo->lo_done);
-
 	for (;;) {
-		int pending;
-
-		if (wait_for_completion_interruptible(&lo->lo_bh_done))
-			continue;
-
 		spin_lock_irq(&lo->lo_lock);
+		while (lo->lo_pending) {
+			bio = loop_get_bio(lo);
+			lo->lo_pending--;
 
-		/*
-		 * could be completed because of tear-down, not pending work
-		 */
-		if (unlikely(!lo->lo_pending)) {
 			spin_unlock_irq(&lo->lo_lock);
-			break;
+			BUG_ON(!bio);
+			loop_handle_bio(lo, bio);
+			spin_lock_irq(&lo->lo_lock);
 		}
 
-		bio = loop_get_bio(lo);
-		lo->lo_pending--;
-		pending = lo->lo_pending;
+		if (lo->lo_state == Lo_rundown) {
+			spin_unlock_irq(&lo->lo_lock);
+			while (!kthread_should_stop());
+			break;
+		}
 		spin_unlock_irq(&lo->lo_lock);
 
-		BUG_ON(!bio);
-		loop_handle_bio(lo, bio);
-
-		/*
-		 * upped both for pending work and tear-down, lo_pending
-		 * will hit zero then
-		 */
-		if (unlikely(!pending))
-			break;
+		wait_for_completion_interruptible(&lo->lo_wait);
 	}
 
-	complete(&lo->lo_done);
 	return 0;
 }
 
@@ -846,10 +824,16 @@ static int loop_set_fd(struct loop_devic
 
 	set_blocksize(bdev, lo_blocksize);
 
-	error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
-	if (error < 0)
+	lo->lo_thread = kthread_create(loop_thread, lo, "loop%d",
+						lo->lo_number);
+	if (IS_ERR(lo->lo_thread)) {
+		error = PTR_ERR(lo->lo_thread);
+		lo->lo_thread = NULL;
 		goto out_putf;
-	wait_for_completion(&lo->lo_done);
+	}
+	lo->lo_pending = 0;
+	lo->lo_state = Lo_bound;
+	wake_up_process(lo->lo_thread);
 	return 0;
 
  out_putf:
@@ -913,12 +897,10 @@ static int loop_clr_fd(struct loop_devic
 
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_rundown;
-	lo->lo_pending--;
-	if (!lo->lo_pending)
-		complete(&lo->lo_bh_done);
+	complete(&lo->lo_wait);
 	spin_unlock_irq(&lo->lo_lock);
 
-	wait_for_completion(&lo->lo_done);
+	kthread_stop(lo->lo_thread);
 
 	lo->lo_backing_file = NULL;
 
@@ -928,6 +910,7 @@ static int loop_clr_fd(struct loop_devic
 	lo->lo_device = NULL;
 	lo->lo_encryption = NULL;
 	lo->lo_offset = 0;
+	lo->lo_thread = NULL;
 	lo->lo_sizelimit = 0;
 	lo->lo_encrypt_key_size = 0;
 	lo->lo_flags = 0;
@@ -1293,8 +1276,8 @@ static int __init loop_init(void)
 		if (!lo->lo_queue)
 			goto out_mem4;
 		mutex_init(&lo->lo_ctl_mutex);
-		init_completion(&lo->lo_done);
-		init_completion(&lo->lo_bh_done);
+		init_completion(&lo->lo_wait);
+		lo->lo_thread = NULL;
 		lo->lo_number = i;
 		spin_lock_init(&lo->lo_lock);
 		disk->major = LOOP_MAJOR;
diff --git a/include/linux/loop.h b/include/linux/loop.h
index e76c761..c9a0a45 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -59,8 +59,8 @@ struct loop_device {
 	struct bio 		*lo_bio;
 	struct bio		*lo_biotail;
 	int			lo_state;
-	struct completion	lo_done;
-	struct completion	lo_bh_done;
+	struct completion	lo_wait;
+	struct task_struct	*lo_thread;
 	struct mutex		lo_ctl_mutex;
 	int			lo_pending;
 
-- 
1.1.6

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-12 23:02             ` Serge E. Hallyn
@ 2006-07-13  9:38               ` Andrew Morton
  2006-07-13 13:36                 ` Serge E. Hallyn
  0 siblings, 1 reply; 15+ messages in thread
From: Andrew Morton @ 2006-07-13  9:38 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: serue, hugh, torvalds, linux-kernel

On Wed, 12 Jul 2006 18:02:29 -0500
"Serge E. Hallyn" <serue@us.ibm.com> wrote:

> +		if (lo->lo_state == Lo_rundown) {
> +			spin_unlock_irq(&lo->lo_lock);
> +			while (!kthread_should_stop());

eww.

A schedule_timeout_uninterruptible(1) or even cpu_relax() would be less
sinful, but still unpleasant.

It's strange that the problem of kthread_stop(already_exitted_task) hasn't
occurred before.

Again: why is this so hard?  It shouldn't be.  Perhaps because loop is
using completions in bizarre ways where it should be using
wake_up_process(), wait_event(), etc.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-13  9:38               ` Andrew Morton
@ 2006-07-13 13:36                 ` Serge E. Hallyn
  2006-07-13 14:57                   ` Andrew Morton
  0 siblings, 1 reply; 15+ messages in thread
From: Serge E. Hallyn @ 2006-07-13 13:36 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Serge E. Hallyn, hugh, torvalds, linux-kernel

Quoting Andrew Morton (akpm@osdl.org):

> Again: why is this so hard?  It shouldn't be.  Perhaps because loop is
> using completions in bizarre ways where it should be using
> wake_up_process(), wait_event(), etc.

Ah.

wait_event() actually seems like the way to go - I'll try to follow the
example in fs/ocfs2/journal.c.

Still I'd also like to patch kthread to correctly handle an already
exited thread.  Would that be acceptable, or is requiring the thread not
to exit prematurely considered desirable?

thanks,
-serge

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-13 13:36                 ` Serge E. Hallyn
@ 2006-07-13 14:57                   ` Andrew Morton
  2006-07-20 17:00                     ` Serge E. Hallyn
  0 siblings, 1 reply; 15+ messages in thread
From: Andrew Morton @ 2006-07-13 14:57 UTC (permalink / raw)
  To: Serge E. Hallyn; +Cc: serue, hugh, torvalds, linux-kernel

On Thu, 13 Jul 2006 08:36:02 -0500
"Serge E. Hallyn" <serue@us.ibm.com> wrote:

> Quoting Andrew Morton (akpm@osdl.org):
> 
> > Again: why is this so hard?  It shouldn't be.  Perhaps because loop is
> > using completions in bizarre ways where it should be using
> > wake_up_process(), wait_event(), etc.
> 
> Ah.
> 
> wait_event() actually seems like the way to go - I'll try to follow the
> example in fs/ocfs2/journal.c.

I suspect quite a lot of changes to loop.c would fall out.  For a start, in
a sufficiently-simplified implementation lo_pending would perhaps go away -
just test the NULLness of the top of the list of BIOs.

> Still I'd also like to patch kthread to correctly handle an already
> exited thread.  Would that be acceptable, or is requiring the thread not
> to exit prematurely considered desirable?

That would seem sensible, but I don't immediately see how to do it
non-racily without changing the API or by adding a `struct completion' to
the task_struct.  Because the task might be exitting-but-not-exitted, and
still using resources which the kthread_stop() caller wants to release.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: please revert kthread from loop.c
  2006-07-13 14:57                   ` Andrew Morton
@ 2006-07-20 17:00                     ` Serge E. Hallyn
  0 siblings, 0 replies; 15+ messages in thread
From: Serge E. Hallyn @ 2006-07-20 17:00 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Serge E. Hallyn, hugh, torvalds, linux-kernel

Quoting Andrew Morton (akpm@osdl.org):
> On Thu, 13 Jul 2006 08:36:02 -0500
> "Serge E. Hallyn" <serue@us.ibm.com> wrote:
> 
> > Quoting Andrew Morton (akpm@osdl.org):
> > 
> > > Again: why is this so hard?  It shouldn't be.  Perhaps because loop is
> > > using completions in bizarre ways where it should be using
> > > wake_up_process(), wait_event(), etc.
> > 
> > Ah.
> > 
> > wait_event() actually seems like the way to go - I'll try to follow the
> > example in fs/ocfs2/journal.c.
> 
> I suspect quite a lot of changes to loop.c would fall out.  For a start, in
> a sufficiently-simplified implementation lo_pending would perhaps go away -
> just test the NULLness of the top of the list of BIOs.

True - here is an attempt at that:

Subject: [PATCH] kthread: convert loop.c to kthread
From: Serge E. Hallyn <hallyn@sergelap.(none)>
Date: 1153345222 -0500

Convert loop.c from the deprecated kernel_thread to kthread.
This patch simplifies the code quite a bit and passes similar
testing to the previous submission on both emulated x86 and
s390.

Changes since last submission:
	switched to using a rather simple loop based on
	wait_event_interruptible.

Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>

---

 drivers/block/loop.c |   69 +++++++++++++++++---------------------------------
 include/linux/loop.h |    5 +---
 2 files changed, 26 insertions(+), 48 deletions(-)

c5f5e9d7016d6fb2b43aa4b13aea302ac367a28c
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 7b3b94d..0468785 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -72,6 +72,7 @@
 #include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
+#include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 
@@ -522,15 +523,12 @@ static int loop_make_request(request_que
 		goto out;
 	if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY)))
 		goto out;
-	lo->lo_pending++;
 	loop_add_bio(lo, old_bio);
+	wake_up(&lo->lo_event);
 	spin_unlock_irq(&lo->lo_lock);
-	complete(&lo->lo_bh_done);
 	return 0;
 
 out:
-	if (lo->lo_pending == 0)
-		complete(&lo->lo_bh_done);
 	spin_unlock_irq(&lo->lo_lock);
 	bio_io_error(old_bio, old_bio->bi_size);
 	return 0;
@@ -570,14 +568,18 @@ static inline void loop_handle_bio(struc
  * to avoid blocking in our make_request_fn. it also does loop decrypting
  * on reads for block backed loop, as that is too heavy to do from
  * b_end_io context where irqs may be disabled.
+ *
+ * Loop explanation:  loop_clr_fd() sets lo_state to Lo_rundown before
+ * calling kthread_stop().  Therefore once kthread_should_stop() is
+ * true, make_request will not place any more requests.  Therefore
+ * once kthread_should_stop() is true and lo_bio is NULL, we are
+ * done with the loop.
  */
 static int loop_thread(void *data)
 {
 	struct loop_device *lo = data;
 	struct bio *bio;
 
-	daemonize("loop%d", lo->lo_number);
-
 	/*
 	 * loop can be used in an encrypted device,
 	 * hence, it mustn't be stopped at all
@@ -587,47 +589,21 @@ static int loop_thread(void *data)
 
 	set_user_nice(current, -20);
 
-	lo->lo_state = Lo_bound;
-	lo->lo_pending = 1;
-
-	/*
-	 * complete it, we are running
-	 */
-	complete(&lo->lo_done);
+	while (!kthread_should_stop() || lo->lo_bio) {
 
-	for (;;) {
-		int pending;
+		wait_event_interruptible(lo->lo_event,
+				lo->lo_bio || kthread_should_stop());
 
-		if (wait_for_completion_interruptible(&lo->lo_bh_done))
+		if (!lo->lo_bio)
 			continue;
-
 		spin_lock_irq(&lo->lo_lock);
-
-		/*
-		 * could be completed because of tear-down, not pending work
-		 */
-		if (unlikely(!lo->lo_pending)) {
-			spin_unlock_irq(&lo->lo_lock);
-			break;
-		}
-
 		bio = loop_get_bio(lo);
-		lo->lo_pending--;
-		pending = lo->lo_pending;
 		spin_unlock_irq(&lo->lo_lock);
 
 		BUG_ON(!bio);
 		loop_handle_bio(lo, bio);
-
-		/*
-		 * upped both for pending work and tear-down, lo_pending
-		 * will hit zero then
-		 */
-		if (unlikely(!pending))
-			break;
 	}
 
-	complete(&lo->lo_done);
 	return 0;
 }
 
@@ -837,10 +813,15 @@ static int loop_set_fd(struct loop_devic
 
 	set_blocksize(bdev, lo_blocksize);
 
-	error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
-	if (error < 0)
+	lo->lo_thread = kthread_create(loop_thread, lo, "loop%d",
+						lo->lo_number);
+	if (IS_ERR(lo->lo_thread)) {
+		error = PTR_ERR(lo->lo_thread);
+		lo->lo_thread = NULL;
 		goto out_putf;
-	wait_for_completion(&lo->lo_done);
+	}
+	lo->lo_state = Lo_bound;
+	wake_up_process(lo->lo_thread);
 	return 0;
 
  out_putf:
@@ -904,12 +885,9 @@ static int loop_clr_fd(struct loop_devic
 
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_rundown;
-	lo->lo_pending--;
-	if (!lo->lo_pending)
-		complete(&lo->lo_bh_done);
 	spin_unlock_irq(&lo->lo_lock);
 
-	wait_for_completion(&lo->lo_done);
+	kthread_stop(lo->lo_thread);
 
 	lo->lo_backing_file = NULL;
 
@@ -922,6 +900,7 @@ static int loop_clr_fd(struct loop_devic
 	lo->lo_sizelimit = 0;
 	lo->lo_encrypt_key_size = 0;
 	lo->lo_flags = 0;
+	lo->lo_thread = NULL;
 	memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
 	memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
 	memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1284,9 +1263,9 @@ static int __init loop_init(void)
 		if (!lo->lo_queue)
 			goto out_mem4;
 		mutex_init(&lo->lo_ctl_mutex);
-		init_completion(&lo->lo_done);
-		init_completion(&lo->lo_bh_done);
 		lo->lo_number = i;
+		lo->lo_thread = NULL;
+		init_waitqueue_head(&lo->lo_event);
 		spin_lock_init(&lo->lo_lock);
 		disk->major = LOOP_MAJOR;
 		disk->first_minor = i;
diff --git a/include/linux/loop.h b/include/linux/loop.h
index e76c761..191a595 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -59,10 +59,9 @@ struct loop_device {
 	struct bio 		*lo_bio;
 	struct bio		*lo_biotail;
 	int			lo_state;
-	struct completion	lo_done;
-	struct completion	lo_bh_done;
 	struct mutex		lo_ctl_mutex;
-	int			lo_pending;
+	struct task_struct	*lo_thread;
+	wait_queue_head_t	lo_event;
 
 	request_queue_t		*lo_queue;
 };
-- 
1.1.6

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2006-07-20 17:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-26 18:39 please revert kthread from loop.c Hugh Dickins
2006-06-27  5:46 ` Serge E. Hallyn
2006-06-28 18:41   ` Hugh Dickins
2006-06-28 19:08     ` Serge E. Hallyn
2006-07-11 19:49     ` Serge E. Hallyn
2006-07-12  0:17       ` Andrew Morton
2006-07-12  3:26         ` Serge E. Hallyn
2006-07-12  3:46           ` Andrew Morton
2006-07-12 14:31             ` Serge E. Hallyn
2006-07-12 23:02             ` Serge E. Hallyn
2006-07-13  9:38               ` Andrew Morton
2006-07-13 13:36                 ` Serge E. Hallyn
2006-07-13 14:57                   ` Andrew Morton
2006-07-20 17:00                     ` Serge E. Hallyn
2006-07-12 15:13       ` Hugh Dickins

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®