Skip to contentSkip to conversation

SCSI breakage on non-cache coherent architectures

DISCUSSION Benjamin Herrenschmidt 6 participants 25 messages Nov 19, 2007 – Nov 20, 2007

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

Hi James !

(Please CC me on replies as I'm not subscribed to linux-scsi)

I've been debugging various issues on the PowerPC 44x embedded architecture which happens to have non-coherent PCI DMA.

One of the problem I'm hitting is that one really need to enforce kmalloc alignement to cache lines or bad things will happen (among others with USB), for some reasons, powerpc failed to do so, I fixed it.

The other one I'm hitting now is that the SCSI layer nowadays embeds the sense_buffer inside the scsi_cmnd structure without any kind of alignment whatsoever. I've been hitting irregulary is a crash on SCSI command completion that seems to be related to corruption of the "request" pointer in struct scsi_cmnd and I think it might be the cause. I'm now trying to setup a proper repro-case.

The sense buffer is something that is written to by the device, thus it gets cache invalidated when the DMA happens, potentially losing whatever was sharing the cache line, which includes, among other things, that "request" pointer field.

There are other issues as well if any of the fields sharing the cache line happens to be read while the DMA is in progress, it would populate the cache with memory content prior to the DMA being completed.

It's fairly important on such architectures not to share cache lines between objects being DMA'd to/from and the rest of the system. If the DMA is strictly outgoing, it's generally ok, but not if the DMA is bidirectional or the device is writing to memory.

I'm not sure what is the best way to fix that. Internally, I've done some test whacking some ____cacheline_aligned in the scsi_cmnd data structure to verify I no longer get random SLAB corruption when using my USB but that significantly bloats the size of the structure on archs such as ppc64 that don't need it and have a large cache line size.

Unfortunately, I don't think there's any existing Kconfig symbol or arch provided #define to tell us that we are on a non-coherent arch afaik that could be used to make that conditional.

Another option would be to kmalloc the buffer (wasn't it the case before btw ?) but I suppose some people will scream at the idea due to how the command pools are done...

What do you suggest ?

Cheers,
Ben.

#1 lore raw

From: Benjamin Herrenschmidt <[email protected]>
Date: Mon, 19 Nov 2007 16:35:23 +1100

Quoted 6 lines

I'm not sure what is the best way to fix that. Internally, I've done some test whacking some ____cacheline_aligned in the scsi_cmnd data structure to verify I no longer get random SLAB corruption when using my USB but that significantly bloats the size of the structure on archs such as ppc64 that don't need it and have a large cache line size.

Quoted 7 lines

Unfortunately, I don't think there's any existing Kconfig symbol or arch provided #define to tell us that we are on a non-coherent arch afaik that could be used to make that conditional.

Another option would be to kmalloc the buffer (wasn't it the case before btw ?) but I suppose some people will scream at the idea due to how the command pools are done...

You could make a ____dma_cacheline_aligned and use that. It seems pretty reasonable.

#2 lore raw
Quoted 13 lines · David Miller

From: Benjamin Herrenschmidt <[email protected]>
Date: Mon, 19 Nov 2007 16:35:23 +1100

Quoted 10 lines

I'm not sure what is the best way to fix that. Internally, I've done some test whacking some ____cacheline_aligned in the scsi_cmnd data structure to verify I no longer get random SLAB corruption when using my USB but that significantly bloats the size of the structure on archs such as ppc64 that don't need it and have a large cache line size.

Unfortunately, I don't think there's any existing Kconfig symbol or arch provided #define to tell us that we are on a non-coherent arch afaik that could be used to make that conditional.

Quoted 6 lines
Quoted 3 lines

Another option would be to kmalloc the buffer (wasn't it the case before btw ?) but I suppose some people will scream at the idea due to how the command pools are done...

You could make a ____dma_cacheline_aligned and use that. It seems pretty reasonable.

I was thinking about that. What archs would need it ? arm, mips, what else ?

Cheers,
Ben.

#3 lore raw

From: Benjamin Herrenschmidt <[email protected]>
Date: Tue, 20 Nov 2007 06:51:14 +1100

Quoted 9 lines · David Miller
Quoted 5 lines

From: Benjamin Herrenschmidt <[email protected]>
Date: Mon, 19 Nov 2007 16:35:23 +1100

You could make a ____dma_cacheline_aligned and use that. It seems pretty reasonable.

I was thinking about that. What archs would need it ? arm, mips, what else ?

The sparc32 port would need it too.

#4 lore raw
Quoted 7 lines · David Miller

From: Benjamin Herrenschmidt <[email protected]>
Date: Tue, 20 Nov 2007 06:51:14 +1100

Quoted 4 lines · David Miller
Quoted 3 lines

From: Benjamin Herrenschmidt <[email protected]>
Date: Mon, 19 Nov 2007 16:35:23 +1100

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

You could make a ____dma_cacheline_aligned and use that. It seems pretty reasonable.

I was thinking about that. What archs would need it ? arm, mips, what else ?

The sparc32 port would need it too.

James preference seem to go for a revert of the patch that removed the kmalloc of the buffer instead. Sounds definitely like an easier plan for .24 (and maybe even backport to stable).

I'll produce a patch for that later today or tomorrow.

Do you still think we should introduce this __dma_cacheline_aligned ? Do you see other cases of drivers where it would be useful ? It tend to agree with your earlier statement that drivers doing that are broken and should be using a separate allocator for DMA'ble objects (in fact, on non-cache coherent archs, kmalloc is just fine).

Cheers,
Ben.

#5 lore raw

From: Benjamin Herrenschmidt <[email protected]>
Date: Tue, 20 Nov 2007 11:34:24 +1100

Quoted 5 lines

Do you still think we should introduce this __dma_cacheline_aligned ? Do you see other cases of drivers where it would be useful ? It tend to agree with your earlier statement that drivers doing that are broken and should be using a separate allocator for DMA'ble objects (in fact, on non-cache coherent archs, kmalloc is just fine).

I don't care either way.

If we say that the DMA api works on "DMA cacheline boundaries" (and in reality it does) we do need to either:

1) Require that entire buffers are commited by call sites, and thus "embedding" DMA'd within non-DMA stuff isn't allowed

2) Add the __dma_cacheline_aligned tag.

But note that with #2 it could get quite ugly because the alignment and size both have a minimum that needs to be enforced, not just the alignment alone. So either:

struct foo {
	unsigned int other_unrelated_stuff;

	struct object dma_thing __dma_cacheline_aligned;

	unsigned int more_nondma_stuff __dma_cacheline_aligned;
};

or:

struct foo {
	unsigned int other_unrelated_stuff;

	union {
		struct object dma_thing __dma_cacheline_aligned;
		char __pad[(sizeof(object) + DMA_CACHELINE_SIZE &
			   ~DMA_CACHELINE_SIZE)];
	} u;

	unsigned int more_nondma_stuff __dma_cacheline_aligned;
};

I hope you see what I'm trying to say.

#6 lore raw
Quoted 9 lines · David Miller

1) Require that entire buffers are commited by call sites, and thus "embedding" DMA'd within non-DMA stuff isn't allowed

2) Add the __dma_cacheline_aligned tag.

But note that with #2 it could get quite ugly because the alignment and size both have a minimum that needs to be enforced, not just the alignment alone. So either:

Yup.

Quoted 7 lines
struct foo {
        unsigned int other_unrelated_stuff;

        struct object dma_thing __dma_cacheline_aligned;

        unsigned int more_nondma_stuff __dma_cacheline_aligned;
};

In my tests, I had used a "fuckton_t" object defined to be an empty thing with alignment constraint, seemed to work :-) But I'd rather require #1.

BTW. What is the status nowadays with skb's ?

Cheers,
Ben.

#7 lore raw

From: Benjamin Herrenschmidt <[email protected]>
Date: Tue, 20 Nov 2007 11:55:01 +1100

Quoted 1 line

BTW. What is the status nowadays with skb's ?

Good question.

Some drivers are problematic (or were) because they put DMA descriptor chaining information at the head of the buffer, but those have been fixed either to use alternate descriptor ring facilities or make the proper DMA sync calls.

#8 lore raw
In reply to David Miller
Quoted 16 lines

2) Add the __dma_cacheline_aligned tag.

But note that with #2 it could get quite ugly because the alignment and size both have a minimum that needs to be enforced, not just the alignment alone. So either:

struct foo {
	unsigned int other_unrelated_stuff;

	struct object dma_thing __dma_cacheline_aligned;

	unsigned int more_nondma_stuff __dma_cacheline_aligned;
};

or:

Quoted 11 lines
struct foo {
	unsigned int other_unrelated_stuff;

	union {
		struct object dma_thing __dma_cacheline_aligned;
		char __pad[(sizeof(object) + DMA_CACHELINE_SIZE &
			   ~DMA_CACHELINE_SIZE)];
	} u;

	unsigned int more_nondma_stuff __dma_cacheline_aligned;
};

I wrapped this ugliness up inside the macro back in what I posted in 2002 (http://lkml.org/lkml/2002/6/12/234):

#define __dma_buffer __dma_buffer_line(__LINE__) #define __dma_buffer_line(line) __dma_buffer_expand_line(line)

#define __dma_buffer_expand_line(line) \
	__attribute__ ((aligned(L1_CACHE_BYTES))); \
	char __dma_pad_ ## line [0] __attribute__ ((aligned(L1_CACHE_BYTES)))

then you just need to tag the actual member like:

	char foo[3] __dma_buffer;

- R.

#9 lore raw
Quoted 6 lines · Roland Dreier

I wrapped this ugliness up inside the macro back in what I posted in 2002 (http://lkml.org/lkml/2002/6/12/234):

#define __dma_buffer __dma_buffer_line(__LINE__) #define __dma_buffer_line(line) __dma_buffer_expand_line(line)

Quoted 8 lines
#define __dma_buffer_expand_line(line) \
        __attribute__ ((aligned(L1_CACHE_BYTES))); \
        char __dma_pad_ ## line [0] __attribute__

((aligned(L1_CACHE_BYTES)))

then you just need to tag the actual member like:

        char foo[3] __dma_buffer;

That's actually not too bad ...

I'm having a problem with reverting SCSI to use an allocation for the sense buffer, because it can fail and the new scso_eh_prep_cmnd() isn't supposed to return a failure. I've changed that but now I get into trying to fix the various drivers that use it without checking the result code and it's becoming much more complicated than initially thought.

So I may do the above instead and revive your patch.

Any objection ? James ? David ?

Cheers,
Ben.

#10 lore raw
In reply to Roland Dreier

FYI, Here's what I have for the SCSI change. I haven't updated drivers to care for the new return code though, help appreciated with that as I don't know much about these drivers.

drivers/scsi/scsi_error.c +27 -5
Index: linux-work/drivers/scsi/scsi_error.c
===================================================================
@@ -602,8 +602,9 @@ static void scsi_abort_eh_cmnd(struct sc
  * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
  * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
  **/
-void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
-			unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
+int scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
+		      unsigned char *cmnd, int cmnd_size, unsigned sense_bytes,
+		      gfp_t gfp_mask)
 {
 	struct scsi_device *sdev = scmd->device;
 
@@ -622,12 +623,20 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd 
 	ses->use_sg = scmd->use_sg;
 	ses->resid = scmd->resid;
 	ses->result = scmd->result;
+	sg_init_table(&ses->sense_sgl, 1);
 
 	if (sense_bytes) {
+		struct page *pg;
+
+		if (sdev->host->hostt->unchecked_isa_dma)
+			gfp_mask |= __GFP_DMA;
 		scmd->request_bufflen = min_t(unsigned,
 		                       sizeof(scmd->sense_buffer), sense_bytes);
-		sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
-		                                       scmd->request_bufflen);
+		pg = alloc_page(gfp_mask);
+		if (!pg)
+			return FAILED;
+		memset(page_address(pg), 0, scmd->request_bufflen);
+		sg_set_page(&ses->sense_sgl, pg, scmd->request_bufflen, 0);
 		scmd->request_buffer = &ses->sense_sgl;
 		scmd->sc_data_direction = DMA_FROM_DEVICE;
 		scmd->use_sg = 1;
@@ -658,6 +667,8 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd 
 	 * untransferred sense data should be interpreted as being zero.
 	 */
 	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
+	return SUCCESS;
 }
 EXPORT_SYMBOL(scsi_eh_prep_cmnd);
 
@@ -670,9 +681,17 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd);
  **/
 void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 {
+	struct page *pg;
+
 	/*
 	 * Restore original data
 	 */
+	pg = sg_page(&ses->sense_sgl);
+	if (pg) {
+		memcpy(scmd->sense_buffer, page_address(pg),
+		       scmd->request_bufflen);
+		__free_page(pg);
+	}
 	scmd->cmd_len = ses->cmd_len;
 	memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
 	scmd->sc_data_direction = ses->data_direction;
@@ -709,7 +728,10 @@ static int scsi_send_eh_cmnd(struct scsi
 	struct scsi_eh_save ses;
 	int rtn;
 
-	scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
+	if (scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes,
+			      GFP_KERNEL) != SUCCESS)
+		return FAILED;
+
 	shost->eh_action = &done;
 
 	spin_lock_irqsave(shost->host_lock, flags);
include/scsi/scsi_eh.h +3 -2
Index: linux-work/include/scsi/scsi_eh.h
===================================================================
@@ -81,9 +81,10 @@ struct scsi_eh_save {
 	struct scatterlist sense_sgl;
 };
 
-extern void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
+extern int scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
 		struct scsi_eh_save *ses, unsigned char *cmnd,
-		int cmnd_size, unsigned sense_bytes);
+		int cmnd_size, unsigned sense_bytes,
+		gfp_t gfp_mask);
 
 extern void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
 		struct scsi_eh_save *ses);
drivers/scsi/NCR5380.c +1 -1
Index: linux-work/drivers/scsi/NCR5380.c
===================================================================
@@ -2283,7 +2283,7 @@ static void NCR5380_information_transfer
 					}
 
 					if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
-						scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+						scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0, GFP_ATOMIC);
 
 						dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no));
 
drivers/scsi/atari_NCR5380.c +1 -1
Index: linux-work/drivers/scsi/atari_NCR5380.c
===================================================================
@@ -2240,7 +2240,7 @@ static void NCR5380_information_transfer
 
 					if ((cmd->cmnd[0] != REQUEST_SENSE) &&
 					    (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
-						scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+						scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0, GFP_ATOMIC);
 
 						ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
 
drivers/scsi/sun3_NCR5380.c +1 -1
Index: linux-work/drivers/scsi/sun3_NCR5380.c
===================================================================
@@ -2261,7 +2261,7 @@ static void NCR5380_information_transfer
 
 		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
 			(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
-			scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+			scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0, GFP_ATOMIC);
 			ASEN_PRINTK("scsi%d: performing request sense\n",
 				    HOSTNO);
 			/* this is initialized from initialize_SCp 
maintainer
#11 lore raw
Quoted 3 lines · Benjamin Herrenschmidt

FYI, Here's what I have for the SCSI change. I haven't updated drivers to care for the new return code though, help appreciated with that as I don't know much about these drivers.

It looks to me like the return problem could be solved by passing in the buffer to be used for sense; that way we can allocate it in hostdata at init time for all the drivers and scsi_error can allocate and free a page using GFP_KERNEL.

James

#12 lore raw
In reply to Benjamin Herrenschmidt
Quoted 19 lines · Benjamin Herrenschmidt
Quoted 17 lines · David Miller

From: Benjamin Herrenschmidt <[email protected]>
Date: Mon, 19 Nov 2007 16:35:23 +1100

Quoted 13 lines

I'm not sure what is the best way to fix that. Internally, I've done some test whacking some ____cacheline_aligned in the scsi_cmnd data structure to verify I no longer get random SLAB corruption when using my USB but that significantly bloats the size of the structure on archs such as ppc64 that don't need it and have a large cache line size.

Unfortunately, I don't think there's any existing Kconfig symbol or arch provided #define to tell us that we are on a non-coherent arch afaik that could be used to make that conditional.

Another option would be to kmalloc the buffer (wasn't it the case before btw ?) but I suppose some people will scream at the idea due to how the command pools are done...

Quoted 5 lines
Quoted 2 lines

You could make a ____dma_cacheline_aligned and use that. It seems pretty reasonable.

I was thinking about that. What archs would need it ? arm, mips, what else ?

older parisc

Thomas.

Signature · 2 lines
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea.                                                [ RFC1925, 2.3 ]
maintainer
#13 lore raw
Quoted 20 lines · Thomas Bogendoerfer
Quoted 19 lines · Benjamin Herrenschmidt
Quoted 17 lines · David Miller

From: Benjamin Herrenschmidt <[email protected]>
Date: Mon, 19 Nov 2007 16:35:23 +1100

Quoted 13 lines

I'm not sure what is the best way to fix that. Internally, I've done some test whacking some ____cacheline_aligned in the scsi_cmnd data structure to verify I no longer get random SLAB corruption when using my USB but that significantly bloats the size of the structure on archs such as ppc64 that don't need it and have a large cache line size.

Unfortunately, I don't think there's any existing Kconfig symbol or arch provided #define to tell us that we are on a non-coherent arch afaik that could be used to make that conditional.

Another option would be to kmalloc the buffer (wasn't it the case before btw ?) but I suppose some people will scream at the idea due to how the command pools are done...

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

You could make a ____dma_cacheline_aligned and use that. It seems pretty reasonable.

I was thinking about that. What archs would need it ? arm, mips, what else ?

older parisc

Actually, we already established on IRC that the lasi700 driver doesn't need this, principally because the parisc architecture doesn't do an invalidate for DMA_FROM_DEVICE but a flush and invalidate (architecturally, if you read our manuals, even pdc is entitled to write back dirty lines, so it's not clear there's actually an invalidate
instruction we can use). This is also one possible temporary fix for
the other architectures if we can't get a different method to work nicely.

James

James

#14 lore raw
Quoted 8 lines

Actually, we already established on IRC that the lasi700 driver doesn't need this, principally because the parisc architecture doesn't do an invalidate for DMA_FROM_DEVICE but a flush and invalidate (architecturally, if you read our manuals, even pdc is entitled to write back dirty lines, so it's not clear there's actually an invalidate
instruction we can use). This is also one possible temporary fix for
the other architectures if we can't get a different method to work nicely.

I think doing a writeback and invalidate is a very fragile way to deal with DMA into the middle of a data structure. It may work OK for now, but you have to make sure forever into the future that no codepath anywhere else ever touches the cacheline that you're DMAing into while the DMA is pending. It just leaves a hidden trap that is too easy to step on, because the architectures that get pretty much all testing all have cache-coherent DMA.

Reviving my ancient __dma_buffer patch seems far preferable to me.

- R.

maintainer
#15 lore raw
Quoted 17 lines · Roland Dreier
Quoted 8 lines

Actually, we already established on IRC that the lasi700 driver doesn't need this, principally because the parisc architecture doesn't do an invalidate for DMA_FROM_DEVICE but a flush and invalidate (architecturally, if you read our manuals, even pdc is entitled to write back dirty lines, so it's not clear there's actually an invalidate
instruction we can use). This is also one possible temporary fix for
the other architectures if we can't get a different method to work nicely.

I think doing a writeback and invalidate is a very fragile way to deal with DMA into the middle of a data structure. It may work OK for now, but you have to make sure forever into the future that no codepath anywhere else ever touches the cacheline that you're DMAing into while the DMA is pending. It just leaves a hidden trap that is too easy to step on, because the architectures that get pretty much all testing all have cache-coherent DMA.

Quoted 1 line

Reviving my ancient __dma_buffer patch seems far preferable to me.

We're talking about trying to fix this for 2.4; which is already at -rc3 ... Is an entire arch change for dma alignment really a merge candidate at this stage?

James

#16 lore raw
Quoted 3 lines · James Bottomley

We're talking about trying to fix this for 2.4; which is already at -rc3 ... Is an entire arch change for dma alignment really a merge candidate at this stage?

Well, as I said before... it's a matter of what seems to be the less likely to break something right ?

On one side, I'm doing surgery on code I barely know, the scsi error handling, and now it seems I also have to fixup a handful of drivers that aren't the most obvious pieces of code around.

On the other side, Roland proposal is basically just adding a macro that can be empty for everybody but a handful of archs, and stick it onto one field in one structure...

The later has about 0 chances to actually break something or cause a regression. I wouldn't say that about the former.

Now, I will see if I manage to fixup the NCR drivers to pass a pre-allocated buffer (USB storage I think can pass NULL as it's not calling prep in atomic context). But then, it complicates the matter because that means "restore" will have to know whether prep allocated the buffer or not, thus more fields to add to the save struct, it's getting messy, unless we decide -all- callers are responsible for the buffer allocation (hrm... maybe the best approach).

Ben.

maintainer
#17 lore raw
Quoted 8 lines · Benjamin Herrenschmidt
Quoted 3 lines · James Bottomley

We're talking about trying to fix this for 2.4; which is already at -rc3 ... Is an entire arch change for dma alignment really a merge candidate at this stage?

Well, as I said before... it's a matter of what seems to be the less likely to break something right ?

Quoted 7 lines

On one side, I'm doing surgery on code I barely know, the scsi error handling, and now it seems I also have to fixup a handful of drivers that aren't the most obvious pieces of code around.

On the other side, Roland proposal is basically just adding a macro that can be empty for everybody but a handful of archs, and stick it onto one field in one structure...

Yes ... it's the getting arch owner agreement to send the patch that slightly worries me.

Quoted 10 lines

The later has about 0 chances to actually break something or cause a regression. I wouldn't say that about the former.

Now, I will see if I manage to fixup the NCR drivers to pass a pre-allocated buffer (USB storage I think can pass NULL as it's not calling prep in atomic context). But then, it complicates the matter because that means "restore" will have to know whether prep allocated the buffer or not, thus more fields to add to the save struct, it's getting messy, unless we decide -all- callers are responsible for the buffer allocation (hrm... maybe the best approach).

Sorry, yes, that's what I was thinking ... identically to the way the struct scsi_eh_save is handled ... or indeed as an extra pointer field inside scsi_eh_save.

James

#18 lore raw
In reply to Benjamin Herrenschmidt
Quoted 1 line · Benjamin Herrenschmidt

The other one I'm hitting now is that the SCSI layer nowadays embeds the

'nowadays'? It has always been so.

Quoted 5 lines

sense_buffer inside the scsi_cmnd structure without any kind of alignment whatsoever. I've been hitting irregulary is a crash on SCSI command completion that seems to be related to corruption of the "request" pointer in struct scsi_cmnd and I think it might be the cause. I'm now trying to setup a proper repro-case.

What other drivers do is DMA to their own allocation and then memcpy to the sense buffer.

There is a movement to allocate the sense data as its own sg list, but I don't think that patch has even been posted yet.

Signature · 4 lines
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."
maintainer
#19 lore raw
Quoted 11 lines · Matthew Wilcox
Quoted 1 line · Benjamin Herrenschmidt

The other one I'm hitting now is that the SCSI layer nowadays embeds the

'nowadays'? It has always been so.

Quoted 5 lines

sense_buffer inside the scsi_cmnd structure without any kind of alignment whatsoever. I've been hitting irregulary is a crash on SCSI command completion that seems to be related to corruption of the "request" pointer in struct scsi_cmnd and I think it might be the cause. I'm now trying to setup a proper repro-case.

Quoted 5 lines

What other drivers do is DMA to their own allocation and then memcpy to the sense buffer.

There is a movement to allocate the sense data as its own sg list, but I don't think that patch has even been posted yet.

I'd like to be rid of it inside the command for various reasons: every command has one of these, and they're expensive in the allocation (at 96 bytes). There's no reason we have to allocate and free that amount of space with every command. In theory, the number of these is bounded at the queue depth, in practice, there's usually only one, and this DMA alignment issue does requires most drivers to double copy.

James

#20 lore raw
Quoted 6 lines · James Bottomley
Quoted 5 lines

What other drivers do is DMA to their own allocation and then memcpy to the sense buffer.

There is a movement to allocate the sense data as its own sg list, but I don't think that patch has even been posted yet.

Quoted 6 lines

I'd like to be rid of it inside the command for various reasons: every command has one of these, and they're expensive in the allocation (at 96 bytes). There's no reason we have to allocate and free that amount of space with every command. In theory, the number of these is bounded at the queue depth, in practice, there's usually only one, and this DMA alignment issue does requires most drivers to double copy.

And most drivers don't and break. Take USB storage, I -think- (code path aren't trivial to follow) it just gets the sglist cooked up by the code in scsi_error.c no ? That just points to the buffer in scsi_cmnd. It then pass that for DMA to the USB stack.

Ben.

#21 lore raw
In reply to James Bottomley
Quoted 7 lines

I'd like to be rid of it inside the command for various reasons: every command has one of these, and they're expensive in the allocation (at 96 bytes). There's no reason we have to allocate and free that amount of space with every command. In theory, the number of these is bounded at the queue depth, in practice, there's usually only one, and this DMA alignment issue does requires most drivers to double copy.

Do you have a plan for short term here ? I'd like something fixed for .25, so I may have to introduce a __dma_aligned macro of some sort to deal with that in the meantime...

Ben.

#22 lore raw
In reply to Matthew Wilcox
Quoted 4 lines · Matthew Wilcox
Quoted 1 line · Benjamin Herrenschmidt

The other one I'm hitting now is that the SCSI layer nowadays embeds the

'nowadays'? It has always been so.

Wasn't it kmalloc'ed at one point ?

Quoted 8 lines
Quoted 5 lines

sense_buffer inside the scsi_cmnd structure without any kind of alignment whatsoever. I've been hitting irregulary is a crash on SCSI command completion that seems to be related to corruption of the "request" pointer in struct scsi_cmnd and I think it might be the cause. I'm now trying to setup a proper repro-case.

What other drivers do is DMA to their own allocation and then memcpy to the sense buffer.

What "other drivers" ? Those architectures use the same drivers as everything else.

Quoted 2 lines

There is a movement to allocate the sense data as its own sg list, but I don't think that patch has even been posted yet.

I've seen code creating an sglist from the scsi_cmnd->sense_buffer and passing that to drivers. That breaks.

Ben.

#23 lore raw
In reply to Benjamin Herrenschmidt
Quoted 6 lines

I've been debugging various issues on the PowerPC 44x embedded architecture which happens to have non-coherent PCI DMA.

One of the problem I'm hitting is that one really need to enforce kmalloc alignement to cache lines or bad things will happen (among others with USB), for some reasons, powerpc failed to do so, I fixed it.

Heh... I hit the same problem literally 5 years ago:

    http://lwn.net/Articles/1783/

I implemented the __dma_buffer annotation:

    http://lwn.net/Articles/2269/

But DaveM said we should just use the PCI pool code instead:

    http://lwn.net/Articles/2270/

- R.

#24 lore raw
Quoted 7 lines · Roland Dreier
Quoted 6 lines

I've been debugging various issues on the PowerPC 44x embedded architecture which happens to have non-coherent PCI DMA.

One of the problem I'm hitting is that one really need to enforce kmalloc alignement to cache lines or bad things will happen (among others with USB), for some reasons, powerpc failed to do so, I fixed it.

Quoted 8 lines

Heh... I hit the same problem literally 5 years ago:

    http://lwn.net/Articles/1783/

I implemented the __dma_buffer annotation:

    http://lwn.net/Articles/2269/

But DaveM said we should just use the PCI pool code instead:

    http://lwn.net/Articles/2270/

Heh, well...

In this case, DaveM just proposed something akin to your __dma_buffer :-)

On the other hand, after discussing with James, it looks like we'll just be reverting the patch that removed the kmalloc of the sense buffer since non cache-coherent archs are supposed to enforce kmalloc alignment to cache lines.

__dma_buffer still seems like a good thing to have if too many other drivers are hitting that but for this specific problem, it's not the approach that we'll be taking.

Cheers,
Ben.