All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-09-28 20:28 ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-09-28 20:28 UTC (permalink / raw)
  To: linux-kernel, Takashi Iwai; +Cc: mingo, alsa-devel

Hi

It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
but its not. bug showed again reliably under memory-pressure.

      Karsten

===

Reset file->f_op in snd_card_file_remove(). Take 2


i think what happens here is:

  us428control runs, kernel has allocated a struct file for /dev/hwC1D0.

  usb disconnect

  snd_usb_usx2y calls snd_card_disconnect,
  tells us428control to exit.

  snd_card_disconnect replaces /dev/hwC1D0's file->f_op
  with a kmalloc()ed version, that would only allow releases.

  us428control starts exiting

  __fput is called with struct file for /dev/hwC1D0.

  snd_card_file_remove() is called, alsa notices struct file
  for /dev/hwC1D0 is about to be closed.
  with patch below, file->f_op would be set NULL now.

  snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
  file->f_ops, those that would only allow releases.

  for reason I would like to know,
  __fput is called again with struct file for /dev/hwC1D0
  from us428control's do_exit().
  __fput see's file->f_op is still set.
  Without patch and under memory pressure, file->f_op can
  point to anything now.


Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>


diff -pur ../alsa/1.0.13/alsa-driver-1.0.13rc3/alsa-kernel/core/init.c rt4-kw/sound/core/init.c
--- ../alsa/1.0.13/alsa-driver-1.0.13rc3/alsa-kernel/core/init.c	2006-09-25 15:33:19.000000000 +0200
+++ rt4-kw/sound/core/init.c	2006-09-28 18:48:15.000000000 +0200
@@ -707,6 +707,8 @@ int snd_card_file_remove(struct snd_card
 	mfile = card->files;
 	while (mfile) {
 		if (mfile->file == file) {
+			fops_put(file->f_op);
+			file->f_op = NULL;
 			if (pfile)
 				pfile->next = mfile->next;
 			else

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-09-28 20:28 ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-09-28 20:28 UTC (permalink / raw)
  To: linux-kernel, Takashi Iwai; +Cc: mingo, alsa-devel

Hi

It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
but its not. bug showed again reliably under memory-pressure.

      Karsten

===

Reset file->f_op in snd_card_file_remove(). Take 2


i think what happens here is:

  us428control runs, kernel has allocated a struct file for /dev/hwC1D0.

  usb disconnect

  snd_usb_usx2y calls snd_card_disconnect,
  tells us428control to exit.

  snd_card_disconnect replaces /dev/hwC1D0's file->f_op
  with a kmalloc()ed version, that would only allow releases.

  us428control starts exiting

  __fput is called with struct file for /dev/hwC1D0.

  snd_card_file_remove() is called, alsa notices struct file
  for /dev/hwC1D0 is about to be closed.
  with patch below, file->f_op would be set NULL now.

  snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
  file->f_ops, those that would only allow releases.

  for reason I would like to know,
  __fput is called again with struct file for /dev/hwC1D0
  from us428control's do_exit().
  __fput see's file->f_op is still set.
  Without patch and under memory pressure, file->f_op can
  point to anything now.


Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>


diff -pur ../alsa/1.0.13/alsa-driver-1.0.13rc3/alsa-kernel/core/init.c rt4-kw/sound/core/init.c
--- ../alsa/1.0.13/alsa-driver-1.0.13rc3/alsa-kernel/core/init.c	2006-09-25 15:33:19.000000000 +0200
+++ rt4-kw/sound/core/init.c	2006-09-28 18:48:15.000000000 +0200
@@ -707,6 +707,8 @@ int snd_card_file_remove(struct snd_card
 	mfile = card->files;
 	while (mfile) {
 		if (mfile->file == file) {
+			fops_put(file->f_op);
+			file->f_op = NULL;
 			if (pfile)
 				pfile->next = mfile->next;
 			else

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-09-28 20:28 ` Karsten Wiese
@ 2006-09-29 10:48   ` Takashi Iwai
  -1 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-09-29 10:48 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: mingo, alsa-devel, linux-kernel

At Thu, 28 Sep 2006 22:28:02 +0200,
Karsten Wiese wrote:
> 
> Hi
> 
> It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> but its not. bug showed again reliably under memory-pressure.
> 
>       Karsten
> 
> ===
> 
> Reset file->f_op in snd_card_file_remove(). Take 2
> 
> 
> i think what happens here is:
> 
>   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> 
>   usb disconnect
> 
>   snd_usb_usx2y calls snd_card_disconnect,
>   tells us428control to exit.
> 
>   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
>   with a kmalloc()ed version, that would only allow releases.
> 
>   us428control starts exiting
> 
>   __fput is called with struct file for /dev/hwC1D0.
> 
>   snd_card_file_remove() is called, alsa notices struct file
>   for /dev/hwC1D0 is about to be closed.
>   with patch below, file->f_op would be set NULL now.
> 
>   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
>   file->f_ops, those that would only allow releases.
> 
>   for reason I would like to know,
>   __fput is called again with struct file for /dev/hwC1D0
>   from us428control's do_exit().
>   __fput see's file->f_op is still set.
>   Without patch and under memory pressure, file->f_op can
>   point to anything now.
> 
> 
> Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>

I guess this bug is fixed by Florin's patch below, juding from your
explanation.  Could you check it?


Takashi

Subject: [PATCH] Dereference after free in snd_hwdep_release()
From: Florin Malita <fmalita@gmail.com>
Date: Thu, 28 Sep 2006 19:45:50 -0400

snd_card_file_remove() may free hw->card so we can't dereference
hw->card->module after that.

Coverity ID 1420.

Signed-off-by: Florin Malita <fmalita@gmail.com>
---

diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 9aa9d94..46b4768 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -158,6 +158,7 @@ static int snd_hwdep_release(struct inod
 {
 	int err = -ENXIO;
 	struct snd_hwdep *hw = file->private_data;
+	struct module *mod = hw->card->module;
 	mutex_lock(&hw->open_mutex);
 	if (hw->ops.release) {
 		err = hw->ops.release(hw, file);
@@ -167,7 +168,7 @@ static int snd_hwdep_release(struct inod
 		hw->used--;
 	snd_card_file_remove(hw->card, file);
 	mutex_unlock(&hw->open_mutex);
-	module_put(hw->card->module);
+	module_put(mod);
 	return err;
 }
 

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-09-29 10:48   ` Takashi Iwai
  0 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-09-29 10:48 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: linux-kernel, mingo, alsa-devel

At Thu, 28 Sep 2006 22:28:02 +0200,
Karsten Wiese wrote:
> 
> Hi
> 
> It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> but its not. bug showed again reliably under memory-pressure.
> 
>       Karsten
> 
> ===
> 
> Reset file->f_op in snd_card_file_remove(). Take 2
> 
> 
> i think what happens here is:
> 
>   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> 
>   usb disconnect
> 
>   snd_usb_usx2y calls snd_card_disconnect,
>   tells us428control to exit.
> 
>   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
>   with a kmalloc()ed version, that would only allow releases.
> 
>   us428control starts exiting
> 
>   __fput is called with struct file for /dev/hwC1D0.
> 
>   snd_card_file_remove() is called, alsa notices struct file
>   for /dev/hwC1D0 is about to be closed.
>   with patch below, file->f_op would be set NULL now.
> 
>   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
>   file->f_ops, those that would only allow releases.
> 
>   for reason I would like to know,
>   __fput is called again with struct file for /dev/hwC1D0
>   from us428control's do_exit().
>   __fput see's file->f_op is still set.
>   Without patch and under memory pressure, file->f_op can
>   point to anything now.
> 
> 
> Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>

I guess this bug is fixed by Florin's patch below, juding from your
explanation.  Could you check it?


Takashi

Subject: [PATCH] Dereference after free in snd_hwdep_release()
From: Florin Malita <fmalita@gmail.com>
Date: Thu, 28 Sep 2006 19:45:50 -0400

snd_card_file_remove() may free hw->card so we can't dereference
hw->card->module after that.

Coverity ID 1420.

Signed-off-by: Florin Malita <fmalita@gmail.com>
---

diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 9aa9d94..46b4768 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -158,6 +158,7 @@ static int snd_hwdep_release(struct inod
 {
 	int err = -ENXIO;
 	struct snd_hwdep *hw = file->private_data;
+	struct module *mod = hw->card->module;
 	mutex_lock(&hw->open_mutex);
 	if (hw->ops.release) {
 		err = hw->ops.release(hw, file);
@@ -167,7 +168,7 @@ static int snd_hwdep_release(struct inod
 		hw->used--;
 	snd_card_file_remove(hw->card, file);
 	mutex_unlock(&hw->open_mutex);
-	module_put(hw->card->module);
+	module_put(mod);
 	return err;
 }
 

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-09-29 12:29     ` Karsten Wiese
  (?)
@ 2006-09-29 12:26     ` Ingo Molnar
  -1 siblings, 0 replies; 31+ messages in thread
From: Ingo Molnar @ 2006-09-29 12:26 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: Takashi Iwai, linux-kernel, alsa-devel


* Karsten Wiese <annabellesgarden@yahoo.de> wrote:

> Florin's patch fixes it.

great - i've applied Florin's patch to -rt.

	Ingo

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-09-29 10:48   ` Takashi Iwai
@ 2006-09-29 12:29     ` Karsten Wiese
  -1 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-09-29 12:29 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: mingo, alsa-devel, linux-kernel

Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> At Thu, 28 Sep 2006 22:28:02 +0200,
> Karsten Wiese wrote:
> > 
> > Hi
> > 
> > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > but its not. bug showed again reliably under memory-pressure.
> > 
> >       Karsten
> > 
> > ===
> > 
> > Reset file->f_op in snd_card_file_remove(). Take 2
> > 
> > 
> > i think what happens here is:
> > 
> >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > 
> >   usb disconnect
> > 
> >   snd_usb_usx2y calls snd_card_disconnect,
> >   tells us428control to exit.
> > 
> >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> >   with a kmalloc()ed version, that would only allow releases.
> > 
> >   us428control starts exiting
> > 
> >   __fput is called with struct file for /dev/hwC1D0.
> > 
> >   snd_card_file_remove() is called, alsa notices struct file
> >   for /dev/hwC1D0 is about to be closed.
> >   with patch below, file->f_op would be set NULL now.
> > 
> >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> >   file->f_ops, those that would only allow releases.
> > 
> >   for reason I would like to know,
> >   __fput is called again with struct file for /dev/hwC1D0
> >   from us428control's do_exit().
> >   __fput see's file->f_op is still set.
> >   Without patch and under memory pressure, file->f_op can
> >   point to anything now.
> > 
> > 
> > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> 
> I guess this bug is fixed by Florin's patch below, juding from your
> explanation.  Could you check it?
> 
Florin's patch fixes it.

This one for immediate consumation by mainline, mm, rt,
and the stable teams, hmm?

      Karsten
> 
> Takashi
> 
> Subject: [PATCH] Dereference after free in snd_hwdep_release()
> From: Florin Malita <fmalita@gmail.com>
> Date: Thu, 28 Sep 2006 19:45:50 -0400
> 
> snd_card_file_remove() may free hw->card so we can't dereference
> hw->card->module after that.
> 
> Coverity ID 1420.
> 
> Signed-off-by: Florin Malita <fmalita@gmail.com>
> ---
> 
> diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
> index 9aa9d94..46b4768 100644
> --- a/sound/core/hwdep.c
> +++ b/sound/core/hwdep.c
> @@ -158,6 +158,7 @@ static int snd_hwdep_release(struct inod
>  {
>  	int err = -ENXIO;
>  	struct snd_hwdep *hw = file->private_data;
> +	struct module *mod = hw->card->module;
>  	mutex_lock(&hw->open_mutex);
>  	if (hw->ops.release) {
>  		err = hw->ops.release(hw, file);
> @@ -167,7 +168,7 @@ static int snd_hwdep_release(struct inod
>  		hw->used--;
>  	snd_card_file_remove(hw->card, file);
>  	mutex_unlock(&hw->open_mutex);
> -	module_put(hw->card->module);
> +	module_put(mod);
>  	return err;
>  }
>  
> 
> 

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-09-29 12:29     ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-09-29 12:29 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: linux-kernel, mingo, alsa-devel

Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> At Thu, 28 Sep 2006 22:28:02 +0200,
> Karsten Wiese wrote:
> > 
> > Hi
> > 
> > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > but its not. bug showed again reliably under memory-pressure.
> > 
> >       Karsten
> > 
> > ===
> > 
> > Reset file->f_op in snd_card_file_remove(). Take 2
> > 
> > 
> > i think what happens here is:
> > 
> >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > 
> >   usb disconnect
> > 
> >   snd_usb_usx2y calls snd_card_disconnect,
> >   tells us428control to exit.
> > 
> >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> >   with a kmalloc()ed version, that would only allow releases.
> > 
> >   us428control starts exiting
> > 
> >   __fput is called with struct file for /dev/hwC1D0.
> > 
> >   snd_card_file_remove() is called, alsa notices struct file
> >   for /dev/hwC1D0 is about to be closed.
> >   with patch below, file->f_op would be set NULL now.
> > 
> >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> >   file->f_ops, those that would only allow releases.
> > 
> >   for reason I would like to know,
> >   __fput is called again with struct file for /dev/hwC1D0
> >   from us428control's do_exit().
> >   __fput see's file->f_op is still set.
> >   Without patch and under memory pressure, file->f_op can
> >   point to anything now.
> > 
> > 
> > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> 
> I guess this bug is fixed by Florin's patch below, juding from your
> explanation.  Could you check it?
> 
Florin's patch fixes it.

This one for immediate consumation by mainline, mm, rt,
and the stable teams, hmm?

      Karsten
> 
> Takashi
> 
> Subject: [PATCH] Dereference after free in snd_hwdep_release()
> From: Florin Malita <fmalita@gmail.com>
> Date: Thu, 28 Sep 2006 19:45:50 -0400
> 
> snd_card_file_remove() may free hw->card so we can't dereference
> hw->card->module after that.
> 
> Coverity ID 1420.
> 
> Signed-off-by: Florin Malita <fmalita@gmail.com>
> ---
> 
> diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
> index 9aa9d94..46b4768 100644
> --- a/sound/core/hwdep.c
> +++ b/sound/core/hwdep.c
> @@ -158,6 +158,7 @@ static int snd_hwdep_release(struct inod
>  {
>  	int err = -ENXIO;
>  	struct snd_hwdep *hw = file->private_data;
> +	struct module *mod = hw->card->module;
>  	mutex_lock(&hw->open_mutex);
>  	if (hw->ops.release) {
>  		err = hw->ops.release(hw, file);
> @@ -167,7 +168,7 @@ static int snd_hwdep_release(struct inod
>  		hw->used--;
>  	snd_card_file_remove(hw->card, file);
>  	mutex_unlock(&hw->open_mutex);
> -	module_put(hw->card->module);
> +	module_put(mod);
>  	return err;
>  }
>  
> 
> 

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-09-29 12:29     ` Karsten Wiese
@ 2006-09-29 12:45       ` Takashi Iwai
  -1 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-09-29 12:45 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: mingo, alsa-devel, linux-kernel

At Fri, 29 Sep 2006 14:29:20 +0200,
Karsten Wiese wrote:
> 
> Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> > At Thu, 28 Sep 2006 22:28:02 +0200,
> > Karsten Wiese wrote:
> > > 
> > > Hi
> > > 
> > > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > > but its not. bug showed again reliably under memory-pressure.
> > > 
> > >       Karsten
> > > 
> > > ===
> > > 
> > > Reset file->f_op in snd_card_file_remove(). Take 2
> > > 
> > > 
> > > i think what happens here is:
> > > 
> > >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > > 
> > >   usb disconnect
> > > 
> > >   snd_usb_usx2y calls snd_card_disconnect,
> > >   tells us428control to exit.
> > > 
> > >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> > >   with a kmalloc()ed version, that would only allow releases.
> > > 
> > >   us428control starts exiting
> > > 
> > >   __fput is called with struct file for /dev/hwC1D0.
> > > 
> > >   snd_card_file_remove() is called, alsa notices struct file
> > >   for /dev/hwC1D0 is about to be closed.
> > >   with patch below, file->f_op would be set NULL now.
> > > 
> > >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> > >   file->f_ops, those that would only allow releases.
> > > 
> > >   for reason I would like to know,
> > >   __fput is called again with struct file for /dev/hwC1D0
> > >   from us428control's do_exit().
> > >   __fput see's file->f_op is still set.
> > >   Without patch and under memory pressure, file->f_op can
> > >   point to anything now.
> > > 
> > > 
> > > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> > 
> > I guess this bug is fixed by Florin's patch below, juding from your
> > explanation.  Could you check it?
> > 
> Florin's patch fixes it.
> 
> This one for immediate consumation by mainline, mm, rt,
> and the stable teams, hmm?

It'll be pushed to mainline soon together with other ALSA fixes.  Then
I'll forward to stable, too.


Takashi

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-09-29 12:45       ` Takashi Iwai
  0 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-09-29 12:45 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: linux-kernel, mingo, alsa-devel

At Fri, 29 Sep 2006 14:29:20 +0200,
Karsten Wiese wrote:
> 
> Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> > At Thu, 28 Sep 2006 22:28:02 +0200,
> > Karsten Wiese wrote:
> > > 
> > > Hi
> > > 
> > > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > > but its not. bug showed again reliably under memory-pressure.
> > > 
> > >       Karsten
> > > 
> > > ===
> > > 
> > > Reset file->f_op in snd_card_file_remove(). Take 2
> > > 
> > > 
> > > i think what happens here is:
> > > 
> > >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > > 
> > >   usb disconnect
> > > 
> > >   snd_usb_usx2y calls snd_card_disconnect,
> > >   tells us428control to exit.
> > > 
> > >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> > >   with a kmalloc()ed version, that would only allow releases.
> > > 
> > >   us428control starts exiting
> > > 
> > >   __fput is called with struct file for /dev/hwC1D0.
> > > 
> > >   snd_card_file_remove() is called, alsa notices struct file
> > >   for /dev/hwC1D0 is about to be closed.
> > >   with patch below, file->f_op would be set NULL now.
> > > 
> > >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> > >   file->f_ops, those that would only allow releases.
> > > 
> > >   for reason I would like to know,
> > >   __fput is called again with struct file for /dev/hwC1D0
> > >   from us428control's do_exit().
> > >   __fput see's file->f_op is still set.
> > >   Without patch and under memory pressure, file->f_op can
> > >   point to anything now.
> > > 
> > > 
> > > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> > 
> > I guess this bug is fixed by Florin's patch below, juding from your
> > explanation.  Could you check it?
> > 
> Florin's patch fixes it.
> 
> This one for immediate consumation by mainline, mm, rt,
> and the stable teams, hmm?

It'll be pushed to mainline soon together with other ALSA fixes.  Then
I'll forward to stable, too.


Takashi

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-09-29 12:45       ` Takashi Iwai
@ 2006-10-01 18:29         ` Karsten Wiese
  -1 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-01 18:29 UTC (permalink / raw)
  To: Takashi Iwai, linux-kernel, alsa-devel; +Cc: mingo

[-- Attachment #1: Type: text/plain, Size: 3114 bytes --]

Am Freitag, 29. September 2006 14:45 schrieb Takashi Iwai:
> At Fri, 29 Sep 2006 14:29:20 +0200,
> Karsten Wiese wrote:
> > 
> > Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> > > At Thu, 28 Sep 2006 22:28:02 +0200,
> > > Karsten Wiese wrote:
> > > > 
> > > > Hi
> > > > 
> > > > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > > > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > > > but its not. bug showed again reliably under memory-pressure.
> > > > 
> > > >       Karsten
> > > > 
> > > > ===
> > > > 
> > > > Reset file->f_op in snd_card_file_remove(). Take 2
> > > > 
> > > > 
> > > > i think what happens here is:
> > > > 
> > > >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > > > 
> > > >   usb disconnect
> > > > 
> > > >   snd_usb_usx2y calls snd_card_disconnect,
> > > >   tells us428control to exit.
> > > > 
> > > >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> > > >   with a kmalloc()ed version, that would only allow releases.
> > > > 
> > > >   us428control starts exiting
> > > > 
> > > >   __fput is called with struct file for /dev/hwC1D0.
> > > > 
> > > >   snd_card_file_remove() is called, alsa notices struct file
> > > >   for /dev/hwC1D0 is about to be closed.
> > > >   with patch below, file->f_op would be set NULL now.
> > > > 
> > > >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> > > >   file->f_ops, those that would only allow releases.
> > > > 
> > > >   for reason I would like to know,
> > > >   __fput is called again with struct file for /dev/hwC1D0
> > > >   from us428control's do_exit().
> > > >   __fput see's file->f_op is still set.
> > > >   Without patch and under memory pressure, file->f_op can
> > > >   point to anything now.
> > > > 
> > > > 
> > > > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> > > 
> > > I guess this bug is fixed by Florin's patch below, juding from your
> > > explanation.  Could you check it?
> > > 
> > Florin's patch fixes it.
> > 
> > This one for immediate consumation by mainline, mm, rt,
> > and the stable teams, hmm?
> 
> It'll be pushed to mainline soon together with other ALSA fixes.  Then
> I'll forward to stable, too.
> 
bug is back. Florin's patch _is_ right.
And installed, unless im getting confuzed.
To help me proove,
please consider this controll of flow:

	usb disconnect

	usX2Y_usb_disconnect() calls snd_card_free(card);

	snd_card_free waits:
		wait_event(card->shutdown_sleep, card->files == NULL);

	us428control starts exiting, closes /dev/hwC1D0, calls __fput.
	__fput calls snd_hwdep_release,
	snd_hwdep_release calls snd_card_file_remove.
	snd_card_file_remove sees lastclose is set, does
		wake_up(&card->shutdown_sleep);

lets assume, snd_card_free's thread prio is FIFO, we are on UP
and us428control' prio is not FIFO:

What keeps snd_card_free from waking up now, deleting /dev/hwC1D0's
file->f_op _before_  __fput is rescheduled,
seeing a set but freeed file->f_op?

Attached crash dmesg also has "BUG: time warp detected!", but that BUG
is propably unrelated.


      Karsten






[-- Attachment #2: crash9.bz2 --]
[-- Type: application/x-bzip2, Size: 8395 bytes --]

[-- Attachment #3: Type: text/plain, Size: 348 bytes --]

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

[-- Attachment #4: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-01 18:29         ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-01 18:29 UTC (permalink / raw)
  To: Takashi Iwai, linux-kernel, alsa-devel; +Cc: mingo

[-- Attachment #1: Type: text/plain, Size: 3114 bytes --]

Am Freitag, 29. September 2006 14:45 schrieb Takashi Iwai:
> At Fri, 29 Sep 2006 14:29:20 +0200,
> Karsten Wiese wrote:
> > 
> > Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> > > At Thu, 28 Sep 2006 22:28:02 +0200,
> > > Karsten Wiese wrote:
> > > > 
> > > > Hi
> > > > 
> > > > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > > > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > > > but its not. bug showed again reliably under memory-pressure.
> > > > 
> > > >       Karsten
> > > > 
> > > > ===
> > > > 
> > > > Reset file->f_op in snd_card_file_remove(). Take 2
> > > > 
> > > > 
> > > > i think what happens here is:
> > > > 
> > > >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > > > 
> > > >   usb disconnect
> > > > 
> > > >   snd_usb_usx2y calls snd_card_disconnect,
> > > >   tells us428control to exit.
> > > > 
> > > >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> > > >   with a kmalloc()ed version, that would only allow releases.
> > > > 
> > > >   us428control starts exiting
> > > > 
> > > >   __fput is called with struct file for /dev/hwC1D0.
> > > > 
> > > >   snd_card_file_remove() is called, alsa notices struct file
> > > >   for /dev/hwC1D0 is about to be closed.
> > > >   with patch below, file->f_op would be set NULL now.
> > > > 
> > > >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> > > >   file->f_ops, those that would only allow releases.
> > > > 
> > > >   for reason I would like to know,
> > > >   __fput is called again with struct file for /dev/hwC1D0
> > > >   from us428control's do_exit().
> > > >   __fput see's file->f_op is still set.
> > > >   Without patch and under memory pressure, file->f_op can
> > > >   point to anything now.
> > > > 
> > > > 
> > > > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> > > 
> > > I guess this bug is fixed by Florin's patch below, juding from your
> > > explanation.  Could you check it?
> > > 
> > Florin's patch fixes it.
> > 
> > This one for immediate consumation by mainline, mm, rt,
> > and the stable teams, hmm?
> 
> It'll be pushed to mainline soon together with other ALSA fixes.  Then
> I'll forward to stable, too.
> 
bug is back. Florin's patch _is_ right.
And installed, unless im getting confuzed.
To help me proove,
please consider this controll of flow:

	usb disconnect

	usX2Y_usb_disconnect() calls snd_card_free(card);

	snd_card_free waits:
		wait_event(card->shutdown_sleep, card->files == NULL);

	us428control starts exiting, closes /dev/hwC1D0, calls __fput.
	__fput calls snd_hwdep_release,
	snd_hwdep_release calls snd_card_file_remove.
	snd_card_file_remove sees lastclose is set, does
		wake_up(&card->shutdown_sleep);

lets assume, snd_card_free's thread prio is FIFO, we are on UP
and us428control' prio is not FIFO:

What keeps snd_card_free from waking up now, deleting /dev/hwC1D0's
file->f_op _before_  __fput is rescheduled,
seeing a set but freeed file->f_op?

Attached crash dmesg also has "BUG: time warp detected!", but that BUG
is propably unrelated.


      Karsten






[-- Attachment #2: crash9.bz2 --]
[-- Type: application/x-bzip2, Size: 8395 bytes --]

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-01 18:29         ` Karsten Wiese
@ 2006-10-04  9:22           ` Takashi Iwai
  -1 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-04  9:22 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: mingo, alsa-devel, linux-kernel

At Sun, 1 Oct 2006 20:29:36 +0200,
Karsten Wiese wrote:
> 
> Am Freitag, 29. September 2006 14:45 schrieb Takashi Iwai:
> > At Fri, 29 Sep 2006 14:29:20 +0200,
> > Karsten Wiese wrote:
> > > 
> > > Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> > > > At Thu, 28 Sep 2006 22:28:02 +0200,
> > > > Karsten Wiese wrote:
> > > > > 
> > > > > Hi
> > > > > 
> > > > > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > > > > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > > > > but its not. bug showed again reliably under memory-pressure.
> > > > > 
> > > > >       Karsten
> > > > > 
> > > > > ===
> > > > > 
> > > > > Reset file->f_op in snd_card_file_remove(). Take 2
> > > > > 
> > > > > 
> > > > > i think what happens here is:
> > > > > 
> > > > >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > > > > 
> > > > >   usb disconnect
> > > > > 
> > > > >   snd_usb_usx2y calls snd_card_disconnect,
> > > > >   tells us428control to exit.
> > > > > 
> > > > >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> > > > >   with a kmalloc()ed version, that would only allow releases.
> > > > > 
> > > > >   us428control starts exiting
> > > > > 
> > > > >   __fput is called with struct file for /dev/hwC1D0.
> > > > > 
> > > > >   snd_card_file_remove() is called, alsa notices struct file
> > > > >   for /dev/hwC1D0 is about to be closed.
> > > > >   with patch below, file->f_op would be set NULL now.
> > > > > 
> > > > >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> > > > >   file->f_ops, those that would only allow releases.
> > > > > 
> > > > >   for reason I would like to know,
> > > > >   __fput is called again with struct file for /dev/hwC1D0
> > > > >   from us428control's do_exit().
> > > > >   __fput see's file->f_op is still set.
> > > > >   Without patch and under memory pressure, file->f_op can
> > > > >   point to anything now.
> > > > > 
> > > > > 
> > > > > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> > > > 
> > > > I guess this bug is fixed by Florin's patch below, juding from your
> > > > explanation.  Could you check it?
> > > > 
> > > Florin's patch fixes it.
> > > 
> > > This one for immediate consumation by mainline, mm, rt,
> > > and the stable teams, hmm?
> > 
> > It'll be pushed to mainline soon together with other ALSA fixes.  Then
> > I'll forward to stable, too.
> > 
> bug is back. Florin's patch _is_ right.
> And installed, unless im getting confuzed.
> To help me proove,
> please consider this controll of flow:
> 
> 	usb disconnect
> 
> 	usX2Y_usb_disconnect() calls snd_card_free(card);

It should call snd_card_free_when_closed() instead.


Takashi

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-04  9:22           ` Takashi Iwai
  0 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-04  9:22 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: linux-kernel, alsa-devel, mingo

At Sun, 1 Oct 2006 20:29:36 +0200,
Karsten Wiese wrote:
> 
> Am Freitag, 29. September 2006 14:45 schrieb Takashi Iwai:
> > At Fri, 29 Sep 2006 14:29:20 +0200,
> > Karsten Wiese wrote:
> > > 
> > > Am Freitag, 29. September 2006 12:48 schrieb Takashi Iwai:
> > > > At Thu, 28 Sep 2006 22:28:02 +0200,
> > > > Karsten Wiese wrote:
> > > > > 
> > > > > Hi
> > > > > 
> > > > > It oopses with 2.6.18-rt4 + alsa-kernel-1.0.13rc3 now.
> > > > > I wrote before, 2.6.18-rt3 + alsa-driver-1.0.13rc3 would be ok,
> > > > > but its not. bug showed again reliably under memory-pressure.
> > > > > 
> > > > >       Karsten
> > > > > 
> > > > > ===
> > > > > 
> > > > > Reset file->f_op in snd_card_file_remove(). Take 2
> > > > > 
> > > > > 
> > > > > i think what happens here is:
> > > > > 
> > > > >   us428control runs, kernel has allocated a struct file for /dev/hwC1D0.
> > > > > 
> > > > >   usb disconnect
> > > > > 
> > > > >   snd_usb_usx2y calls snd_card_disconnect,
> > > > >   tells us428control to exit.
> > > > > 
> > > > >   snd_card_disconnect replaces /dev/hwC1D0's file->f_op
> > > > >   with a kmalloc()ed version, that would only allow releases.
> > > > > 
> > > > >   us428control starts exiting
> > > > > 
> > > > >   __fput is called with struct file for /dev/hwC1D0.
> > > > > 
> > > > >   snd_card_file_remove() is called, alsa notices struct file
> > > > >   for /dev/hwC1D0 is about to be closed.
> > > > >   with patch below, file->f_op would be set NULL now.
> > > > > 
> > > > >   snd_usb_usx2y's free()s snd_card instance and /dev/hwC1D0's
> > > > >   file->f_ops, those that would only allow releases.
> > > > > 
> > > > >   for reason I would like to know,
> > > > >   __fput is called again with struct file for /dev/hwC1D0
> > > > >   from us428control's do_exit().
> > > > >   __fput see's file->f_op is still set.
> > > > >   Without patch and under memory pressure, file->f_op can
> > > > >   point to anything now.
> > > > > 
> > > > > 
> > > > > Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de>
> > > > 
> > > > I guess this bug is fixed by Florin's patch below, juding from your
> > > > explanation.  Could you check it?
> > > > 
> > > Florin's patch fixes it.
> > > 
> > > This one for immediate consumation by mainline, mm, rt,
> > > and the stable teams, hmm?
> > 
> > It'll be pushed to mainline soon together with other ALSA fixes.  Then
> > I'll forward to stable, too.
> > 
> bug is back. Florin's patch _is_ right.
> And installed, unless im getting confuzed.
> To help me proove,
> please consider this controll of flow:
> 
> 	usb disconnect
> 
> 	usX2Y_usb_disconnect() calls snd_card_free(card);

It should call snd_card_free_when_closed() instead.


Takashi

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04  9:22           ` Takashi Iwai
  (?)
@ 2006-10-04 10:47           ` Karsten Wiese
  2006-10-04 14:18             ` Takashi Iwai
  -1 siblings, 1 reply; 31+ messages in thread
From: Karsten Wiese @ 2006-10-04 10:47 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: mingo, alsa-devel, linux-kernel

Am Mittwoch, 4. Oktober 2006 11:22 schrieb Takashi Iwai:
> 
> It should call snd_card_free_when_closed() instead.
> 
IMHO, that would just make sure that the bug happens.
Please see my annotations, starting with // in:

void fastcall __fput(struct file *file)
{
	struct dentry *dentry = file->f_dentry;
	struct vfsmount *mnt = file->f_vfsmnt;
	struct inode *inode = dentry->d_inode;

	might_sleep();

	fsnotify_close(file);
	/*
	 * The function eventpoll_release() should be the first called
	 * in the file cleanup chain.
	 */
	eventpoll_release(file);
	locks_remove_flock(file);

	if (file->f_op && file->f_op->release)
		file->f_op->release(inode, file);
// Here snd_hwdep_release() is called.
// snd_hwdep_release() calls snd_card_file_remove().
// snd_card_file_remove() sees card->free_on_last_close ist set,
// calls snd_card_do_free().
// snd_card_do_free frees file->f_op but doesn't set it NULL.
//
	security_file_free(file);
	if (unlikely(inode->i_cdev != NULL))
		cdev_put(inode->i_cdev);
	fops_put(file->f_op);
// file->f_op has already been freeed!
// fops_put(file->f_op) is likely to oops.
//
	if (file->f_mode & FMODE_WRITE)
		put_write_access(inode);
	file_kill(file);
	file->f_dentry = NULL;
	file->f_vfsmnt = NULL;
	file_free(file);
	dput(dentry);
	mntput(mnt);
}

Right or wrong?

      Karsten

	

	
		
___________________________________________________________ 
Der frühe Vogel fängt den Wurm. Hier gelangen Sie zum neuen Yahoo! Mail: http://mail.yahoo.de


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04 10:47           ` Karsten Wiese
@ 2006-10-04 14:18             ` Takashi Iwai
  2006-10-04 15:36                 ` Karsten Wiese
  0 siblings, 1 reply; 31+ messages in thread
From: Takashi Iwai @ 2006-10-04 14:18 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: linux-kernel, alsa-devel, mingo

At Wed, 4 Oct 2006 12:47:19 +0200,
Karsten Wiese wrote:
> 
> Am Mittwoch, 4. Oktober 2006 11:22 schrieb Takashi Iwai:
> > 
> > It should call snd_card_free_when_closed() instead.
> > 
> IMHO, that would just make sure that the bug happens.
> Please see my annotations, starting with // in:
> 
> void fastcall __fput(struct file *file)
> {
> 	struct dentry *dentry = file->f_dentry;
> 	struct vfsmount *mnt = file->f_vfsmnt;
> 	struct inode *inode = dentry->d_inode;
> 
> 	might_sleep();
> 
> 	fsnotify_close(file);
> 	/*
> 	 * The function eventpoll_release() should be the first called
> 	 * in the file cleanup chain.
> 	 */
> 	eventpoll_release(file);
> 	locks_remove_flock(file);
> 
> 	if (file->f_op && file->f_op->release)
> 		file->f_op->release(inode, file);
> // Here snd_hwdep_release() is called.
> // snd_hwdep_release() calls snd_card_file_remove().
> // snd_card_file_remove() sees card->free_on_last_close ist set,
> // calls snd_card_do_free().
> // snd_card_do_free frees file->f_op but doesn't set it NULL.
> //
> 	security_file_free(file);
> 	if (unlikely(inode->i_cdev != NULL))
> 		cdev_put(inode->i_cdev);
> 	fops_put(file->f_op);
> // file->f_op has already been freeed!
> // fops_put(file->f_op) is likely to oops.

Yes, this looks like an invalid access.

The problem is that we use kmalloc for allocating a dummy f_op.
IMO, the simlest solution is to use a static dummy f_op.


Takashi

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04 14:18             ` Takashi Iwai
@ 2006-10-04 15:36                 ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-04 15:36 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: mingo, alsa-devel, linux-kernel

Am Mittwoch, 4. Oktober 2006 16:18 schrieb Takashi Iwai:
> At Wed, 4 Oct 2006 12:47:19 +0200,
> Karsten Wiese wrote:
> > 
> > Am Mittwoch, 4. Oktober 2006 11:22 schrieb Takashi Iwai:
> > > 
> > > It should call snd_card_free_when_closed() instead.
> > > 
> > IMHO, that would just make sure that the bug happens.
> > Please see my annotations, starting with // in:
> > 
> > void fastcall __fput(struct file *file)
> > {
> > 	struct dentry *dentry = file->f_dentry;
> > 	struct vfsmount *mnt = file->f_vfsmnt;
> > 	struct inode *inode = dentry->d_inode;
> > 
> > 	might_sleep();
> > 
> > 	fsnotify_close(file);
> > 	/*
> > 	 * The function eventpoll_release() should be the first called
> > 	 * in the file cleanup chain.
> > 	 */
> > 	eventpoll_release(file);
> > 	locks_remove_flock(file);
> > 
> > 	if (file->f_op && file->f_op->release)
> > 		file->f_op->release(inode, file);
> > // Here snd_hwdep_release() is called.
> > // snd_hwdep_release() calls snd_card_file_remove().
> > // snd_card_file_remove() sees card->free_on_last_close ist set,
> > // calls snd_card_do_free().
> > // snd_card_do_free frees file->f_op but doesn't set it NULL.
> > //
> > 	security_file_free(file);
> > 	if (unlikely(inode->i_cdev != NULL))
> > 		cdev_put(inode->i_cdev);
> > 	fops_put(file->f_op);
> > // file->f_op has already been freeed!
> > // fops_put(file->f_op) is likely to oops.
> 
> Yes, this looks like an invalid access.
> 
> The problem is that we use kmalloc for allocating a dummy f_op.
> IMO, the simlest solution is to use a static dummy f_op.
> 
That'd take 1 static dummy f_op per snd_*_release().
I prefer the patch at the start of this thread :-)

      Karsten

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-04 15:36                 ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-04 15:36 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: linux-kernel, alsa-devel, mingo

Am Mittwoch, 4. Oktober 2006 16:18 schrieb Takashi Iwai:
> At Wed, 4 Oct 2006 12:47:19 +0200,
> Karsten Wiese wrote:
> > 
> > Am Mittwoch, 4. Oktober 2006 11:22 schrieb Takashi Iwai:
> > > 
> > > It should call snd_card_free_when_closed() instead.
> > > 
> > IMHO, that would just make sure that the bug happens.
> > Please see my annotations, starting with // in:
> > 
> > void fastcall __fput(struct file *file)
> > {
> > 	struct dentry *dentry = file->f_dentry;
> > 	struct vfsmount *mnt = file->f_vfsmnt;
> > 	struct inode *inode = dentry->d_inode;
> > 
> > 	might_sleep();
> > 
> > 	fsnotify_close(file);
> > 	/*
> > 	 * The function eventpoll_release() should be the first called
> > 	 * in the file cleanup chain.
> > 	 */
> > 	eventpoll_release(file);
> > 	locks_remove_flock(file);
> > 
> > 	if (file->f_op && file->f_op->release)
> > 		file->f_op->release(inode, file);
> > // Here snd_hwdep_release() is called.
> > // snd_hwdep_release() calls snd_card_file_remove().
> > // snd_card_file_remove() sees card->free_on_last_close ist set,
> > // calls snd_card_do_free().
> > // snd_card_do_free frees file->f_op but doesn't set it NULL.
> > //
> > 	security_file_free(file);
> > 	if (unlikely(inode->i_cdev != NULL))
> > 		cdev_put(inode->i_cdev);
> > 	fops_put(file->f_op);
> > // file->f_op has already been freeed!
> > // fops_put(file->f_op) is likely to oops.
> 
> Yes, this looks like an invalid access.
> 
> The problem is that we use kmalloc for allocating a dummy f_op.
> IMO, the simlest solution is to use a static dummy f_op.
> 
That'd take 1 static dummy f_op per snd_*_release().
I prefer the patch at the start of this thread :-)

      Karsten

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04 15:36                 ` Karsten Wiese
@ 2006-10-04 15:57                   ` Takashi Iwai
  -1 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-04 15:57 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: mingo, alsa-devel, linux-kernel

At Wed, 4 Oct 2006 17:36:37 +0200,
Karsten Wiese wrote:
> 
> Am Mittwoch, 4. Oktober 2006 16:18 schrieb Takashi Iwai:
> > At Wed, 4 Oct 2006 12:47:19 +0200,
> > Karsten Wiese wrote:
> > > 
> > > Am Mittwoch, 4. Oktober 2006 11:22 schrieb Takashi Iwai:
> > > > 
> > > > It should call snd_card_free_when_closed() instead.
> > > > 
> > > IMHO, that would just make sure that the bug happens.
> > > Please see my annotations, starting with // in:
> > > 
> > > void fastcall __fput(struct file *file)
> > > {
> > > 	struct dentry *dentry = file->f_dentry;
> > > 	struct vfsmount *mnt = file->f_vfsmnt;
> > > 	struct inode *inode = dentry->d_inode;
> > > 
> > > 	might_sleep();
> > > 
> > > 	fsnotify_close(file);
> > > 	/*
> > > 	 * The function eventpoll_release() should be the first called
> > > 	 * in the file cleanup chain.
> > > 	 */
> > > 	eventpoll_release(file);
> > > 	locks_remove_flock(file);
> > > 
> > > 	if (file->f_op && file->f_op->release)
> > > 		file->f_op->release(inode, file);
> > > // Here snd_hwdep_release() is called.
> > > // snd_hwdep_release() calls snd_card_file_remove().
> > > // snd_card_file_remove() sees card->free_on_last_close ist set,
> > > // calls snd_card_do_free().
> > > // snd_card_do_free frees file->f_op but doesn't set it NULL.
> > > //
> > > 	security_file_free(file);
> > > 	if (unlikely(inode->i_cdev != NULL))
> > > 		cdev_put(inode->i_cdev);
> > > 	fops_put(file->f_op);
> > > // file->f_op has already been freeed!
> > > // fops_put(file->f_op) is likely to oops.
> > 
> > Yes, this looks like an invalid access.
> > 
> > The problem is that we use kmalloc for allocating a dummy f_op.
> > IMO, the simlest solution is to use a static dummy f_op.
> > 
> That'd take 1 static dummy f_op per snd_*_release().

Yes, but it'll remove extra codes at the same time, too.
Well, OTOH, it requires more additions for assignment of dummy ops...

> I prefer the patch at the start of this thread :-)

I think it's not good to set NULL always there.  The NULL is necessary
only when the card is freed.  So, I prefer the patch like below.  Is
it OK?


Takashi

diff -r f38b12373137 sound/core/init.c
--- a/sound/core/init.c	Wed Oct 04 17:17:32 2006 +0200
+++ b/sound/core/init.c	Wed Oct 04 17:50:11 2006 +0200
@@ -721,8 +721,14 @@ int snd_card_file_remove(struct snd_card
 	spin_unlock(&card->files_lock);
 	if (last_close) {
 		wake_up(&card->shutdown_sleep);
-		if (card->free_on_last_close)
+		if (card->free_on_last_close) {
+			/* release and clear f_op here since the dummy f_ops will
+			 * be freed in snd_card_do_free().
+			 */
+			fops_put(file->f_op);
+			file->f_op = NULL;
 			snd_card_do_free(card);
+		}
 	}
 	if (!mfile) {
 		snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-04 15:57                   ` Takashi Iwai
  0 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-04 15:57 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: linux-kernel, alsa-devel, mingo

At Wed, 4 Oct 2006 17:36:37 +0200,
Karsten Wiese wrote:
> 
> Am Mittwoch, 4. Oktober 2006 16:18 schrieb Takashi Iwai:
> > At Wed, 4 Oct 2006 12:47:19 +0200,
> > Karsten Wiese wrote:
> > > 
> > > Am Mittwoch, 4. Oktober 2006 11:22 schrieb Takashi Iwai:
> > > > 
> > > > It should call snd_card_free_when_closed() instead.
> > > > 
> > > IMHO, that would just make sure that the bug happens.
> > > Please see my annotations, starting with // in:
> > > 
> > > void fastcall __fput(struct file *file)
> > > {
> > > 	struct dentry *dentry = file->f_dentry;
> > > 	struct vfsmount *mnt = file->f_vfsmnt;
> > > 	struct inode *inode = dentry->d_inode;
> > > 
> > > 	might_sleep();
> > > 
> > > 	fsnotify_close(file);
> > > 	/*
> > > 	 * The function eventpoll_release() should be the first called
> > > 	 * in the file cleanup chain.
> > > 	 */
> > > 	eventpoll_release(file);
> > > 	locks_remove_flock(file);
> > > 
> > > 	if (file->f_op && file->f_op->release)
> > > 		file->f_op->release(inode, file);
> > > // Here snd_hwdep_release() is called.
> > > // snd_hwdep_release() calls snd_card_file_remove().
> > > // snd_card_file_remove() sees card->free_on_last_close ist set,
> > > // calls snd_card_do_free().
> > > // snd_card_do_free frees file->f_op but doesn't set it NULL.
> > > //
> > > 	security_file_free(file);
> > > 	if (unlikely(inode->i_cdev != NULL))
> > > 		cdev_put(inode->i_cdev);
> > > 	fops_put(file->f_op);
> > > // file->f_op has already been freeed!
> > > // fops_put(file->f_op) is likely to oops.
> > 
> > Yes, this looks like an invalid access.
> > 
> > The problem is that we use kmalloc for allocating a dummy f_op.
> > IMO, the simlest solution is to use a static dummy f_op.
> > 
> That'd take 1 static dummy f_op per snd_*_release().

Yes, but it'll remove extra codes at the same time, too.
Well, OTOH, it requires more additions for assignment of dummy ops...

> I prefer the patch at the start of this thread :-)

I think it's not good to set NULL always there.  The NULL is necessary
only when the card is freed.  So, I prefer the patch like below.  Is
it OK?


Takashi

diff -r f38b12373137 sound/core/init.c
--- a/sound/core/init.c	Wed Oct 04 17:17:32 2006 +0200
+++ b/sound/core/init.c	Wed Oct 04 17:50:11 2006 +0200
@@ -721,8 +721,14 @@ int snd_card_file_remove(struct snd_card
 	spin_unlock(&card->files_lock);
 	if (last_close) {
 		wake_up(&card->shutdown_sleep);
-		if (card->free_on_last_close)
+		if (card->free_on_last_close) {
+			/* release and clear f_op here since the dummy f_ops will
+			 * be freed in snd_card_do_free().
+			 */
+			fops_put(file->f_op);
+			file->f_op = NULL;
 			snd_card_do_free(card);
+		}
 	}
 	if (!mfile) {
 		snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04 15:57                   ` Takashi Iwai
@ 2006-10-04 20:01                     ` Karsten Wiese
  -1 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-04 20:01 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: mingo, alsa-devel, linux-kernel

Am Mittwoch, 4. Oktober 2006 17:57 schrieb Takashi Iwai:
> > > 
> > > The problem is that we use kmalloc for allocating a dummy f_op.
> > > IMO, the simlest solution is to use a static dummy f_op.
> > > 
> > That'd take 1 static dummy f_op per snd_*_release().
> 
> Yes, but it'll remove extra codes at the same time, too.
> Well, OTOH, it requires more additions for assignment of dummy ops...
> 
> > I prefer the patch at the start of this thread :-)
> 
> I think it's not good to set NULL always there.  The NULL is necessary

I disagree. In snd_card_file_remove() the file has already been
released. Is file->f_op still used anywhere later on
except from __fput()'s call to fops_put(file->f_op); ?
First glance didn't show.... 

> only when the card is freed.  So, I prefer the patch like below.  Is
> it OK?
> 
IMO not:
Lets assume 2 cpus CA, CB and two processes PA, PB,
closing their file's after usb disconnect of 1 snd_card.
PA running on CA going through snd_card_file_remove() first would not
have it's file->f_op set NULL.
Now PA is back in __fput() right after the
	file->f_op->release(inode, file);
Some third process happens to be scheduled an CA.
Meanwhile PB running on CB goes through snd_card_file_remove()
and calls snd_card_do_free(card).
snd_card_do_free(card) frees PA's file->f_op.
PA is scheduled again and has a freed, non NULL file->f_op.
> 
> Takashi
> 
> diff -r f38b12373137 sound/core/init.c
> --- a/sound/core/init.c	Wed Oct 04 17:17:32 2006 +0200
> +++ b/sound/core/init.c	Wed Oct 04 17:50:11 2006 +0200
> @@ -721,8 +721,14 @@ int snd_card_file_remove(struct snd_card
>  	spin_unlock(&card->files_lock);
>  	if (last_close) {
>  		wake_up(&card->shutdown_sleep);
> -		if (card->free_on_last_close)
> +		if (card->free_on_last_close) {
> +			/* release and clear f_op here since the dummy f_ops will
> +			 * be freed in snd_card_do_free().
> +			 */
> +			fops_put(file->f_op);
> +			file->f_op = NULL;
>  			snd_card_do_free(card);
> +		}
>  	}
>  	if (!mfile) {
>  		snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
> 

How about a "disconnecting device" that can emulate a real one
for diconnect reasons?
I've sketched one here:

-------------------------------------------------------------------
/* virtual device
   hides a real device's f_ops,
   exept for release
*/

struct snd_disconnected_file {
	struct file *file;
	int (*release) (struct inode *, struct file *);
	struct snd_disconnected_file *next;
};

static struct snd_disconnected_file *disconnecting_files;
static struct file_operations snd_disconnect_f_ops;

int snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
{
	int err;
// TODO:	zmalloc and initialize struct snd_disconnected_file,
//		rechain
	return err;

	file->f_op = snd_disconnect_f_ops;
	return 0;
}

static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
				   size_t count, loff_t *offset)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
				    size_t count, loff_t *offset)
{
	return -ENODEV;
}

static int snd_disconnect_release(struct inode *inode, struct file *file)
{
	struct snd_disconnected_file * df = disconnecting_files;
	int err = 0;
	while (df)
		if (df->file == file) {
			err = df->release(inode, file);
// TODO: free df, rechain
		}
	return err;
}

static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
{
	return POLLERR | POLLNVAL;
}

static long snd_disconnect_ioctl(struct file *file,
				 unsigned int cmd, unsigned long arg)
{
	return -ENODEV;
}

static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
{
	return -ENODEV;
}

static int snd_disconnect_fasync(int fd, struct file *file, int on)
{
	return -ENODEV;
}

static struct file_operations snd_disconnect_f_ops =
{
	.owner = 	THIS_MODULE,
	.llseek =	snd_disconnect_llseek,
	.read = 	snd_disconnect_read,
	.write =	snd_disconnect_write,
	.release =	snd_disconnect_release,
	.poll =		snd_disconnect_poll,
	.ioctl =	snd_disconnect_ioctl,
	.mmap =		snd_disconnect_mmap,
	.fasync =	snd_disconnect_fasync
};

----------------------------------------

snd_card_disconnect() would call 
  int snd_disconnect_file(file,	file->f_op->release)
instead of allocating/initing the special f_ops by itself.
We'd win memory by the difference
 sizeof(struct snd_shutdown_f_ops) - sizeof(struct snd_disconnected_file)
.
And play safe.
We would need to be sure, a file->f_op's
	int (*release) (struct inode *, struct file *);
id called exactly one time during a file's life though.

      Karsten

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-04 20:01                     ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-04 20:01 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: linux-kernel, alsa-devel, mingo

Am Mittwoch, 4. Oktober 2006 17:57 schrieb Takashi Iwai:
> > > 
> > > The problem is that we use kmalloc for allocating a dummy f_op.
> > > IMO, the simlest solution is to use a static dummy f_op.
> > > 
> > That'd take 1 static dummy f_op per snd_*_release().
> 
> Yes, but it'll remove extra codes at the same time, too.
> Well, OTOH, it requires more additions for assignment of dummy ops...
> 
> > I prefer the patch at the start of this thread :-)
> 
> I think it's not good to set NULL always there.  The NULL is necessary

I disagree. In snd_card_file_remove() the file has already been
released. Is file->f_op still used anywhere later on
except from __fput()'s call to fops_put(file->f_op); ?
First glance didn't show.... 

> only when the card is freed.  So, I prefer the patch like below.  Is
> it OK?
> 
IMO not:
Lets assume 2 cpus CA, CB and two processes PA, PB,
closing their file's after usb disconnect of 1 snd_card.
PA running on CA going through snd_card_file_remove() first would not
have it's file->f_op set NULL.
Now PA is back in __fput() right after the
	file->f_op->release(inode, file);
Some third process happens to be scheduled an CA.
Meanwhile PB running on CB goes through snd_card_file_remove()
and calls snd_card_do_free(card).
snd_card_do_free(card) frees PA's file->f_op.
PA is scheduled again and has a freed, non NULL file->f_op.
> 
> Takashi
> 
> diff -r f38b12373137 sound/core/init.c
> --- a/sound/core/init.c	Wed Oct 04 17:17:32 2006 +0200
> +++ b/sound/core/init.c	Wed Oct 04 17:50:11 2006 +0200
> @@ -721,8 +721,14 @@ int snd_card_file_remove(struct snd_card
>  	spin_unlock(&card->files_lock);
>  	if (last_close) {
>  		wake_up(&card->shutdown_sleep);
> -		if (card->free_on_last_close)
> +		if (card->free_on_last_close) {
> +			/* release and clear f_op here since the dummy f_ops will
> +			 * be freed in snd_card_do_free().
> +			 */
> +			fops_put(file->f_op);
> +			file->f_op = NULL;
>  			snd_card_do_free(card);
> +		}
>  	}
>  	if (!mfile) {
>  		snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
> 

How about a "disconnecting device" that can emulate a real one
for diconnect reasons?
I've sketched one here:

-------------------------------------------------------------------
/* virtual device
   hides a real device's f_ops,
   exept for release
*/

struct snd_disconnected_file {
	struct file *file;
	int (*release) (struct inode *, struct file *);
	struct snd_disconnected_file *next;
};

static struct snd_disconnected_file *disconnecting_files;
static struct file_operations snd_disconnect_f_ops;

int snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
{
	int err;
// TODO:	zmalloc and initialize struct snd_disconnected_file,
//		rechain
	return err;

	file->f_op = snd_disconnect_f_ops;
	return 0;
}

static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
				   size_t count, loff_t *offset)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
				    size_t count, loff_t *offset)
{
	return -ENODEV;
}

static int snd_disconnect_release(struct inode *inode, struct file *file)
{
	struct snd_disconnected_file * df = disconnecting_files;
	int err = 0;
	while (df)
		if (df->file == file) {
			err = df->release(inode, file);
// TODO: free df, rechain
		}
	return err;
}

static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
{
	return POLLERR | POLLNVAL;
}

static long snd_disconnect_ioctl(struct file *file,
				 unsigned int cmd, unsigned long arg)
{
	return -ENODEV;
}

static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
{
	return -ENODEV;
}

static int snd_disconnect_fasync(int fd, struct file *file, int on)
{
	return -ENODEV;
}

static struct file_operations snd_disconnect_f_ops =
{
	.owner = 	THIS_MODULE,
	.llseek =	snd_disconnect_llseek,
	.read = 	snd_disconnect_read,
	.write =	snd_disconnect_write,
	.release =	snd_disconnect_release,
	.poll =		snd_disconnect_poll,
	.ioctl =	snd_disconnect_ioctl,
	.mmap =		snd_disconnect_mmap,
	.fasync =	snd_disconnect_fasync
};

----------------------------------------

snd_card_disconnect() would call 
  int snd_disconnect_file(file,	file->f_op->release)
instead of allocating/initing the special f_ops by itself.
We'd win memory by the difference
 sizeof(struct snd_shutdown_f_ops) - sizeof(struct snd_disconnected_file)
.
And play safe.
We would need to be sure, a file->f_op's
	int (*release) (struct inode *, struct file *);
id called exactly one time during a file's life though.

      Karsten

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04 20:01                     ` Karsten Wiese
@ 2006-10-04 20:15                       ` Takashi Iwai
  -1 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-04 20:15 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: mingo, alsa-devel, linux-kernel

At Wed, 4 Oct 2006 22:01:53 +0200,
Karsten Wiese wrote:
> 
> Am Mittwoch, 4. Oktober 2006 17:57 schrieb Takashi Iwai:
> > > > 
> > > > The problem is that we use kmalloc for allocating a dummy f_op.
> > > > IMO, the simlest solution is to use a static dummy f_op.
> > > > 
> > > That'd take 1 static dummy f_op per snd_*_release().
> > 
> > Yes, but it'll remove extra codes at the same time, too.
> > Well, OTOH, it requires more additions for assignment of dummy ops...
> > 
> > > I prefer the patch at the start of this thread :-)
> > 
> > I think it's not good to set NULL always there.  The NULL is necessary
> 
> I disagree. In snd_card_file_remove() the file has already been
> released. Is file->f_op still used anywhere later on
> except from __fput()'s call to fops_put(file->f_op); ?
> First glance didn't show.... 

But who knows that is so in near future, too?

> > only when the card is freed.  So, I prefer the patch like below.  Is
> > it OK?
> > 
> IMO not:
> Lets assume 2 cpus CA, CB and two processes PA, PB,
> closing their file's after usb disconnect of 1 snd_card.
> PA running on CA going through snd_card_file_remove() first would not
> have it's file->f_op set NULL.
> Now PA is back in __fput() right after the
> 	file->f_op->release(inode, file);
> Some third process happens to be scheduled an CA.
> Meanwhile PB running on CB goes through snd_card_file_remove()
> and calls snd_card_do_free(card).
> snd_card_do_free(card) frees PA's file->f_op.
> PA is scheduled again and has a freed, non NULL file->f_op.

Hmmm, right, this is racy.  Let's forget.

> How about a "disconnecting device" that can emulate a real one
> for diconnect reasons?
> I've sketched one here:
> 
> -------------------------------------------------------------------
> /* virtual device
>    hides a real device's f_ops,
>    exept for release
> */
> 
> struct snd_disconnected_file {
> 	struct file *file;
> 	int (*release) (struct inode *, struct file *);
> 	struct snd_disconnected_file *next;
> };
> 
> static struct snd_disconnected_file *disconnecting_files;
> static struct file_operations snd_disconnect_f_ops;
> 
> int snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
> {
> 	int err;
> // TODO:	zmalloc and initialize struct snd_disconnected_file,
> //		rechain
> 	return err;
> 
> 	file->f_op = snd_disconnect_f_ops;
> 	return 0;
> }
> 
> static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
> {
> 	return -ENODEV;
> }
> 
> static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
> 				   size_t count, loff_t *offset)
> {
> 	return -ENODEV;
> }
> 
> static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
> 				    size_t count, loff_t *offset)
> {
> 	return -ENODEV;
> }
> 
> static int snd_disconnect_release(struct inode *inode, struct file *file)
> {
> 	struct snd_disconnected_file * df = disconnecting_files;
> 	int err = 0;
> 	while (df)
> 		if (df->file == file) {
> 			err = df->release(inode, file);
> // TODO: free df, rechain
> 		}
> 	return err;
> }
> 
> static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
> {
> 	return POLLERR | POLLNVAL;
> }
> 
> static long snd_disconnect_ioctl(struct file *file,
> 				 unsigned int cmd, unsigned long arg)
> {
> 	return -ENODEV;
> }
> 
> static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
> {
> 	return -ENODEV;
> }
> 
> static int snd_disconnect_fasync(int fd, struct file *file, int on)
> {
> 	return -ENODEV;
> }
> 
> static struct file_operations snd_disconnect_f_ops =
> {
> 	.owner = 	THIS_MODULE,
> 	.llseek =	snd_disconnect_llseek,
> 	.read = 	snd_disconnect_read,
> 	.write =	snd_disconnect_write,
> 	.release =	snd_disconnect_release,
> 	.poll =		snd_disconnect_poll,
> 	.ioctl =	snd_disconnect_ioctl,
> 	.mmap =		snd_disconnect_mmap,
> 	.fasync =	snd_disconnect_fasync
> };
> 
> ----------------------------------------
> 
> snd_card_disconnect() would call 
>   int snd_disconnect_file(file,	file->f_op->release)
> instead of allocating/initing the special f_ops by itself.
> We'd win memory by the difference
>  sizeof(struct snd_shutdown_f_ops) - sizeof(struct snd_disconnected_file)
> .
> And play safe.

This looks like a good optoin.  But one thing we have to be careful
about is the module counter since the owner is different between the
old f_op and disconnect_f_op...


Takashi

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-04 20:15                       ` Takashi Iwai
  0 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-04 20:15 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: linux-kernel, alsa-devel, mingo

At Wed, 4 Oct 2006 22:01:53 +0200,
Karsten Wiese wrote:
> 
> Am Mittwoch, 4. Oktober 2006 17:57 schrieb Takashi Iwai:
> > > > 
> > > > The problem is that we use kmalloc for allocating a dummy f_op.
> > > > IMO, the simlest solution is to use a static dummy f_op.
> > > > 
> > > That'd take 1 static dummy f_op per snd_*_release().
> > 
> > Yes, but it'll remove extra codes at the same time, too.
> > Well, OTOH, it requires more additions for assignment of dummy ops...
> > 
> > > I prefer the patch at the start of this thread :-)
> > 
> > I think it's not good to set NULL always there.  The NULL is necessary
> 
> I disagree. In snd_card_file_remove() the file has already been
> released. Is file->f_op still used anywhere later on
> except from __fput()'s call to fops_put(file->f_op); ?
> First glance didn't show.... 

But who knows that is so in near future, too?

> > only when the card is freed.  So, I prefer the patch like below.  Is
> > it OK?
> > 
> IMO not:
> Lets assume 2 cpus CA, CB and two processes PA, PB,
> closing their file's after usb disconnect of 1 snd_card.
> PA running on CA going through snd_card_file_remove() first would not
> have it's file->f_op set NULL.
> Now PA is back in __fput() right after the
> 	file->f_op->release(inode, file);
> Some third process happens to be scheduled an CA.
> Meanwhile PB running on CB goes through snd_card_file_remove()
> and calls snd_card_do_free(card).
> snd_card_do_free(card) frees PA's file->f_op.
> PA is scheduled again and has a freed, non NULL file->f_op.

Hmmm, right, this is racy.  Let's forget.

> How about a "disconnecting device" that can emulate a real one
> for diconnect reasons?
> I've sketched one here:
> 
> -------------------------------------------------------------------
> /* virtual device
>    hides a real device's f_ops,
>    exept for release
> */
> 
> struct snd_disconnected_file {
> 	struct file *file;
> 	int (*release) (struct inode *, struct file *);
> 	struct snd_disconnected_file *next;
> };
> 
> static struct snd_disconnected_file *disconnecting_files;
> static struct file_operations snd_disconnect_f_ops;
> 
> int snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
> {
> 	int err;
> // TODO:	zmalloc and initialize struct snd_disconnected_file,
> //		rechain
> 	return err;
> 
> 	file->f_op = snd_disconnect_f_ops;
> 	return 0;
> }
> 
> static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
> {
> 	return -ENODEV;
> }
> 
> static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
> 				   size_t count, loff_t *offset)
> {
> 	return -ENODEV;
> }
> 
> static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
> 				    size_t count, loff_t *offset)
> {
> 	return -ENODEV;
> }
> 
> static int snd_disconnect_release(struct inode *inode, struct file *file)
> {
> 	struct snd_disconnected_file * df = disconnecting_files;
> 	int err = 0;
> 	while (df)
> 		if (df->file == file) {
> 			err = df->release(inode, file);
> // TODO: free df, rechain
> 		}
> 	return err;
> }
> 
> static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
> {
> 	return POLLERR | POLLNVAL;
> }
> 
> static long snd_disconnect_ioctl(struct file *file,
> 				 unsigned int cmd, unsigned long arg)
> {
> 	return -ENODEV;
> }
> 
> static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
> {
> 	return -ENODEV;
> }
> 
> static int snd_disconnect_fasync(int fd, struct file *file, int on)
> {
> 	return -ENODEV;
> }
> 
> static struct file_operations snd_disconnect_f_ops =
> {
> 	.owner = 	THIS_MODULE,
> 	.llseek =	snd_disconnect_llseek,
> 	.read = 	snd_disconnect_read,
> 	.write =	snd_disconnect_write,
> 	.release =	snd_disconnect_release,
> 	.poll =		snd_disconnect_poll,
> 	.ioctl =	snd_disconnect_ioctl,
> 	.mmap =		snd_disconnect_mmap,
> 	.fasync =	snd_disconnect_fasync
> };
> 
> ----------------------------------------
> 
> snd_card_disconnect() would call 
>   int snd_disconnect_file(file,	file->f_op->release)
> instead of allocating/initing the special f_ops by itself.
> We'd win memory by the difference
>  sizeof(struct snd_shutdown_f_ops) - sizeof(struct snd_disconnected_file)
> .
> And play safe.

This looks like a good optoin.  But one thing we have to be careful
about is the module counter since the owner is different between the
old f_op and disconnect_f_op...


Takashi

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04 20:15                       ` Takashi Iwai
@ 2006-10-04 23:41                         ` Karsten Wiese
  -1 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-04 23:41 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: mingo, alsa-devel, linux-kernel

Am Mittwoch, 4. Oktober 2006 22:15 schrieb Takashi Iwai:
> 
> This looks like a good optoin.  But one thing we have to be careful
> about is the module counter since the owner is different between the
> old f_op and disconnect_f_op...
> 
here is rc1, will test later.
Feel free to pick it apart ;-)

-----------------------------------------------
/* virtual device
   hides a real device's f_ops,
   except for release

 *  Copyright (c) by Karsten Wiese <fzu@wemgehoertderstaat.de>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */


#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/module.h>

struct snd_disconnected_file {
	struct file *file;
	int (*release) (struct inode *, struct file *);
	struct snd_disconnected_file *next;
};

static struct snd_disconnected_file *disconnecting_files;
static struct file_operations snd_disconnect_f_ops;
static DEFINE_MUTEX(mutex);

void snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
{
	struct snd_disconnected_file *df, **_dfs;
	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
	if (df == NULL)
		panic("Atomic allocation failed for snd_disconnected_file!");

	df->file = file;
	df->release = release;
	df->next = NULL;

	mutex_lock(&mutex);
	_dfs = &disconnecting_files;
	while (*_dfs != NULL)
		_dfs = &(*_dfs)->next;
	*_dfs = df;
	mutex_unlock(&mutex);

	{
		const struct file_operations *old_f_op = file->f_op;
		fops_get(&snd_disconnect_f_ops);
		file->f_op = &snd_disconnect_f_ops;
		fops_put(old_f_op);
	}
}
EXPORT_SYMBOL(snd_disconnect_file);

static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
				   size_t count, loff_t *offset)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
				    size_t count, loff_t *offset)
{
	return -ENODEV;
}

static int snd_disconnect_release(struct inode *inode, struct file *file)
{
	struct snd_disconnected_file *df, **_dfs, **__dfs;
	int err = 0;
	__dfs = _dfs = &disconnecting_files;

	mutex_lock(&mutex);
	while ((df = *_dfs))
		if (df->file == file) {
			*__dfs = df->next;
			break;
		} else {
			__dfs = _dfs;
			_dfs = &df->next;
		}
	mutex_unlock(&mutex);

	if (df != NULL)	{
		err = df->release(inode, file);
		kfree(df);
		return err;
	}

	panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
}

static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
{
	return POLLERR | POLLNVAL;
}

static long snd_disconnect_ioctl(struct file *file,
				 unsigned int cmd, unsigned long arg)
{
	return -ENODEV;
}

static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
{
	return -ENODEV;
}

static int snd_disconnect_fasync(int fd, struct file *file, int on)
{
	return -ENODEV;
}

static struct file_operations snd_disconnect_f_ops =
{
	.owner = 	THIS_MODULE,
	.llseek =	snd_disconnect_llseek,
	.read = 	snd_disconnect_read,
	.write =	snd_disconnect_write,
	.release =	snd_disconnect_release,
	.poll =		snd_disconnect_poll,
	.unlocked_ioctl = snd_disconnect_ioctl,
	.compat_ioctl = snd_disconnect_ioctl,
	.mmap =		snd_disconnect_mmap,
	.fasync =	snd_disconnect_fasync
};
--------------------------------------------------------

      Karsten

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-04 23:41                         ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-04 23:41 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: linux-kernel, alsa-devel, mingo

Am Mittwoch, 4. Oktober 2006 22:15 schrieb Takashi Iwai:
> 
> This looks like a good optoin.  But one thing we have to be careful
> about is the module counter since the owner is different between the
> old f_op and disconnect_f_op...
> 
here is rc1, will test later.
Feel free to pick it apart ;-)

-----------------------------------------------
/* virtual device
   hides a real device's f_ops,
   except for release

 *  Copyright (c) by Karsten Wiese <fzu@wemgehoertderstaat.de>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */


#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/module.h>

struct snd_disconnected_file {
	struct file *file;
	int (*release) (struct inode *, struct file *);
	struct snd_disconnected_file *next;
};

static struct snd_disconnected_file *disconnecting_files;
static struct file_operations snd_disconnect_f_ops;
static DEFINE_MUTEX(mutex);

void snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
{
	struct snd_disconnected_file *df, **_dfs;
	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
	if (df == NULL)
		panic("Atomic allocation failed for snd_disconnected_file!");

	df->file = file;
	df->release = release;
	df->next = NULL;

	mutex_lock(&mutex);
	_dfs = &disconnecting_files;
	while (*_dfs != NULL)
		_dfs = &(*_dfs)->next;
	*_dfs = df;
	mutex_unlock(&mutex);

	{
		const struct file_operations *old_f_op = file->f_op;
		fops_get(&snd_disconnect_f_ops);
		file->f_op = &snd_disconnect_f_ops;
		fops_put(old_f_op);
	}
}
EXPORT_SYMBOL(snd_disconnect_file);

static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
				   size_t count, loff_t *offset)
{
	return -ENODEV;
}

static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
				    size_t count, loff_t *offset)
{
	return -ENODEV;
}

static int snd_disconnect_release(struct inode *inode, struct file *file)
{
	struct snd_disconnected_file *df, **_dfs, **__dfs;
	int err = 0;
	__dfs = _dfs = &disconnecting_files;

	mutex_lock(&mutex);
	while ((df = *_dfs))
		if (df->file == file) {
			*__dfs = df->next;
			break;
		} else {
			__dfs = _dfs;
			_dfs = &df->next;
		}
	mutex_unlock(&mutex);

	if (df != NULL)	{
		err = df->release(inode, file);
		kfree(df);
		return err;
	}

	panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
}

static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
{
	return POLLERR | POLLNVAL;
}

static long snd_disconnect_ioctl(struct file *file,
				 unsigned int cmd, unsigned long arg)
{
	return -ENODEV;
}

static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
{
	return -ENODEV;
}

static int snd_disconnect_fasync(int fd, struct file *file, int on)
{
	return -ENODEV;
}

static struct file_operations snd_disconnect_f_ops =
{
	.owner = 	THIS_MODULE,
	.llseek =	snd_disconnect_llseek,
	.read = 	snd_disconnect_read,
	.write =	snd_disconnect_write,
	.release =	snd_disconnect_release,
	.poll =		snd_disconnect_poll,
	.unlocked_ioctl = snd_disconnect_ioctl,
	.compat_ioctl = snd_disconnect_ioctl,
	.mmap =		snd_disconnect_mmap,
	.fasync =	snd_disconnect_fasync
};
--------------------------------------------------------

      Karsten

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
  2006-10-04 23:41                         ` Karsten Wiese
@ 2006-10-05 10:43                           ` Takashi Iwai
  -1 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-05 10:43 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: mingo, alsa-devel, linux-kernel

At Thu, 5 Oct 2006 01:41:47 +0200,
Karsten Wiese wrote:
> 
> Am Mittwoch, 4. Oktober 2006 22:15 schrieb Takashi Iwai:
> > 
> > This looks like a good optoin.  But one thing we have to be careful
> > about is the module counter since the owner is different between the
> > old f_op and disconnect_f_op...
> > 
> here is rc1, will test later.
> Feel free to pick it apart ;-)

Any special reason to make it separate instead of patching init.c?
Most of codes (e.g. dummy callbacks) are already in init.c.

> struct snd_disconnected_file {
> 	struct file *file;
> 	int (*release) (struct inode *, struct file *);
> 	struct snd_disconnected_file *next;

We can use a standard list here.

> };
> 
> static struct snd_disconnected_file *disconnecting_files;
> static struct file_operations snd_disconnect_f_ops;
> static DEFINE_MUTEX(mutex);
> 
> void snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
> {
> 	struct snd_disconnected_file *df, **_dfs;
> 	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
> 	if (df == NULL)
> 		panic("Atomic allocation failed for snd_disconnected_file!");

IIRC, the reason that snd_card_disconnect() uses GFP_ATOMIC is that
(usb-)disconnection was atomic in the earlier time.
You're using mutex here, hence no reason to allocate with GFP_ATOMIC.

> 	df->file = file;
> 	df->release = release;
> 	df->next = NULL;
> 
> 	mutex_lock(&mutex);
> 	_dfs = &disconnecting_files;
> 	while (*_dfs != NULL)
> 		_dfs = &(*_dfs)->next;
> 	*_dfs = df;

You can add to the item to head :)  The order doesn't matter.

> 	mutex_unlock(&mutex);
> 
> 	{
> 		const struct file_operations *old_f_op = file->f_op;
> 		fops_get(&snd_disconnect_f_ops);
> 		file->f_op = &snd_disconnect_f_ops;
> 		fops_put(old_f_op);

I wonder whether the old release might be called during this
operation.  Then df won't be freed.


> static int snd_disconnect_release(struct inode *inode, struct file *file)
> {
> 	struct snd_disconnected_file *df, **_dfs, **__dfs;
> 	int err = 0;
> 	__dfs = _dfs = &disconnecting_files;
> 
> 	mutex_lock(&mutex);
> 	while ((df = *_dfs))
> 		if (df->file == file) {
> 			*__dfs = df->next;
> 			break;
> 		} else {
> 			__dfs = _dfs;
> 			_dfs = &df->next;
> 		}
> 	mutex_unlock(&mutex);

A standard list would make the code more readable (unless you use too
many underscores ;)


Thanks,

Takashi

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [Alsa-devel] [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-05 10:43                           ` Takashi Iwai
  0 siblings, 0 replies; 31+ messages in thread
From: Takashi Iwai @ 2006-10-05 10:43 UTC (permalink / raw)
  To: Karsten Wiese; +Cc: mingo, alsa-devel, linux-kernel

At Thu, 5 Oct 2006 01:41:47 +0200,
Karsten Wiese wrote:
> 
> Am Mittwoch, 4. Oktober 2006 22:15 schrieb Takashi Iwai:
> > 
> > This looks like a good optoin.  But one thing we have to be careful
> > about is the module counter since the owner is different between the
> > old f_op and disconnect_f_op...
> > 
> here is rc1, will test later.
> Feel free to pick it apart ;-)

Any special reason to make it separate instead of patching init.c?
Most of codes (e.g. dummy callbacks) are already in init.c.

> struct snd_disconnected_file {
> 	struct file *file;
> 	int (*release) (struct inode *, struct file *);
> 	struct snd_disconnected_file *next;

We can use a standard list here.

> };
> 
> static struct snd_disconnected_file *disconnecting_files;
> static struct file_operations snd_disconnect_f_ops;
> static DEFINE_MUTEX(mutex);
> 
> void snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
> {
> 	struct snd_disconnected_file *df, **_dfs;
> 	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
> 	if (df == NULL)
> 		panic("Atomic allocation failed for snd_disconnected_file!");

IIRC, the reason that snd_card_disconnect() uses GFP_ATOMIC is that
(usb-)disconnection was atomic in the earlier time.
You're using mutex here, hence no reason to allocate with GFP_ATOMIC.

> 	df->file = file;
> 	df->release = release;
> 	df->next = NULL;
> 
> 	mutex_lock(&mutex);
> 	_dfs = &disconnecting_files;
> 	while (*_dfs != NULL)
> 		_dfs = &(*_dfs)->next;
> 	*_dfs = df;

You can add to the item to head :)  The order doesn't matter.

> 	mutex_unlock(&mutex);
> 
> 	{
> 		const struct file_operations *old_f_op = file->f_op;
> 		fops_get(&snd_disconnect_f_ops);
> 		file->f_op = &snd_disconnect_f_ops;
> 		fops_put(old_f_op);

I wonder whether the old release might be called during this
operation.  Then df won't be freed.


> static int snd_disconnect_release(struct inode *inode, struct file *file)
> {
> 	struct snd_disconnected_file *df, **_dfs, **__dfs;
> 	int err = 0;
> 	__dfs = _dfs = &disconnecting_files;
> 
> 	mutex_lock(&mutex);
> 	while ((df = *_dfs))
> 		if (df->file == file) {
> 			*__dfs = df->next;
> 			break;
> 		} else {
> 			__dfs = _dfs;
> 			_dfs = &df->next;
> 		}
> 	mutex_unlock(&mutex);

A standard list would make the code more readable (unless you use too
many underscores ;)


Thanks,

Takashi

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove (). Take 2
  2006-10-05 10:43                           ` [Alsa-devel] " Takashi Iwai
@ 2006-10-05 11:33                             ` Karsten Wiese
  -1 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-05 11:33 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: mingo, alsa-devel, linux-kernel

Am Donnerstag, 5. Oktober 2006 12:43 schrieb Takashi Iwai:
> > here is rc1, will test later.
Just posted rc2 to alsa-devel, see also at the end of mail.

> > Feel free to pick it apart ;-)
> 
> Any special reason to make it separate instead of patching init.c?
> Most of codes (e.g. dummy callbacks) are already in init.c.
> 
Maybe there are other usecases for this. Then it'd be easier to move.

> > struct snd_disconnected_file {
> > 	struct file *file;
> > 	int (*release) (struct inode *, struct file *);
> > 	struct snd_disconnected_file *next;
> 
> We can use a standard list here.
struct list_head?
I thought we'd use one pointer less this way.
If there are benefits that outweight one pointer more per instance,
I'll use standard list.

> 
> > };
> > 
> > static struct snd_disconnected_file *disconnecting_files;
> > static struct file_operations snd_disconnect_f_ops;
> > static DEFINE_MUTEX(mutex);
> > 
> > void snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
> > {
> > 	struct snd_disconnected_file *df, **_dfs;
> > 	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
> > 	if (df == NULL)
> > 		panic("Atomic allocation failed for snd_disconnected_file!");
> 
> IIRC, the reason that snd_card_disconnect() uses GFP_ATOMIC is that
> (usb-)disconnection was atomic in the earlier time.
> You're using mutex here, hence no reason to allocate with GFP_ATOMIC.
Ah ok.

> 
> > 	df->file = file;
> > 	df->release = release;
> > 	df->next = NULL;
> > 
> > 	mutex_lock(&mutex);
> > 	_dfs = &disconnecting_files;
> > 	while (*_dfs != NULL)
> > 		_dfs = &(*_dfs)->next;
> > 	*_dfs = df;
> 
> You can add to the item to head :)  The order doesn't matter.
benefit here

> 
> > 	mutex_unlock(&mutex);
> > 
> > 	{
> > 		const struct file_operations *old_f_op = file->f_op;
> > 		fops_get(&snd_disconnect_f_ops);
> > 		file->f_op = &snd_disconnect_f_ops;
> > 		fops_put(old_f_op);
> 
> I wonder whether the old release might be called during this
> operation.  Then df won't be freed.
this looks better in rc2, I hope.

> 
> 
> > static int snd_disconnect_release(struct inode *inode, struct file *file)
> > {
> > 	struct snd_disconnected_file *df, **_dfs, **__dfs;
> > 	int err = 0;
> > 	__dfs = _dfs = &disconnecting_files;
> > 
> > 	mutex_lock(&mutex);
> > 	while ((df = *_dfs))
> > 		if (df->file == file) {
> > 			*__dfs = df->next;
> > 			break;
> > 		} else {
> > 			__dfs = _dfs;
> > 			_dfs = &df->next;
> > 		}
> > 	mutex_unlock(&mutex);
> 
> A standard list would make the code more readable (unless you use too
> many underscores ;)
Will post rc3 :-)

      Karsten


rc2:
-------------------------------------------------------------
snd_disconnected_file, virtual device

On response to "usb disconnect" an usb-soundcard manipulates
that snd_card's file's f_ops to only allow release
by calling this virtual device's 
   void snd_disconnect_file(struct file *file).
After release is actually called, the virtual device instance is freeed.

Signed-off-by: Karsten Wiese <fzu@wemgehoertderstaat.de>


--- alsa-kernel/core/_disconnected.c	2006-10-05 12:16:34.000000000 +0200
+++ alsa-kernel/core/disconnected.c	2006-10-05 11:47:43.000000000 +0200
@@ -0,0 +1,147 @@
+/* virtual device
+   hides a real device's f_ops,
+   exept for release
+
+ *  Copyright (c) by Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+
+struct snd_disconnected_file {
+	struct file *file;
+	const struct file_operations *f_op;
+	struct snd_disconnected_file *next;
+};
+
+static struct snd_disconnected_file *disconnecting_files;
+static struct file_operations snd_disconnect_f_ops;
+static DEFINE_MUTEX(mutex);
+
+void snd_disconnect_file(struct file *file)
+{
+	struct snd_disconnected_file *df, **_dfs;
+	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
+	if (df == NULL)
+		panic("Atomic allocation failed for snd_disconnected_file!");
+
+	df->file = file;
+	df->f_op = file->f_op;
+	df->next = NULL;
+
+	mutex_lock(&mutex);
+	_dfs = &disconnecting_files;
+	while (*_dfs != NULL)
+		_dfs = &(*_dfs)->next;
+	*_dfs = df;
+	mutex_unlock(&mutex);
+
+	fops_get(&snd_disconnect_f_ops);
+	file->f_op = &snd_disconnect_f_ops;
+	printk(KERN_INFO "%s\n", __FUNCTION__);
+}
+
+
+static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
+				   size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
+				    size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_release(struct inode *inode, struct file *file)
+{
+	struct snd_disconnected_file *df, **_dfs, **__dfs;
+	int err = 0;
+	__dfs = _dfs = &disconnecting_files;
+
+	mutex_lock(&mutex);
+	while ((df = *_dfs))
+		if (df->file == file) {
+			*__dfs = df->next;
+			break;
+		} else {
+			__dfs = _dfs;
+			_dfs = &df->next;
+		}
+	mutex_unlock(&mutex);
+
+	if (df)	{
+		err = df->f_op->release(inode, file);
+		fops_put(df->f_op);
+		kfree(df);
+		printk(KERN_INFO "%s\n", __FUNCTION__);
+		return err;
+	}
+
+	panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
+}
+
+static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
+{
+	return POLLERR | POLLNVAL;
+}
+
+static long snd_disconnect_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_fasync(int fd, struct file *file, int on)
+{
+	return -ENODEV;
+}
+
+/*
+
+ */
+
+static struct file_operations snd_disconnect_f_ops =
+{
+	.owner = 	THIS_MODULE,
+	.llseek =	snd_disconnect_llseek,
+	.read = 	snd_disconnect_read,
+	.write =	snd_disconnect_write,
+	.release =	snd_disconnect_release,
+	.poll =		snd_disconnect_poll,
+	.unlocked_ioctl = snd_disconnect_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = snd_disconnect_ioctl,
+#endif
+	.mmap =		snd_disconnect_mmap,
+	.fasync =	snd_disconnect_fasync
+};

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [Alsa-devel] [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-05 11:33                             ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-05 11:33 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: mingo, alsa-devel, linux-kernel

Am Donnerstag, 5. Oktober 2006 12:43 schrieb Takashi Iwai:
> > here is rc1, will test later.
Just posted rc2 to alsa-devel, see also at the end of mail.

> > Feel free to pick it apart ;-)
> 
> Any special reason to make it separate instead of patching init.c?
> Most of codes (e.g. dummy callbacks) are already in init.c.
> 
Maybe there are other usecases for this. Then it'd be easier to move.

> > struct snd_disconnected_file {
> > 	struct file *file;
> > 	int (*release) (struct inode *, struct file *);
> > 	struct snd_disconnected_file *next;
> 
> We can use a standard list here.
struct list_head?
I thought we'd use one pointer less this way.
If there are benefits that outweight one pointer more per instance,
I'll use standard list.

> 
> > };
> > 
> > static struct snd_disconnected_file *disconnecting_files;
> > static struct file_operations snd_disconnect_f_ops;
> > static DEFINE_MUTEX(mutex);
> > 
> > void snd_disconnect_file(struct file *file, int (*release) (struct inode *, struct file *))
> > {
> > 	struct snd_disconnected_file *df, **_dfs;
> > 	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
> > 	if (df == NULL)
> > 		panic("Atomic allocation failed for snd_disconnected_file!");
> 
> IIRC, the reason that snd_card_disconnect() uses GFP_ATOMIC is that
> (usb-)disconnection was atomic in the earlier time.
> You're using mutex here, hence no reason to allocate with GFP_ATOMIC.
Ah ok.

> 
> > 	df->file = file;
> > 	df->release = release;
> > 	df->next = NULL;
> > 
> > 	mutex_lock(&mutex);
> > 	_dfs = &disconnecting_files;
> > 	while (*_dfs != NULL)
> > 		_dfs = &(*_dfs)->next;
> > 	*_dfs = df;
> 
> You can add to the item to head :)  The order doesn't matter.
benefit here

> 
> > 	mutex_unlock(&mutex);
> > 
> > 	{
> > 		const struct file_operations *old_f_op = file->f_op;
> > 		fops_get(&snd_disconnect_f_ops);
> > 		file->f_op = &snd_disconnect_f_ops;
> > 		fops_put(old_f_op);
> 
> I wonder whether the old release might be called during this
> operation.  Then df won't be freed.
this looks better in rc2, I hope.

> 
> 
> > static int snd_disconnect_release(struct inode *inode, struct file *file)
> > {
> > 	struct snd_disconnected_file *df, **_dfs, **__dfs;
> > 	int err = 0;
> > 	__dfs = _dfs = &disconnecting_files;
> > 
> > 	mutex_lock(&mutex);
> > 	while ((df = *_dfs))
> > 		if (df->file == file) {
> > 			*__dfs = df->next;
> > 			break;
> > 		} else {
> > 			__dfs = _dfs;
> > 			_dfs = &df->next;
> > 		}
> > 	mutex_unlock(&mutex);
> 
> A standard list would make the code more readable (unless you use too
> many underscores ;)
Will post rc3 :-)

      Karsten


rc2:
-------------------------------------------------------------
snd_disconnected_file, virtual device

On response to "usb disconnect" an usb-soundcard manipulates
that snd_card's file's f_ops to only allow release
by calling this virtual device's 
   void snd_disconnect_file(struct file *file).
After release is actually called, the virtual device instance is freeed.

Signed-off-by: Karsten Wiese <fzu@wemgehoertderstaat.de>


--- alsa-kernel/core/_disconnected.c	2006-10-05 12:16:34.000000000 +0200
+++ alsa-kernel/core/disconnected.c	2006-10-05 11:47:43.000000000 +0200
@@ -0,0 +1,147 @@
+/* virtual device
+   hides a real device's f_ops,
+   exept for release
+
+ *  Copyright (c) by Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+
+struct snd_disconnected_file {
+	struct file *file;
+	const struct file_operations *f_op;
+	struct snd_disconnected_file *next;
+};
+
+static struct snd_disconnected_file *disconnecting_files;
+static struct file_operations snd_disconnect_f_ops;
+static DEFINE_MUTEX(mutex);
+
+void snd_disconnect_file(struct file *file)
+{
+	struct snd_disconnected_file *df, **_dfs;
+	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_ATOMIC);
+	if (df == NULL)
+		panic("Atomic allocation failed for snd_disconnected_file!");
+
+	df->file = file;
+	df->f_op = file->f_op;
+	df->next = NULL;
+
+	mutex_lock(&mutex);
+	_dfs = &disconnecting_files;
+	while (*_dfs != NULL)
+		_dfs = &(*_dfs)->next;
+	*_dfs = df;
+	mutex_unlock(&mutex);
+
+	fops_get(&snd_disconnect_f_ops);
+	file->f_op = &snd_disconnect_f_ops;
+	printk(KERN_INFO "%s\n", __FUNCTION__);
+}
+
+
+static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
+				   size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
+				    size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_release(struct inode *inode, struct file *file)
+{
+	struct snd_disconnected_file *df, **_dfs, **__dfs;
+	int err = 0;
+	__dfs = _dfs = &disconnecting_files;
+
+	mutex_lock(&mutex);
+	while ((df = *_dfs))
+		if (df->file == file) {
+			*__dfs = df->next;
+			break;
+		} else {
+			__dfs = _dfs;
+			_dfs = &df->next;
+		}
+	mutex_unlock(&mutex);
+
+	if (df)	{
+		err = df->f_op->release(inode, file);
+		fops_put(df->f_op);
+		kfree(df);
+		printk(KERN_INFO "%s\n", __FUNCTION__);
+		return err;
+	}
+
+	panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
+}
+
+static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
+{
+	return POLLERR | POLLNVAL;
+}
+
+static long snd_disconnect_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_fasync(int fd, struct file *file, int on)
+{
+	return -ENODEV;
+}
+
+/*
+
+ */
+
+static struct file_operations snd_disconnect_f_ops =
+{
+	.owner = 	THIS_MODULE,
+	.llseek =	snd_disconnect_llseek,
+	.read = 	snd_disconnect_read,
+	.write =	snd_disconnect_write,
+	.release =	snd_disconnect_release,
+	.poll =		snd_disconnect_poll,
+	.unlocked_ioctl = snd_disconnect_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = snd_disconnect_ioctl,
+#endif
+	.mmap =		snd_disconnect_mmap,
+	.fasync =	snd_disconnect_fasync
+};

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

* Re: [PATCH] Reset file->f_op in snd_card_file_remove (). Take 2
  2006-10-05 11:33                             ` [Alsa-devel] [PATCH] Reset file->f_op in snd_card_file_remove(). " Karsten Wiese
@ 2006-10-05 14:12                               ` Karsten Wiese
  -1 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-05 14:12 UTC (permalink / raw)
  To: Takashi Iwai, linux-kernel; +Cc: mingo, alsa-devel

here is rc3.

Anything to fix?

We've lots of things disconnectable...
Is this useful in the kernel global?

      Karsten

rc3:
---------------------------------------------------------------------------
snd_disconnected_file, virtual device

On response to "usb disconnect" an usb-soundcard manipulates
that snd_card's file's f_ops to only allow release
by calling this virtual device's 
   void snd_disconnect_file(struct file *file).
After release is actually called, the virtual device instance is freeed.

Signed-off-by: Karsten Wiese <fzu@wemgehoertderstaat.de>


--- alsa-kernel/core/_disconnected.c	2006-10-05 12:16:34.000000000 +0200
+++ alsa-kernel/core/disconnected.c	2006-10-05 15:15:06.000000000 +0200
@@ -0,0 +1,141 @@
+/* virtual device
+   hides a real device's f_ops,
+   except for release
+
+ *  Copyright (c) by Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+
+static DEFINE_MUTEX(mutex);
+static LIST_HEAD(disconnected_files);
+
+struct snd_disconnected_file {
+	struct file *file;
+	const struct file_operations *f_op;
+	struct list_head list;
+};
+
+static struct file_operations snd_disconnect_f_ops;
+
+void snd_disconnect_file(struct file *file)
+{
+	struct snd_disconnected_file *df;
+	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_KERNEL);
+	if (df == NULL)
+		panic("Atomic allocation failed for snd_disconnected_file!");
+
+	df->file = file;
+	df->f_op = file->f_op;
+
+	mutex_lock(&mutex);
+	list_add(&df->list, &disconnected_files);
+	mutex_unlock(&mutex);
+
+	fops_get(&snd_disconnect_f_ops);
+	file->f_op = &snd_disconnect_f_ops;
+	printk(KERN_INFO "%s rc3\n", __FUNCTION__);
+}
+
+
+static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
+				   size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
+				    size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_release(struct inode *inode, struct file *file)
+{
+	struct snd_disconnected_file *df = NULL;
+	struct list_head *entry;
+
+	mutex_lock(&mutex);
+	list_for_each(entry, &disconnected_files) {
+		struct snd_disconnected_file *_df;
+		_df = list_entry(entry, struct snd_disconnected_file, list);
+		if (_df->file == file) {
+			list_del(entry);
+			df = _df;
+			break;
+		}
+	}
+	mutex_unlock(&mutex);
+
+	if (likely(df != NULL))	{
+		int err = df->f_op->release(inode, file);
+		fops_put(df->f_op);
+		kfree(df);
+		printk(KERN_INFO "%s rc3\n", __FUNCTION__);
+		return err;
+	}
+
+	panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
+}
+
+static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
+{
+	return POLLERR | POLLNVAL;
+}
+
+static long snd_disconnect_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_fasync(int fd, struct file *file, int on)
+{
+	return -ENODEV;
+}
+
+static struct file_operations snd_disconnect_f_ops =
+{
+	.owner = 	THIS_MODULE,
+	.llseek =	snd_disconnect_llseek,
+	.read = 	snd_disconnect_read,
+	.write =	snd_disconnect_write,
+	.release =	snd_disconnect_release,
+	.poll =		snd_disconnect_poll,
+	.unlocked_ioctl = snd_disconnect_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = snd_disconnect_ioctl,
+#endif
+	.mmap =		snd_disconnect_mmap,
+	.fasync =	snd_disconnect_fasync
+};

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

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

* Re: [Alsa-devel] [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2
@ 2006-10-05 14:12                               ` Karsten Wiese
  0 siblings, 0 replies; 31+ messages in thread
From: Karsten Wiese @ 2006-10-05 14:12 UTC (permalink / raw)
  To: Takashi Iwai, linux-kernel; +Cc: mingo, alsa-devel

here is rc3.

Anything to fix?

We've lots of things disconnectable...
Is this useful in the kernel global?

      Karsten

rc3:
---------------------------------------------------------------------------
snd_disconnected_file, virtual device

On response to "usb disconnect" an usb-soundcard manipulates
that snd_card's file's f_ops to only allow release
by calling this virtual device's 
   void snd_disconnect_file(struct file *file).
After release is actually called, the virtual device instance is freeed.

Signed-off-by: Karsten Wiese <fzu@wemgehoertderstaat.de>


--- alsa-kernel/core/_disconnected.c	2006-10-05 12:16:34.000000000 +0200
+++ alsa-kernel/core/disconnected.c	2006-10-05 15:15:06.000000000 +0200
@@ -0,0 +1,141 @@
+/* virtual device
+   hides a real device's f_ops,
+   except for release
+
+ *  Copyright (c) by Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+
+static DEFINE_MUTEX(mutex);
+static LIST_HEAD(disconnected_files);
+
+struct snd_disconnected_file {
+	struct file *file;
+	const struct file_operations *f_op;
+	struct list_head list;
+};
+
+static struct file_operations snd_disconnect_f_ops;
+
+void snd_disconnect_file(struct file *file)
+{
+	struct snd_disconnected_file *df;
+	df = kmalloc(sizeof(struct snd_disconnected_file), GFP_KERNEL);
+	if (df == NULL)
+		panic("Atomic allocation failed for snd_disconnected_file!");
+
+	df->file = file;
+	df->f_op = file->f_op;
+
+	mutex_lock(&mutex);
+	list_add(&df->list, &disconnected_files);
+	mutex_unlock(&mutex);
+
+	fops_get(&snd_disconnect_f_ops);
+	file->f_op = &snd_disconnect_f_ops;
+	printk(KERN_INFO "%s rc3\n", __FUNCTION__);
+}
+
+
+static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
+				   size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
+				    size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_release(struct inode *inode, struct file *file)
+{
+	struct snd_disconnected_file *df = NULL;
+	struct list_head *entry;
+
+	mutex_lock(&mutex);
+	list_for_each(entry, &disconnected_files) {
+		struct snd_disconnected_file *_df;
+		_df = list_entry(entry, struct snd_disconnected_file, list);
+		if (_df->file == file) {
+			list_del(entry);
+			df = _df;
+			break;
+		}
+	}
+	mutex_unlock(&mutex);
+
+	if (likely(df != NULL))	{
+		int err = df->f_op->release(inode, file);
+		fops_put(df->f_op);
+		kfree(df);
+		printk(KERN_INFO "%s rc3\n", __FUNCTION__);
+		return err;
+	}
+
+	panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
+}
+
+static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
+{
+	return POLLERR | POLLNVAL;
+}
+
+static long snd_disconnect_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_fasync(int fd, struct file *file, int on)
+{
+	return -ENODEV;
+}
+
+static struct file_operations snd_disconnect_f_ops =
+{
+	.owner = 	THIS_MODULE,
+	.llseek =	snd_disconnect_llseek,
+	.read = 	snd_disconnect_read,
+	.write =	snd_disconnect_write,
+	.release =	snd_disconnect_release,
+	.poll =		snd_disconnect_poll,
+	.unlocked_ioctl = snd_disconnect_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = snd_disconnect_ioctl,
+#endif
+	.mmap =		snd_disconnect_mmap,
+	.fasync =	snd_disconnect_fasync
+};

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

end of thread, other threads:[~2006-10-05 14:12 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-28 20:28 [PATCH] Reset file->f_op in snd_card_file_remove(). Take 2 Karsten Wiese
2006-09-28 20:28 ` Karsten Wiese
2006-09-29 10:48 ` Takashi Iwai
2006-09-29 10:48   ` Takashi Iwai
2006-09-29 12:29   ` Karsten Wiese
2006-09-29 12:29     ` Karsten Wiese
2006-09-29 12:26     ` Ingo Molnar
2006-09-29 12:45     ` Takashi Iwai
2006-09-29 12:45       ` Takashi Iwai
2006-10-01 18:29       ` Karsten Wiese
2006-10-01 18:29         ` Karsten Wiese
2006-10-04  9:22         ` Takashi Iwai
2006-10-04  9:22           ` Takashi Iwai
2006-10-04 10:47           ` Karsten Wiese
2006-10-04 14:18             ` Takashi Iwai
2006-10-04 15:36               ` Karsten Wiese
2006-10-04 15:36                 ` Karsten Wiese
2006-10-04 15:57                 ` Takashi Iwai
2006-10-04 15:57                   ` Takashi Iwai
2006-10-04 20:01                   ` Karsten Wiese
2006-10-04 20:01                     ` Karsten Wiese
2006-10-04 20:15                     ` Takashi Iwai
2006-10-04 20:15                       ` Takashi Iwai
2006-10-04 23:41                       ` Karsten Wiese
2006-10-04 23:41                         ` Karsten Wiese
2006-10-05 10:43                         ` Takashi Iwai
2006-10-05 10:43                           ` [Alsa-devel] " Takashi Iwai
2006-10-05 11:33                           ` [PATCH] Reset file->f_op in snd_card_file_remove (). " Karsten Wiese
2006-10-05 11:33                             ` [Alsa-devel] [PATCH] Reset file->f_op in snd_card_file_remove(). " Karsten Wiese
2006-10-05 14:12                             ` [PATCH] Reset file->f_op in snd_card_file_remove (). " Karsten Wiese
2006-10-05 14:12                               ` [Alsa-devel] [PATCH] Reset file->f_op in snd_card_file_remove(). " Karsten Wiese

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.