Skip to contentSkip to conversation

SCSI host numbers?

PATCH New Itai Nahshon 3 participants 13 messages Jan 2, 2002 – Mar 21, 2002

lore
Share & tools
lore
#0 lore raw

Hello,

Under some scenarios Linux assigns the same
host_no to more than one scsi device.

Can someone tell me what is the intended behavior?

The problem is that a newly registered device gets its host_no from max_scsi_host. max_scsi_host is decremented when a device driver is unregistered (see drivers/scsi/host.c) allowing a second new
host to reuse the same host_no.
A device that was already in use (but the module
was unloaded and reloaded gets its old host_no that was kept in scsi_host_no_list. host_id's in scsi_host_no_list can also be reserved at boot time (though I never tried that).

This rarely happens except when there are two or more dynamic scsi hosts (I had i with ide-scsi and usb-storage).

I could mount devices even when they were on conflicting host numbers (/dev/sda on usb-storage and /dev/scd0 on ide-scsi). I could access only one of the devices via the generic-scsi interface (/dev/sgX). I do not know what other things can get broken if scsi host get conflicting host id.

This was tried on linux-2.4.9 (RedHat). I looked at newer kernels but did not see an obvious fix.

Similar bug reported also to redhat. See:
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=55876

Thanks,
-- Itai

#1 lore raw
Quoted 4 lines

Under some scenarios Linux assigns the same host_no to more than one scsi device.

Can someone tell me what is the intended behavior?

A number should never be reissued.

Quoted 5 lines

The problem is that a newly registered device gets its host_no from max_scsi_host. max_scsi_host is decremented when a device driver is unregistered (see drivers/scsi/host.c) allowing a second new host to reuse the same host_no.

I guess it needs to either only decrement the count if we are the highest one (trivial hack) or scan for a free number/keep a free bitmap. The devfs code has a handy little unique_id function for that

#2 lore raw
Quoted 13 lines · Alan Cox
Quoted 4 lines

Under some scenarios Linux assigns the same host_no to more than one scsi device.

Can someone tell me what is the intended behavior?

A number should never be reissued.

Quoted 5 lines

The problem is that a newly registered device gets its host_no from max_scsi_host. max_scsi_host is decremented when a device driver is unregistered (see drivers/scsi/host.c) allowing a second new host to reuse the same host_no.

Quoted 4 lines

I guess it needs to either only decrement the count if we are the highest one (trivial hack) or scan for a free number/keep a free bitmap. The devfs code has a handy little unique_id function for that

Yeah, I was going to get around to submitting a patch to change the SCSI host allocation code to use devfs_alloc_unique_number(), but right now that function is only functional if CONFIG_DEVFS_FS=y (otherwise you get a stub function which returns -1). So really this should be turned into a generic function, which was my plan all along, but I didn't want to fight that battle back then. Now that it's in the tree, I can look at doing this.

Comments? Got a suggestion for which file the generic function should go into? I figure on stripping the leading "devfs_" part of the function names.

				Regards,

					Richard....
Permanent: [email protected]
Current:   [email protected]
#3 lore raw
Quoted 3 lines

Comments? Got a suggestion for which file the generic function should go into? I figure on stripping the leading "devfs_" part of the function names.

Sounds sensible to me. I guess it belongs in lib/ somewhere ?

#4 lore raw
Quoted 5 lines · Alan Cox
Quoted 3 lines

Comments? Got a suggestion for which file the generic function should go into? I figure on stripping the leading "devfs_" part of the function names.

Sounds sensible to me. I guess it belongs in lib/ somewhere ?

I was thinking perhaps lib/unique.c

				Regards,

					Richard....
Permanent: [email protected]
Current:   [email protected]
#5 lore raw
In reply to Alan Cox
Quoted 7 lines · Alan Cox
Quoted 4 lines

Under some scenarios Linux assigns the same host_no to more than one scsi device.

Can someone tell me what is the intended behavior?

A number should never be reissued.

Quoted 7 lines
Quoted 5 lines

The problem is that a newly registered device gets its host_no from max_scsi_host. max_scsi_host is decremented when a device driver is unregistered (see drivers/scsi/host.c) allowing a second new host to reuse the same host_no.

I guess it needs to either only decrement the count if we are the highest

I'll argue that it should never decrement. The host that was just unregisrtered already has its host_id reserved and if we decrement, this number will be reasigned to the next new scsi host.

Unless if the code for reservation that causes the conflicts is removed (but I guess it has a reason).

Quoted 2 lines

one (trivial hack) or scan for a free number/keep a free bitmap. The devfs code has a handy little unique_id function for that

That would not solve it. The problem is that one piece of code tries to allocate unique numbers (and get them back to the pool when they are not in use), another piece of code remembers the old number that a scsi host had and whan it re-registers gives it back its old host_no regardless if this number was re-assigned to a new host.

Is there a function that given a string returns a unique number for this string? That would do the job.

-- Itai

#6 lore raw
Quoted 26 lines · Itai Nahshon
Quoted 7 lines · Alan Cox
Quoted 4 lines

Under some scenarios Linux assigns the same host_no to more than one scsi device.

Can someone tell me what is the intended behavior?

A number should never be reissued.

Quoted 7 lines
Quoted 5 lines

The problem is that a newly registered device gets its host_no from max_scsi_host. max_scsi_host is decremented when a device driver is unregistered (see drivers/scsi/host.c) allowing a second new host to reuse the same host_no.

I guess it needs to either only decrement the count if we are the highest

I'll argue that it should never decrement. The host that was just unregisrtered already has its host_id reserved and if we decrement, this number will be reasigned to the next new scsi host.

Unless if the code for reservation that causes the conflicts is removed (but I guess it has a reason).

Quoted 2 lines

one (trivial hack) or scan for a free number/keep a free bitmap. The devfs code has a handy little unique_id function for that

Quoted 6 lines

That would not solve it. The problem is that one piece of code tries to allocate unique numbers (and get them back to the pool when they are not in use), another piece of code remembers the old number that a scsi host had and whan it re-registers gives it back its old host_no regardless if this number was re-assigned to a new host.

Where exactly is the host_id for an unregistered host being remembered?

				Regards,

					Richard....
Permanent: [email protected]
Current:   [email protected]
#7 lore raw
In reply to Alan Cox
Quoted 2 lines · Richard Gooch

Where exactly is the host_id for an unregistered host being remembered?

Sorry for the late reply. I was away from Email for the whole week.

Scsi host numbers (for both regstered and unregistered hosts) are preserved in scsi_host_no_list.

The list is used in the function scsi_register (in drivers/scsi/hosts.c). Same function also adds new hosts to the list.

The list can be initialized (from boot parameters ?) by the function scsi_host_no_init (drivers/scsi/scsi.c).

-- Itai

#8 lore raw
Quoted 6 lines · Itai Nahshon
Quoted 2 lines · Richard Gooch

Where exactly is the host_id for an unregistered host being remembered?

Sorry for the late reply. I was away from Email for the whole week.

Quoted 8 lines

Scsi host numbers (for both regstered and unregistered hosts) are preserved in scsi_host_no_list.

The list is used in the function scsi_register (in drivers/scsi/hosts.c). Same function also adds new hosts to the list.

The list can be initialized (from boot parameters ?) by the function scsi_host_no_init (drivers/scsi/scsi.c).

Ah, yes. That was a patch someone sent to me years ago, and got included in the jumbo devfs patch. There's a boot parameter which allows you to control the allocation of host numbers.

So how about in scsi_host_no_init() we call alloc_unique_number() N times until we've allocated the required number of host numbers for manual control. These will never be freed. Then all other host allocations can be done dynamically. We would just need a flag in the host structure to disable deallocation of the number if it's one of the reserved numbers.

				Regards,

					Richard....
Permanent: [email protected]
Current:   [email protected]
#9 lore raw
In reply to Alan Cox
Quoted 6 lines · Richard Gooch

So how about in scsi_host_no_init() we call alloc_unique_number() N times until we've allocated the required number of host numbers for manual control. These will never be freed. Then all other host allocations can be done dynamically. We would just need a flag in the host structure to disable deallocation of the number if it's one of the reserved numbers.

See that dynamic hosts are also added to the list and *never* removed from it (even when the host is unregistered). With that behaviour your unique number functions would be an overkill because we must never free host nubers.

I suggest these changes:
max_scsi_host initialized in scsi_host_no_init. max_scsi_host never decremented.
That would fix the problem that I reported.
Than (cosmetic):
rename next_scsi_host to count_scsi_hosts (or num_scsi_hosts)
because it actually just counts the number of registered scsi hosts. The current name for that variable is confusing...

-- Itai

#10 lore raw
Quoted 13 lines · Itai Nahshon
Quoted 6 lines · Richard Gooch

So how about in scsi_host_no_init() we call alloc_unique_number() N times until we've allocated the required number of host numbers for manual control. These will never be freed. Then all other host allocations can be done dynamically. We would just need a flag in the host structure to disable deallocation of the number if it's one of the reserved numbers.

See that dynamic hosts are also added to the list and *never* removed from it (even when the host is unregistered). With that behaviour your unique number functions would be an overkill because we must never free host nubers.

Quoted 4 lines

I suggest these changes:
max_scsi_host initialized in scsi_host_no_init. max_scsi_host never decremented.
That would fix the problem that I reported.

But if you load, unload and reload a host driver, and it's not listed in scsihosts=, then won't it get a different host number each time?

				Regards,

					Richard....
Permanent: [email protected]
Current:   [email protected]
#11 lore raw
In reply to Alan Cox
Quoted 2 lines · Richard Gooch

But if you load, unload and reload a host driver, and it's not listed in scsihosts=, then won't it get a different host number each time?

In the fist time that it registers it is added to scsi_host_no_list (see code under "if (flag_new) {" in scsi/host.c).
Than it will get the same number again every time.

scsi_host_no_list is discarded only when scsi_mod
gets unloaded (that is if compiled as module).

-- Itai

#12 lore raw

PATCH 1/1 [PATCH] [was SCSI host numbers? ]

In reply to Alan Cox

Hello all,

Under some scenarios Linux assigns the same
host_no to more than one scsi device.

I raised this problem a long time ago.

To repeat the problem (all recent 2.4.x and possibly 2.5.x kernels):
Use two scsi drivers that are not required for system
use (mean - not the one that drives your hard disk). I got this problem the first time with ide-scsi and usb-storage. Call these device drivers A and B.
Host numbers are remembered after they are assigned
until the next reboot (or until unloading scsi_mod if
it is compiled as a module). Start with a "clean" system.

modprobe A
rmmod A
modprobe B
modprobe A

And - the two adapters now have the same host number.
In this case, some functions of A will not work. Especially devices attached to A cannot be accessed through the sg interface. I believe that writes to /proc/scsi/scsi will not work for these devices too (but these are useless for the drivers that I used in my tests).

See also <http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=55876>.

I gave it as much testing as I could, and I believe it is not worse than it was. People with more SCSI hardware should be able to try more complex cases.

I left the stuff in #ifdef + comments because I believe that the scsi registration code needs more cleanup. I have some related questions that I will post on a separate message to lkml.

-- Itai

scsi/hosts.c renamed from scsi/hosts-2.4.19-pre4.c +16 -2
@@ -81,8 +81,8 @@
 struct Scsi_Host * scsi_hostlist;
 struct Scsi_Device_Template * scsi_devicelist;
 
-int max_scsi_hosts;
-int next_scsi_host;
+int max_scsi_hosts;	/* host_no for next new host */
+int next_scsi_host;	/* count of registered scsi hosts */
 
 void
 scsi_unregister(struct Scsi_Host * sh){
@@ -107,6 +107,18 @@
     if (shn) shn->host_registered = 0;
     /* else {} : This should not happen, we should panic here... */
     
+#if 1
+    /* We shoult not decrement max_scsi_hosts (and make this value
+     * candidate for re-allocation by a different driver).
+     * Reason: the device is _still_ on the
+     * scsi_host_no_list and it's identified by its name. When the same
+     * device is re-registered it will get the same host_no again while
+     * new devices may use the allocation scheme and get this very same
+     * host_no.
+     * It's OK to have "holes" in the allocation but it does not mean
+     * "leaks".
+     */
+#else // if 0
     /* If we are removing the last host registered, it is safe to reuse
      * its host number (this avoids "holes" at boot time) (DB) 
      * It is also safe to reuse those of numbers directly below which have
@@ -121,7 +133,9 @@
 		break;
 	}
     }
+#endif
     next_scsi_host--;
+
     kfree((char *) sh);
 }