Skip to contentSkip to conversation

scsi: Drop struct Scsi_Host->host_lock around SHT->queuecommand()

PATCH In review Nicholas A. Bellinger 6 participants 13 messages Sep 16, 2010 – Sep 17, 2010 SCSI

lore
Share & tools
lore
#0 lore raw

PATCH 1/8 scsi: Drop struct Scsi_Host->host_lock around SHT->queuecommand()

From: Nicholas Bellinger <[email protected]>

This patch converts scsi_dispatch_cmd() to only hold struct Scsi_Host->host_lock for scsi_cmd_get_serial(), and drops the lock because the call into the LLD with host->hostt->queuecommand().

---
 drivers/scsi/scsi.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/scsi/scsi.c +2 -1
index ad0ed21..06e5b3a 100644
@@ -745,6 +745,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	 * TODO: kill serial or move to blk layer
 	 */
 	scsi_cmd_get_serial(host, cmd); 
+	spin_unlock_irqrestore(host->host_lock, flags);
 
 	if (unlikely(host->shost_state == SHOST_DEL)) {
 		cmd->result = (DID_NO_CONNECT << 16);
@@ -753,7 +754,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 		trace_scsi_dispatch_cmd_start(cmd);
 		rtn = host->hostt->queuecommand(cmd, scsi_done);
 	}
-	spin_unlock_irqrestore(host->host_lock, flags);
+
 	if (rtn) {
 		trace_scsi_dispatch_cmd_error(cmd, rtn);
 		if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
Signature · 1 line
1.7.2.3
#1 lore raw
Quoted 16 lines · Nicholas A. Bellinger

From: Nicholas Bellinger <[email protected]>

This patch converts scsi_dispatch_cmd() to only hold struct Scsi_Host->host_lock for scsi_cmd_get_serial(), and drops the lock because the call into the LLD with host->hostt->queuecommand().

---
 drivers/scsi/scsi.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/scsi/scsi.c +0 -0
index ad0ed21..06e5b3a 100644

drivers/scsi/scsi.c int scsi_dispatch_cmd(struct scsi_cmnd *cmd) · line 748

Quoted 4 lines
drivers/scsi/scsi.c +1 -0
@@ -745,6 +745,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	 * TODO: kill serial or move to blk layer
 	 */
 	scsi_cmd_get_serial(host, cmd); 
+	spin_unlock_irqrestore(host->host_lock, flags);

So at least from where I stand, my object is to reduce the number of times we take and release the lock, which this doesn't do. As I said
before: we need to figure out the rest, which likely includes an atomic for the serial number (which is almost unused). I think the check against SHOST_DEL is fine unlocked.

James

#2 lore raw
Quoted 12 lines · James Bottomley
Quoted 11 lines · Nicholas A. Bellinger

From: Nicholas Bellinger <[email protected]>

This patch converts scsi_dispatch_cmd() to only hold struct Scsi_Host->host_lock for scsi_cmd_get_serial(), and drops the lock because the call into the LLD with host->hostt->queuecommand().

---
 drivers/scsi/scsi.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
Quoted 16 lines

drivers/scsi/scsi.c int scsi_dispatch_cmd(struct scsi_cmnd *cmd) · line 748

Quoted 9 lines
drivers/scsi/scsi.c +1 -0
index ad0ed21..06e5b3a 100644
@@ -745,6 +745,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	 * TODO: kill serial or move to blk layer
 	 */
 	scsi_cmd_get_serial(host, cmd); 
+	spin_unlock_irqrestore(host->host_lock, flags);

So at least from where I stand, my object is to reduce the number of times we take and release the lock, which this doesn't do. As I said
before: we need to figure out the rest, which likely includes an atomic for the serial number (which is almost unused). I think the check against SHOST_DEL is fine unlocked.

Ok, this makes sense if the shost_state == SHOST_DEL check really is OK to be done w/o host_lock held (I really don't know on this one..)

So if that is the case, then Tim and Vasu can you guys have a look at dropping the host_lock around serial number usage and post this for review..? I will plan to include the host_lock'less serial number patch into lio-core-2.6.git/drop-host_lock with the rest of the LLD driver conversion patches from this afternoon and respin a new branch for James and Co. to review.

Thanks!

--nab

#3 lore raw
In reply to James Bottomley
Quoted 5 lines · James Bottomley

So at least from where I stand, my object is to reduce the number of times we take and release the lock, which this doesn't do. As I said
before: we need to figure out the rest, which likely includes an atomic for the serial number (which is almost unused). I think the check against SHOST_DEL is fine unlocked.

The check by itself for sure is. But I wonder whether we make any assumptions about it not changing while we are in ->queuecommand, which isn't nessecarily the case after this patch.

#4 lore raw
In reply to James Bottomley
Quoted 4 lines

So at least from where I stand, my object is to reduce the number of times we take and release the lock, which this doesn't do. As I said
before: we need to figure out the rest, which likely includes an atomic for the serial number (which is almost unused). I think the check

If it's unused it should be removed, make optional.
Atomics are a scalability problem too and not much cheaper than spinlocks.

-Andi

#5 lore raw
Quoted 7 lines · Andi Kleen
Quoted 4 lines

So at least from where I stand, my object is to reduce the number of times we take and release the lock, which this doesn't do. As I said
before: we need to figure out the rest, which likely includes an atomic for the serial number (which is almost unused). I think the check

If it's unused it should be removed, make optional.
Atomics are a scalability problem too and not much cheaper than spinlocks.

I don't disagree with the idea of removing it, especially as it has so few users, but replacing the host lock with an atomic here would still vastly reduce the contention, which is the initial complaint. The contention occurs because the host lock is so widely used for other things. The way to reduce that contention is firstly to reduce the length of code covered by the lock and also reduce the actual number of places where the lock is taken. Compared with host lock's current vast footprint, and atomic here is tiny.

James

#6 lore raw
Quoted 4 lines

I don't disagree with the idea of removing it, especially as it has so few users, but replacing the host lock with an atomic here would still vastly reduce the contention, which is the initial complaint. The

Actually the complaint is the overhead of the spin lock. This can be either caused by contention or by cache line bounce time.

Quoted 5 lines

contention occurs because the host lock is so widely used for other things. The way to reduce that contention is firstly to reduce the length of code covered by the lock and also reduce the actual number of places where the lock is taken. Compared with host lock's current vast footprint, and atomic here is tiny.

That assumes that it's contention that is the problem and not simply bounce time.

-Andi

#7 lore raw
Quoted 7 lines · Andi Kleen
Quoted 3 lines

I don't disagree with the idea of removing it, especially as it has so few users, but replacing the host lock with an atomic here would still vastly reduce the contention, which is the initial complaint. The

Actually the complaint is the overhead of the spin lock. This can be either caused
by contention or by cache line bounce time.

The original complaint was contention. My desire is to reduce the locked path coverage, so I saw an opportunity.

What I was actually thinking of for the atomic is that we'd let it range [1..INT_MAX] so a zero was an indicator of no use of this. Then the actual code could become

if (atomic_read(x)) {
	do {
		y = atomic_add_return(1, x);
	} while (y == 0);
}

So "fast" cards not using the serial number set a zero there (we'd default initialise to one), the line is shared so no bouncing (because it's never updated). This should satisfy everyone.

Quoted 8 lines
Quoted 5 lines

contention occurs because the host lock is so widely used for other things. The way to reduce that contention is firstly to reduce the length of code covered by the lock and also reduce the actual number of places where the lock is taken. Compared with host lock's current vast footprint, and atomic here is tiny.

That assumes that it's contention that is the problem and not simply bounce time.

That's what the patch and data that started this whole thread showed, yes ... but I think actual bounce in the spinlock is also a problem ... we just don't have data to show it.

James

#8 lore raw
Quoted 16 lines · James Bottomley
Quoted 7 lines · Andi Kleen
Quoted 3 lines

I don't disagree with the idea of removing it, especially as it has so few users, but replacing the host lock with an atomic here would still vastly reduce the contention, which is the initial complaint. The

Actually the complaint is the overhead of the spin lock. This can be either caused
by contention or by cache line bounce time.

The original complaint was contention. My desire is to reduce the locked path coverage, so I saw an opportunity.

What I was actually thinking of for the atomic is that we'd let it range [1..INT_MAX] so a zero was an indicator of no use of this. Then the actual code could become

Quoted 5 lines
if (atomic_read(x)) {
	do {
		y = atomic_add_return(1, x);
	} while (y == 0);
}

The conversion of struct scsi_cmnd->serial_number to atomic_t and the above code for scsi_cmd_get_serial() sounds perfectly reasonable to me.

I will take a look at this conversion and respin a complete set of patches for review a bit later today.

Thanks!

--nab

Quoted 25 lines

So "fast" cards not using the serial number set a zero there (we'd default initialise to one), the line is shared so no bouncing (because it's never updated). This should satisfy everyone.

Quoted 8 lines
Quoted 5 lines

contention occurs because the host lock is so widely used for other things. The way to reduce that contention is firstly to reduce the length of code covered by the lock and also reduce the actual number of places where the lock is taken. Compared with host lock's current vast footprint, and atomic here is tiny.

That assumes that it's contention that is the problem and not simply bounce time.

That's what the patch and data that started this whole thread showed, yes ... but I think actual bounce in the spinlock is also a problem ... we just don't have data to show it.

James

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#9 lore raw
Quoted 17 lines · Nicholas A. Bellinger
Quoted 16 lines · James Bottomley
Quoted 7 lines · Andi Kleen
Quoted 3 lines

I don't disagree with the idea of removing it, especially as it has so few users, but replacing the host lock with an atomic here would still vastly reduce the contention, which is the initial complaint. The

Actually the complaint is the overhead of the spin lock. This can be either caused
by contention or by cache line bounce time.

The original complaint was contention. My desire is to reduce the locked path coverage, so I saw an opportunity.

What I was actually thinking of for the atomic is that we'd let it range [1..INT_MAX] so a zero was an indicator of no use of this. Then the actual code could become

Quoted 9 lines
Quoted 5 lines
if (atomic_read(x)) {
	do {
		y = atomic_add_return(1, x);
	} while (y == 0);
}

The conversion of struct scsi_cmnd->serial_number to atomic_t and the above code for scsi_cmd_get_serial() sounds perfectly reasonable to me.

Actually, that should be the conversion of struct
Scsi_Host->cmd_serial_number to an atomic_t. AFAICT there is no reason
for struct scsi_cmnd->serial_number needing to be an atomic_t.

Best,

--nab

#10 lore raw
Quoted 11 lines · Nicholas A. Bellinger
Quoted 11 lines
Quoted 10 lines

What I was actually thinking of for the atomic is that we'd let it range [1..INT_MAX] so a zero was an indicator of no use of this. Then the actual code could become

if (atomic_read(x)) {
	do {
		y = atomic_add_return(1, x);
	} while (y == 0);
}
Quoted 7 lines
Quoted 3 lines

The conversion of struct scsi_cmnd->serial_number to atomic_t and the above code for scsi_cmd_get_serial() sounds perfectly reasonable to me.

Actually, that should be the conversion of struct
Scsi_Host->cmd_serial_number to an atomic_t. AFAICT there is no reason
for struct scsi_cmnd->serial_number needing to be an atomic_t.

Just want to verify the hidden assumption we have here when the atomic int Scsi_Host->cmd_serial_number counter overflow after increment. The counter itself then becomes negative. We are assuming that when we do type conversion back to unsigned long scsi_cmnd->serial_number, we will get the right thing.

So for 32-bit int, we expect if we start with 0x7fffffff in hex and the expected sequence will be

	2147483647 (int) -> 2147483647 (unsigned long)  [0x7fffffff]
	+1
	-2147483648 (int) -> 2147483648 (unsigned long) [0x80000000]
	+1
	-2147483647 (int) -> 2147483649 (unsigned long) [0x80000001]

If there is architecture where the above assumption is not true (which I'm not aware of but just checking), then we should manually wrap the atomic counter to 1 when counter overflow.

Tim

#11 lore raw
Quoted 36 lines · Tim Chen
Quoted 11 lines · Nicholas A. Bellinger
Quoted 11 lines
Quoted 10 lines

What I was actually thinking of for the atomic is that we'd let it range [1..INT_MAX] so a zero was an indicator of no use of this. Then the actual code could become

if (atomic_read(x)) {
	do {
		y = atomic_add_return(1, x);
	} while (y == 0);
}
Quoted 7 lines
Quoted 3 lines

The conversion of struct scsi_cmnd->serial_number to atomic_t and the above code for scsi_cmd_get_serial() sounds perfectly reasonable to me.

Actually, that should be the conversion of struct
Scsi_Host->cmd_serial_number to an atomic_t. AFAICT there is no reason
for struct scsi_cmnd->serial_number needing to be an atomic_t.

Just want to verify the hidden assumption we have here when the atomic int Scsi_Host->cmd_serial_number counter overflow after increment. The counter itself then becomes negative. We are assuming that when we do type conversion back to unsigned long scsi_cmnd->serial_number, we will get the right thing.

So for 32-bit int, we expect if we start with 0x7fffffff in hex and the expected sequence will be

	2147483647 (int) -> 2147483647 (unsigned long)  [0x7fffffff]
	+1
	-2147483648 (int) -> 2147483648 (unsigned long) [0x80000000]
	+1
	-2147483647 (int) -> 2147483649 (unsigned long) [0x80000001]
Quoted 4 lines

If there is architecture where the above assumption is not true (which I'm not aware of but just checking), then we should manually wrap the atomic counter to 1 when counter overflow.

I was thinking about this as well, but I figured since jejb recommended it's usage for scsi_cmd_get_serial() that it would not be a problem. However I am not sure if he had keeping the struct scsi_cmnd->serial_number a 'unsigned long' that is done in the new v2 patches.

James, is there any other consideration here wrt to atomic_t wrapping for scsi_cmd_get_serial() using a astruct Scsi_Host->cmd_serial_number assignment to an 'unsigned long' that I need to include in a v3 series..?

--nab

#12 lore raw
In reply to Nicholas A. Bellinger
Quoted 17 lines · Nicholas A. Bellinger
Quoted 16 lines · James Bottomley
Quoted 7 lines · Andi Kleen
Quoted 3 lines

I don't disagree with the idea of removing it, especially as it has so few users, but replacing the host lock with an atomic here would still vastly reduce the contention, which is the initial complaint. The

Actually the complaint is the overhead of the spin lock. This can be either caused
by contention or by cache line bounce time.

The original complaint was contention. My desire is to reduce the locked path coverage, so I saw an opportunity.

What I was actually thinking of for the atomic is that we'd let it range [1..INT_MAX] so a zero was an indicator of no use of this. Then the actual code could become

Quoted 5 lines
Quoted 5 lines
if (atomic_read(x)) {
	do {
		y = atomic_add_return(1, x);
	} while (y == 0);
}

A tiny trick I like to use is to start a serial number at 1 and increment by 2 so its always odd and then never wraps to 0. That eliminates the check for 0 (and the curly brackets).

Quoted 36 lines

The conversion of struct scsi_cmnd->serial_number to atomic_t and the above code for scsi_cmd_get_serial() sounds perfectly reasonable to me.

I will take a look at this conversion and respin a complete set of patches for review a bit later today.

Thanks!

--nab

Quoted 25 lines

So "fast" cards not using the serial number set a zero there (we'd default initialise to one), the line is shared so no bouncing (because it's never updated). This should satisfy everyone.

Quoted 8 lines
Quoted 5 lines

contention occurs because the host lock is so widely used for other things. The way to reduce that contention is firstly to reduce the length of code covered by the lock and also reduce the actual number of places where the lock is taken. Compared with host lock's current vast footprint, and atomic here is tiny.

That assumes that it's contention that is the problem and not simply bounce time.

That's what the patch and data that started this whole thread showed, yes ... but I think actual bounce in the spinlock is also a problem ... we just don't have data to show it.

James

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html