linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] libata: fix oops with sparsemem
@ 2006-12-08 18:14 Arnd Bergmann
  2006-12-11 14:02 ` [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE Tejun Heo
  0 siblings, 1 reply; 7+ messages in thread
From: Arnd Bergmann @ 2006-12-08 18:14 UTC (permalink / raw)
  To: jgarzik; +Cc: linux-ide, linux-kernel, linuxppc-dev

libata incorrectly passes NULL arguments to sg_set_buf, which
crashes on powerpc64 when looking for the corresponding mem_section.

This introduces a new ata_exec_nodma() wrapper that takes no buffer
arguments and does not call sg_set_buf either. In order to make it
easier to detect this sort of problem, it also adds a WARN_ON(!buf)
to sg_set_buf() so we get a log message even platforms without
sparsemem.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

Index: linux-2.6/drivers/ata/libata-core.c
===================================================================
--- linux-2.6.orig/drivers/ata/libata-core.c
+++ linux-2.6/drivers/ata/libata-core.c
@@ -1332,7 +1332,7 @@ unsigned ata_exec_internal_sg(struct ata
 }
 
 /**
- *	ata_exec_internal_sg - execute libata internal command
+ *	ata_exec_internal - execute libata internal command
  *	@dev: Device to which the command is sent
  *	@tf: Taskfile registers for the command and the result
  *	@cdb: CDB for packet command
@@ -1361,6 +1361,25 @@ unsigned ata_exec_internal(struct ata_de
 }
 
 /**
+ *	ata_exec_nodma - execute libata internal command
+ *	@dev: Device to which the command is sent
+ *	@tf: Taskfile registers for the command and the result
+ *
+ *	Wrapper around ata_exec_internal_sg() which takes no
+ *	data buffer.
+ *
+ *	LOCKING:
+ *	None.  Should be called with kernel context, might sleep.
+ *
+ *	RETURNS:
+ *	Zero on success, AC_ERR_* mask on failure
+ */
+static unsigned ata_exec_nodma(struct ata_device *dev, struct ata_taskfile *tf)
+{
+	return ata_exec_internal_sg(dev, tf, NULL, DMA_NONE, NULL, 0);
+}
+
+/**
  *	ata_do_simple_cmd - execute simple internal command
  *	@dev: Device to which the command is sent
  *	@cmd: Opcode to execute
@@ -1384,7 +1403,7 @@ unsigned int ata_do_simple_cmd(struct at
 	tf.flags |= ATA_TFLAG_DEVICE;
 	tf.protocol = ATA_PROT_NODATA;
 
-	return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	return ata_exec_nodma(dev, &tf);
 }
 
 /**
@@ -3475,7 +3494,7 @@ static unsigned int ata_dev_set_xfermode
 	tf.protocol = ATA_PROT_NODATA;
 	tf.nsect = dev->xfer_mode;
 
-	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	err_mask = ata_exec_nodma(dev, &tf);
 
 	DPRINTK("EXIT, err_mask=%x\n", err_mask);
 	return err_mask;
@@ -3513,7 +3532,7 @@ static unsigned int ata_dev_init_params(
 	tf.nsect = sectors;
 	tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
 
-	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	err_mask = ata_exec_nodma(dev, &tf);
 
 	DPRINTK("EXIT, err_mask=%x\n", err_mask);
 	return err_mask;
Index: linux-2.6/include/linux/scatterlist.h
===================================================================
--- linux-2.6.orig/include/linux/scatterlist.h
+++ linux-2.6/include/linux/scatterlist.h
@@ -8,6 +8,8 @@
 static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
 			      unsigned int buflen)
 {
+	WARN_ON(!buf); /* virt_to_page(NULL) crashes with sparsemem */
+
 	sg->page = virt_to_page(buf);
 	sg->offset = offset_in_page(buf);
 	sg->length = buflen;

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

* [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE
  2006-12-08 18:14 [PATCH] libata: fix oops with sparsemem Arnd Bergmann
@ 2006-12-11 14:02 ` Tejun Heo
  2006-12-11 14:18   ` Arnd Bergmann
                     ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Tejun Heo @ 2006-12-11 14:02 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-ide, jgarzik, linux-kernel, linuxppc-dev

Calling sg_init_one() with NULL buf causes oops on certain
configurations.  Don't initialize sg in ata_exec_internal() if
DMA_NONE and make the function complain if @buf is NULL when dma_dir
isn't DMA_NONE.  While at it, fix comment.

The problem is discovered and initial patch was submitted by Arnd
Bergmann.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---

Hello, Arnd Bergmann.

Thanks for spotting and fixing this but ata_exec_internal_nodma() is
almost identical to ata_do_simple_cmd() and ata_exec_internal() itself
needs fixing anyway.  This patch just fixes ata_exec_internal().  I'll
follow up with conversion to ata_do_simple_cmd().

Thanks.

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 011c0a8..70e02e9 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1332,7 +1332,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
 }
 
 /**
- *	ata_exec_internal_sg - execute libata internal command
+ *	ata_exec_internal - execute libata internal command
  *	@dev: Device to which the command is sent
  *	@tf: Taskfile registers for the command and the result
  *	@cdb: CDB for packet command
@@ -1354,10 +1354,15 @@ unsigned ata_exec_internal(struct ata_device *dev,
 			   int dma_dir, void *buf, unsigned int buflen)
 {
 	struct scatterlist sg;
+	unsigned int n_elem = 0;
 
-	sg_init_one(&sg, buf, buflen);
+	if (dma_dir != DMA_NONE) {
+		WARN_ON(!buf);
+		sg_init_one(&sg, buf, buflen);
+		n_elem++;
+	}
 
-	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, 1);
+	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, n_elem);
 }
 
 /**

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

* Re: [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE
  2006-12-11 14:02 ` [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE Tejun Heo
@ 2006-12-11 14:18   ` Arnd Bergmann
  2006-12-11 14:33     ` Jeff Garzik
  2006-12-11 14:23   ` Tejun Heo
  2006-12-11 15:55   ` Jeff Garzik
  2 siblings, 1 reply; 7+ messages in thread
From: Arnd Bergmann @ 2006-12-11 14:18 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-ide, Tejun Heo, jgarzik, linux-kernel

T24gTW9uZGF5IDExIERlY2VtYmVyIDIwMDYgMTU6MDIsIFRlanVuIEhlbyB3cm90ZToKPiCgewo+
IKCgoKCgoKCgc3RydWN0IHNjYXR0ZXJsaXN0IHNnOwo+ICugoKCgoKCgdW5zaWduZWQgaW50IG5f
ZWxlbSA9IDA7Cj4goAo+IC2goKCgoKCgc2dfaW5pdF9vbmUoJnNnLCBidWYsIGJ1Zmxlbik7Cj4g
K6CgoKCgoKBpZiAoZG1hX2RpciAhPSBETUFfTk9ORSkgewo+ICugoKCgoKCgoKCgoKCgoKBXQVJO
X09OKCFidWYpOwo+ICugoKCgoKCgoKCgoKCgoKBzZ19pbml0X29uZSgmc2csIGJ1ZiwgYnVmbGVu
KTsKPiAroKCgoKCgoKCgoKCgoKCgbl9lbGVtKys7Cj4gK6CgoKCgoKB9Cj4goApPaywgbG9va3Mg
Z29vZCBhcyB3ZWxsLiBJIHN0aWxsIHRoaW5rIHdlIHNob3VsZCBoYXZlIHRoZSBXQVJOX09OKCkK
aW4gc2dfc2V0X2J1ZigpLCBidXQgSSBjYW4gc2VuZCBhIHNlcGFyYXRlIHBhdGNoIGZvciB0aGF0
IHRvIGxpbnV4LW1tLgoKCUFybmQgPD48Cg==

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

* Re: [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE
  2006-12-11 14:02 ` [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE Tejun Heo
  2006-12-11 14:18   ` Arnd Bergmann
@ 2006-12-11 14:23   ` Tejun Heo
  2006-12-11 15:55   ` Jeff Garzik
  2 siblings, 0 replies; 7+ messages in thread
From: Tejun Heo @ 2006-12-11 14:23 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-ide, jgarzik, linux-kernel, linuxppc-dev

Tejun Heo wrote:
> I'll follow up with conversion to ata_do_simple_cmd().

The current situation is...

ata_exec_internal_sg()	: no user except for ata_exec_internal() yet
ata_exec_internal()	: one data transferring user. other are non-data
ata_do_simple_cmd()	: three users

So, adding another exec_internal variant doesn't look so hot.  It seems
we already have enough variants considering the small number of users.
I think it's best to leave it alone for now.

Thanks.

-- 
tejun

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

* Re: [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE
  2006-12-11 14:18   ` Arnd Bergmann
@ 2006-12-11 14:33     ` Jeff Garzik
  0 siblings, 0 replies; 7+ messages in thread
From: Jeff Garzik @ 2006-12-11 14:33 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, Tejun Heo, linux-kernel, linux-ide

Arnd Bergmann wrote:
> On Monday 11 December 2006 15:02, Tejun Heo wrote:
>>  {
>>         struct scatterlist sg;
>> +       unsigned int n_elem = 0;
>>  
>> -       sg_init_one(&sg, buf, buflen);
>> +       if (dma_dir != DMA_NONE) {
>> +               WARN_ON(!buf);
>> +               sg_init_one(&sg, buf, buflen);
>> +               n_elem++;
>> +       }
>>  
> Ok, looks good as well. I still think we should have the WARN_ON()
> in sg_set_buf(), but I can send a separate patch for that to linux-mm.

Please CC me and linux-ide on all libata patches (certainly akpm as 
well).  Andrew picks up most of the libata changes automatically via git 
from my libata-dev.git#ALL.

	Jeff

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

* Re: [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE
  2006-12-11 14:02 ` [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE Tejun Heo
  2006-12-11 14:18   ` Arnd Bergmann
  2006-12-11 14:23   ` Tejun Heo
@ 2006-12-11 15:55   ` Jeff Garzik
  2006-12-11 17:15     ` [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE (take #2) Tejun Heo
  2 siblings, 1 reply; 7+ messages in thread
From: Jeff Garzik @ 2006-12-11 15:55 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide, Arnd Bergmann, linux-kernel, linuxppc-dev

Tejun Heo wrote:
> Calling sg_init_one() with NULL buf causes oops on certain
> configurations.  Don't initialize sg in ata_exec_internal() if
> DMA_NONE and make the function complain if @buf is NULL when dma_dir
> isn't DMA_NONE.  While at it, fix comment.
> 
> The problem is discovered and initial patch was submitted by Arnd
> Bergmann.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> Cc: Arnd Bergmann <arnd.bergmann@de.ibm.com>
> ---
> 
> Hello, Arnd Bergmann.
> 
> Thanks for spotting and fixing this but ata_exec_internal_nodma() is
> almost identical to ata_do_simple_cmd() and ata_exec_internal() itself
> needs fixing anyway.  This patch just fixes ata_exec_internal().  I'll
> follow up with conversion to ata_do_simple_cmd().
> 
> Thanks.
> 
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index 011c0a8..70e02e9 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -1332,7 +1332,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
>  }
>  
>  /**
> - *	ata_exec_internal_sg - execute libata internal command
> + *	ata_exec_internal - execute libata internal command
>   *	@dev: Device to which the command is sent
>   *	@tf: Taskfile registers for the command and the result
>   *	@cdb: CDB for packet command
> @@ -1354,10 +1354,15 @@ unsigned ata_exec_internal(struct ata_device *dev,
>  			   int dma_dir, void *buf, unsigned int buflen)
>  {
>  	struct scatterlist sg;
> +	unsigned int n_elem = 0;
>  
> -	sg_init_one(&sg, buf, buflen);
> +	if (dma_dir != DMA_NONE) {
> +		WARN_ON(!buf);
> +		sg_init_one(&sg, buf, buflen);
> +		n_elem++;
> +	}
>  
> -	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, 1);
> +	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, n_elem);

ACK, if you conditionally replace "&sg" with NULL.  That's the safer 
choice, as it guarantees (via an oops) that the user will not be 
touching sg, if dma_dir==DMA_NONE.

	Jeff

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

* [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE (take #2)
  2006-12-11 15:55   ` Jeff Garzik
@ 2006-12-11 17:15     ` Tejun Heo
  0 siblings, 0 replies; 7+ messages in thread
From: Tejun Heo @ 2006-12-11 17:15 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-ide, Arnd Bergmann, linux-kernel, linuxppc-dev

Calling sg_init_one() with NULL buf causes oops on certain
configurations.  Don't initialize sg in ata_exec_internal() if
DMA_NONE and make the function complain if @buf is NULL when dma_dir
isn't DMA_NONE.  While at it, fix comment.

The problem is discovered and initial patch was submitted by Arnd
Bergmann.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---

Modified as suggested.

Thanks.

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 011c0a8..0d51d13 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1332,7 +1332,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
 }
 
 /**
- *	ata_exec_internal_sg - execute libata internal command
+ *	ata_exec_internal - execute libata internal command
  *	@dev: Device to which the command is sent
  *	@tf: Taskfile registers for the command and the result
  *	@cdb: CDB for packet command
@@ -1353,11 +1353,17 @@ unsigned ata_exec_internal(struct ata_device *dev,
 			   struct ata_taskfile *tf, const u8 *cdb,
 			   int dma_dir, void *buf, unsigned int buflen)
 {
-	struct scatterlist sg;
+	struct scatterlist *psg = NULL, sg;
+	unsigned int n_elem = 0;
 
-	sg_init_one(&sg, buf, buflen);
+	if (dma_dir != DMA_NONE) {
+		WARN_ON(!buf);
+		sg_init_one(&sg, buf, buflen);
+		psg = &sg;
+		n_elem++;
+	}
 
-	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, &sg, 1);
+	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem);
 }
 
 /**

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

end of thread, other threads:[~2006-12-11 17:15 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-08 18:14 [PATCH] libata: fix oops with sparsemem Arnd Bergmann
2006-12-11 14:02 ` [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE Tejun Heo
2006-12-11 14:18   ` Arnd Bergmann
2006-12-11 14:33     ` Jeff Garzik
2006-12-11 14:23   ` Tejun Heo
2006-12-11 15:55   ` Jeff Garzik
2006-12-11 17:15     ` [PATCH] libata: don't initialize sg in ata_exec_internal() if DMA_NONE (take #2) Tejun Heo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).