mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-20 12:11:26 +00:00
Great threads handling and performance improvements:
- io_context not needed anymore - Now threads pool can be per session - Each device now can have own type of threads pool with own threads count + docs updates and some cleanups and minor fixes. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1563 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -352,6 +352,8 @@ both iSCSI-SCST targets will look like:
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | `-- usn
|
||||
| |-- cdrom
|
||||
@@ -361,6 +363,8 @@ both iSCSI-SCST targets will look like:
|
||||
| | |-- handler -> ../../handlers/vcdrom
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | `-- usn
|
||||
| |-- disk1
|
||||
@@ -376,6 +380,8 @@ both iSCSI-SCST targets will look like:
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | |-- usn
|
||||
| | `-- write_through
|
||||
@@ -392,6 +398,8 @@ both iSCSI-SCST targets will look like:
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | |-- usn
|
||||
| | `-- write_through
|
||||
@@ -404,6 +412,8 @@ both iSCSI-SCST targets will look like:
|
||||
| |-- removable
|
||||
| |-- size_mb
|
||||
| |-- t10_dev_id
|
||||
| |-- threads_num
|
||||
| |-- threads_pool_type
|
||||
| |-- type
|
||||
| `-- usn
|
||||
|-- handlers
|
||||
@@ -608,6 +618,17 @@ as well.
|
||||
3. ISCSI initiators from pre-CentOS/RHEL 5 reported to have some
|
||||
performance problems. If you use it, it is strongly advised to upgrade.
|
||||
|
||||
4. Pay attention to have mpio_type option set correctly. See SCST core's
|
||||
README for more details.
|
||||
|
||||
5. If you are going to use your target in an VM environment, for
|
||||
instance as a shared storage with VMware, make sure all your VMs
|
||||
connected to the target via *separate* sessions, i.e. each VM has own
|
||||
connection to the target, not all VMs connected using a single
|
||||
connection. You can check it using SCST proc or sysfs interface. If you
|
||||
miss it, you can greatly loose performance of parallel access to your
|
||||
target from different VMs.
|
||||
|
||||
|
||||
Compilation options
|
||||
-------------------
|
||||
|
||||
@@ -263,6 +263,8 @@ both iSCSI-SCST targets will look like:
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | `-- usn
|
||||
| |-- cdrom
|
||||
@@ -272,6 +274,8 @@ both iSCSI-SCST targets will look like:
|
||||
| | |-- handler -> ../../handlers/vcdrom
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | `-- usn
|
||||
| |-- disk1
|
||||
@@ -303,6 +307,10 @@ both iSCSI-SCST targets will look like:
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | |-- usn
|
||||
| | `-- write_through
|
||||
@@ -315,6 +323,8 @@ both iSCSI-SCST targets will look like:
|
||||
| |-- removable
|
||||
| |-- size_mb
|
||||
| |-- t10_dev_id
|
||||
| |-- threads_num
|
||||
| |-- threads_pool_type
|
||||
| |-- type
|
||||
| `-- usn
|
||||
|-- handlers
|
||||
@@ -517,6 +527,17 @@ as well.
|
||||
3. ISCSI initiators built in pre-CentOS/RHEL 5 reported to have some
|
||||
performance problems. If you use it, it is strongly advised to upgrade.
|
||||
|
||||
4. Pay attention to have mpio_type option set correctly. See SCST core's
|
||||
README for more details.
|
||||
|
||||
5. If you are going to use your target in an VM environment, for
|
||||
instance as a shared storage with VMware, make sure all your VMs
|
||||
connected to the target via *separate* sessions, i.e. each VM has own
|
||||
connection to the target, not all VMs connected using a single
|
||||
connection. You can check it using SCST proc or sysfs interface. If you
|
||||
miss it, you can greatly loose performance of parallel access to your
|
||||
target from different VMs.
|
||||
|
||||
|
||||
Compilation options
|
||||
-------------------
|
||||
|
||||
@@ -583,11 +583,11 @@ static void init_max_params(void)
|
||||
}
|
||||
|
||||
/* QueuedCommands */
|
||||
target_keys[key_queued_cmnds].local_def = min(target_keys[key_queued_cmnds].local_def,
|
||||
target_keys[key_queued_cmnds].local_def = min((int)target_keys[key_queued_cmnds].local_def,
|
||||
iscsi_init_params.max_queued_cmds);
|
||||
target_keys[key_queued_cmnds].max = min(target_keys[key_queued_cmnds].max,
|
||||
target_keys[key_queued_cmnds].max = min((int)target_keys[key_queued_cmnds].max,
|
||||
iscsi_init_params.max_queued_cmds);
|
||||
target_keys[key_queued_cmnds].min = min(target_keys[key_queued_cmnds].min,
|
||||
target_keys[key_queued_cmnds].min = min((int)target_keys[key_queued_cmnds].min,
|
||||
iscsi_init_params.max_queued_cmds);
|
||||
|
||||
/* MaxRecvDataSegmentLength */
|
||||
|
||||
@@ -730,6 +730,8 @@ static void cmnd_exec_login(struct connection *conn)
|
||||
conn->state = STATE_LOGIN;
|
||||
|
||||
login_start(conn);
|
||||
if (rsp->status_class)
|
||||
return;
|
||||
if (!accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
|
||||
goto auth_err;
|
||||
if (rsp->status_class)
|
||||
|
||||
@@ -282,6 +282,8 @@ The resulting overall SCST sysfs hierarchy with initiator
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | `-- usn
|
||||
| |-- cdrom
|
||||
@@ -291,6 +293,8 @@ The resulting overall SCST sysfs hierarchy with initiator
|
||||
| | |-- handler -> ../../handlers/vcdrom
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | `-- usn
|
||||
| |-- disk1
|
||||
@@ -306,6 +310,8 @@ The resulting overall SCST sysfs hierarchy with initiator
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | |-- usn
|
||||
| | `-- write_through
|
||||
@@ -322,6 +328,8 @@ The resulting overall SCST sysfs hierarchy with initiator
|
||||
| | |-- resync_size
|
||||
| | |-- size_mb
|
||||
| | |-- t10_dev_id
|
||||
| | |-- threads_num
|
||||
| | |-- threads_pool_type
|
||||
| | |-- type
|
||||
| | |-- usn
|
||||
| | `-- write_through
|
||||
@@ -334,6 +342,8 @@ The resulting overall SCST sysfs hierarchy with initiator
|
||||
| |-- removable
|
||||
| |-- size_mb
|
||||
| |-- t10_dev_id
|
||||
| |-- threads_num
|
||||
| |-- threads_pool_type
|
||||
| |-- type
|
||||
| `-- usn
|
||||
|-- handlers
|
||||
@@ -411,6 +421,21 @@ The resulting overall SCST sysfs hierarchy with initiator
|
||||
`-- version
|
||||
|
||||
|
||||
Performance advices
|
||||
-------------------
|
||||
|
||||
1. Pay attention to have mpio_type option set correctly. See SCST core's
|
||||
README for more details.
|
||||
|
||||
2. If you are going to use your target in an VM environment, for
|
||||
instance as a shared storage with VMware, make sure all your VMs
|
||||
connected to the target via *separate* sessions. You can check it using
|
||||
SCST proc or sysfs interface. You should use available facilities, like
|
||||
NPIV, to make separate sessions for each VM. If you miss it, you can
|
||||
greatly loose performance of parallel access to your target from
|
||||
different VMs.
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
|
||||
82
scst/README
82
scst/README
@@ -701,6 +701,24 @@ Every target should have at least the following entries:
|
||||
initiators security groups, so you can assign the addressing method
|
||||
on per-initiator basis.
|
||||
|
||||
- mpio_type - defines how I/O from sessions to this target are grouped
|
||||
together. This I/O grouping is very important for performance. If
|
||||
you have this attribute set in a wrong value, you can considerably
|
||||
decrease performance of your setup. Possible values: "enable",
|
||||
"disable" and "auto". When "enable" all I/O from all sessions will be
|
||||
grouped together. When "disable", I/O from different sessions will
|
||||
not be grouped together, i.e. all sessions will have separate
|
||||
dedicated group. When "auto" (default), all I/O from initiators with
|
||||
the same name (iSCSI initiator name, for instance) will be grouped
|
||||
together with a separate dedicated group for each initiator name. For
|
||||
iSCSI it works well, but other transports usually use different
|
||||
names, so using them in MPIO configurations, you should instead use
|
||||
value "enable". This attribute is also available in the initiators
|
||||
security groups, so you can assign the addressing method on
|
||||
per-initiator basis. Recommended practice is to create a separate
|
||||
initiator security group for each MPIO sessions and set mpio_type in
|
||||
"enable".
|
||||
|
||||
- rel_tgt_id - allows to read or write SCSI Relative Target Port
|
||||
Identifier attribute. This identifier is used to identify SCSI Target
|
||||
Ports by some SCSI commands, mainly by Persistent Reservations
|
||||
@@ -710,7 +728,7 @@ Every target should have at least the following entries:
|
||||
until rel_tgt_id becomes unique. This attribute initialized unique by
|
||||
SCST by default.
|
||||
|
||||
A target driver may have also the follwoing entries:
|
||||
A target driver may have also the following entries:
|
||||
|
||||
- "hw_target" - if the target driver supports both hardware and virtual
|
||||
targets (for instance, an FC adapter supporting NPIV, which has
|
||||
@@ -1087,6 +1105,18 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
- removable - with this flag set the device is reported to remote
|
||||
initiators as removable.
|
||||
|
||||
- threads_num - sets number of threads in this device's threads
|
||||
pool. If 0 - no threads will be created, and global SCST threads pool
|
||||
will be used. If <0 - creation of the threads pool will be
|
||||
prohibited.
|
||||
|
||||
- threads_pool_type - sets threads pool type. Possible values:
|
||||
"per_initiator" and "shared". When "per_initiator" (default), each
|
||||
session from each initiator will use separate dedicated pool of
|
||||
threads. When "shared", all sessions from all initiators will share
|
||||
the same per-device pool of threads. Valid only if threads_num
|
||||
attribute >0.
|
||||
|
||||
Handler vdisk_blockio provides BLOCKIO mode to create virtual devices.
|
||||
This mode performs direct block I/O with a block device, bypassing the
|
||||
page cache for all operations. This mode works ideally with high-end
|
||||
@@ -1170,26 +1200,31 @@ For example:
|
||||
|-- resync_size
|
||||
|-- size_mb
|
||||
|-- t10_dev_id
|
||||
|-- threads_num
|
||||
|-- threads_pool_type
|
||||
|-- type
|
||||
|-- usn
|
||||
`-- write_through
|
||||
|
||||
Each vdisk_blockio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename,
|
||||
read_only, removable, resync_size, size_mb, t10_dev_id, type, usn. See
|
||||
description of vdisk_fileio's device for description of those parameters.
|
||||
read_only, removable, resync_size, size_mb, t10_dev_id, threads_num,
|
||||
threads_pool_type, type, usn. See description of vdisk_fileio's device
|
||||
for description of those parameters.
|
||||
|
||||
Each vdisk_nullio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
|
||||
removable, size_mb, t10_dev_id, type, usn. See description
|
||||
of vdisk_fileio's device for description of those parameters.
|
||||
removable, size_mb, t10_dev_id, threads_num, threads_pool_type, type,
|
||||
usn. See description of vdisk_fileio's device for description of those
|
||||
parameters.
|
||||
|
||||
Each vcdrom's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: filename, size_mb,
|
||||
t10_dev_id, type, usn. See description of vdisk_fileio's device for
|
||||
description of those parameters. Exception is filename attribute. For
|
||||
vcdrom it is writable. Writing to it allows to virtually insert or
|
||||
change virtual CD media in the virtual CDROM device. For example:
|
||||
t10_dev_id, threads_num, threads_pool_type, type, usn. See description
|
||||
of vdisk_fileio's device for description of those parameters. Exception
|
||||
is filename attribute. For vcdrom it is writable. Writing to it allows
|
||||
to virtually insert or change virtual CD media in the virtual CDROM
|
||||
device. For example:
|
||||
|
||||
- echo "/image.iso" >/sys/kernel/scst_tgt/devices/cdrom/filename - will
|
||||
insert file /image.iso as virtual media to the virtual CDROM cdrom.
|
||||
@@ -1406,13 +1441,12 @@ fileio_tgt's README file for more details.
|
||||
Performance
|
||||
-----------
|
||||
|
||||
Before doing any performance measurements note that:
|
||||
Before doing any performance measurements note that performance results
|
||||
are very much dependent from your type of load, so it is crucial that
|
||||
you choose access mode (FILEIO, BLOCKIO, O_DIRECT, pass-through), which
|
||||
suits your needs the best.
|
||||
|
||||
I. Performance results are very much dependent from your type of load,
|
||||
so it is crucial that you choose access mode (FILEIO, BLOCKIO,
|
||||
O_DIRECT, pass-through), which suits your needs the best.
|
||||
|
||||
II. In order to get the maximum performance you should:
|
||||
In order to get the maximum performance you should:
|
||||
|
||||
1. For SCST:
|
||||
|
||||
@@ -1440,7 +1474,17 @@ You can set the above options, except
|
||||
CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ, in the needed values
|
||||
using debug2perf root Makefile target.
|
||||
|
||||
4. For other target and initiator software parts:
|
||||
4. If you are going to use your target in an VM environment, for
|
||||
instance as a shared storage with VMware, make sure all your VMs
|
||||
connected to the target via *separate* sessions. For instance, for iSCSI
|
||||
it means that each VM has own connection to the target, not all VMs
|
||||
connected using a single connection. You can check it using SCST proc or
|
||||
sysfs interface. For other transports you should use available
|
||||
facilities, like NPIV for Fibre Channel, to make separate sessions for
|
||||
each VM. If you miss it, you can greatly loose performance of parallel
|
||||
access to your target from different VMs.
|
||||
|
||||
5. For other target and initiator software parts:
|
||||
|
||||
- Make sure you applied on your kernel all available SCST patches,
|
||||
especially io_context-2.6.X.patch. If for your kernel version this
|
||||
@@ -1501,7 +1545,7 @@ using debug2perf root Makefile target.
|
||||
files, because it allows considerably better linear write throughput,
|
||||
than ext3.
|
||||
|
||||
5. For hardware on target.
|
||||
6. For hardware on target.
|
||||
|
||||
- Make sure that your target hardware (e.g. target FC or network card)
|
||||
and underlaying IO hardware (e.g. IO card, like SATA, SCSI or RAID to
|
||||
@@ -1518,7 +1562,7 @@ using debug2perf root Makefile target.
|
||||
you have no choice, but PCI bus sharing, set in the BIOS PCI latency
|
||||
as low as possible.
|
||||
|
||||
6. If you use VDISK IO module in FILEIO mode, NV_CACHE option will
|
||||
7. If you use VDISK IO module in FILEIO mode, NV_CACHE option will
|
||||
provide you the best performance. But using it make sure you use a good
|
||||
UPS with ability to shutdown the target on the power failure.
|
||||
|
||||
@@ -1542,7 +1586,7 @@ IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
|
||||
for VDISK FILEIO devices above.
|
||||
|
||||
|
||||
In some cases, for instance working with SSD devices, which consume 100%
|
||||
8. In some cases, for instance working with SSD devices, which consume 100%
|
||||
of a single CPU load for data transfers in their internal threads, to
|
||||
maximize IOPS it can be needed to assign for those threads dedicated
|
||||
CPUs using Linux CPU affinity facilities. No IRQ processing should be
|
||||
|
||||
@@ -624,6 +624,24 @@ Every target should have at least the following entries:
|
||||
initiators security groups, so you can assign the addressing method
|
||||
on per-initiator basis.
|
||||
|
||||
- mpio_type - defines how I/O from sessions to this target are grouped
|
||||
together. This I/O grouping is very important for performance. If
|
||||
you have this attribute set in a wrong value, you can considerably
|
||||
decrease performance of your setup. Possible values: "enable",
|
||||
"disable" and "auto". When "enable" all I/O from all sessions will be
|
||||
grouped together. When "disable", I/O from different sessions will
|
||||
not be grouped together, i.e. all sessions will have separate
|
||||
dedicated group. When "auto" (default), all I/O from initiators with
|
||||
the same name (iSCSI initiator name, for instance) will be grouped
|
||||
together with a separate dedicated group for each initiator name. For
|
||||
iSCSI it works well, but other transports usually use different
|
||||
names, so using them in MPIO configurations, you should instead use
|
||||
value "enable". This attribute is also available in the initiators
|
||||
security groups, so you can assign the addressing method on
|
||||
per-initiator basis. Recommended practice is to create a separate
|
||||
initiator security group for each MPIO sessions and set mpio_type in
|
||||
"enable".
|
||||
|
||||
- rel_tgt_id - allows to read or write SCSI Relative Target Port
|
||||
Identifier attribute. This identifier is used to identify SCSI Target
|
||||
Ports by some SCSI commands, mainly by Persistent Reservations
|
||||
@@ -633,7 +651,7 @@ Every target should have at least the following entries:
|
||||
until rel_tgt_id becomes unique. This attribute initialized unique by
|
||||
SCST by default.
|
||||
|
||||
A target driver may have also the follwoing entries:
|
||||
A target driver may have also the following entries:
|
||||
|
||||
- "hw_target" - if the target driver supports both hardware and virtual
|
||||
targets (for instance, an FC adapter supporting NPIV, which has
|
||||
@@ -1011,6 +1029,18 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
- removable - with this flag set the device is reported to remote
|
||||
initiators as removable.
|
||||
|
||||
- threads_num - sets number of threads in this device's threads
|
||||
pool. If 0 - no threads will be created, and global SCST threads pool
|
||||
will be used. If <0 - creation of the threads pool will be
|
||||
prohibited.
|
||||
|
||||
- threads_pool_type - sets threads pool type. Possible values:
|
||||
"per_initiator" and "shared". When "per_initiator" (default), each
|
||||
session from each initiator will use separate dedicated pool of
|
||||
threads. When "shared", all sessions from all initiators will share
|
||||
the same per-device pool of threads. Valid only if threads_num
|
||||
attribute >0.
|
||||
|
||||
Handler vdisk_blockio provides BLOCKIO mode to create virtual devices.
|
||||
This mode performs direct block I/O with a block device, bypassing the
|
||||
page cache for all operations. This mode works ideally with high-end
|
||||
@@ -1094,26 +1124,31 @@ For example:
|
||||
|-- resync_size
|
||||
|-- size_mb
|
||||
|-- t10_dev_id
|
||||
|-- threads_num
|
||||
|-- threads_pool_type
|
||||
|-- type
|
||||
|-- usn
|
||||
`-- write_through
|
||||
|
||||
Each vdisk_blockio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename,
|
||||
read_only, removable, resync_size, size_mb, t10_dev_id, type, usn. See
|
||||
description of vdisk_fileio's device for description of those parameters.
|
||||
read_only, removable, resync_size, size_mb, t10_dev_id, threads_num,
|
||||
threads_pool_type, type, usn. See description of vdisk_fileio's device
|
||||
for description of those parameters.
|
||||
|
||||
Each vdisk_nullio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
|
||||
removable, size_mb, t10_dev_id, type, usn. See description
|
||||
of vdisk_fileio's device for description of those parameters.
|
||||
removable, size_mb, t10_dev_id, threads_num, threads_pool_type, type,
|
||||
usn. See description of vdisk_fileio's device for description of those
|
||||
parameters.
|
||||
|
||||
Each vcdrom's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: filename, size_mb,
|
||||
t10_dev_id, type, usn. See description of vdisk_fileio's device for
|
||||
description of those parameters. Exception is filename attribute. For
|
||||
vcdrom it is writable. Writing to it allows to virtually insert or
|
||||
change virtual CD media in the virtual CDROM device. For example:
|
||||
t10_dev_id, threads_num, threads_pool_type, type, usn. See description
|
||||
of vdisk_fileio's device for description of those parameters. Exception
|
||||
is filename attribute. For vcdrom it is writable. Writing to it allows
|
||||
to virtually insert or change virtual CD media in the virtual CDROM
|
||||
device. For example:
|
||||
|
||||
- echo "/image.iso" >/sys/kernel/scst_tgt/devices/cdrom/filename - will
|
||||
insert file /image.iso as virtual media to the virtual CDROM cdrom.
|
||||
@@ -1330,13 +1365,12 @@ fileio_tgt's README file for more details.
|
||||
Performance
|
||||
-----------
|
||||
|
||||
Before doing any performance measurements note that:
|
||||
Before doing any performance measurements note that performance results
|
||||
are very much dependent from your type of load, so it is crucial that
|
||||
you choose access mode (FILEIO, BLOCKIO, O_DIRECT, pass-through), which
|
||||
suits your needs the best.
|
||||
|
||||
I. Performance results are very much dependent from your type of load,
|
||||
so it is crucial that you choose access mode (FILEIO, BLOCKIO,
|
||||
O_DIRECT, pass-through), which suits your needs the best.
|
||||
|
||||
II. In order to get the maximum performance you should:
|
||||
In order to get the maximum performance you should:
|
||||
|
||||
1. For SCST:
|
||||
|
||||
@@ -1364,7 +1398,17 @@ You can set the above options, except
|
||||
CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ, in the needed values
|
||||
using debug2perf root Makefile target.
|
||||
|
||||
4. For other target and initiator software parts:
|
||||
4. If you are going to use your target in an VM environment, for
|
||||
instance as a shared storage with VMware, make sure all your VMs
|
||||
connected to the target via *separate* sessions. For instance, for iSCSI
|
||||
it means that each VM has own connection to the target, not all VMs
|
||||
connected using a single connection. You can check it using SCST proc or
|
||||
sysfs interface. For other transports you should use available
|
||||
facilities, like NPIV for Fibre Channel, to make separate sessions for
|
||||
each VM. If you miss it, you can greatly loose performance of parallel
|
||||
access to your target from different VMs.
|
||||
|
||||
5. For other target and initiator software parts:
|
||||
|
||||
- Make sure you applied on your kernel all available SCST patches,
|
||||
especially io_context-2.6.X.patch. If for your kernel version this
|
||||
@@ -1425,7 +1469,7 @@ using debug2perf root Makefile target.
|
||||
files, because it allows considerably better linear write throughput,
|
||||
than ext3.
|
||||
|
||||
5. For hardware on target.
|
||||
6. For hardware on target.
|
||||
|
||||
- Make sure that your target hardware (e.g. target FC or network card)
|
||||
and underlaying IO hardware (e.g. IO card, like SATA, SCSI or RAID to
|
||||
@@ -1442,7 +1486,7 @@ using debug2perf root Makefile target.
|
||||
you have no choice, but PCI bus sharing, set in the BIOS PCI latency
|
||||
as low as possible.
|
||||
|
||||
6. If you use VDISK IO module in FILEIO mode, NV_CACHE option will
|
||||
7. If you use VDISK IO module in FILEIO mode, NV_CACHE option will
|
||||
provide you the best performance. But using it make sure you use a good
|
||||
UPS with ability to shutdown the target on the power failure.
|
||||
|
||||
@@ -1465,7 +1509,7 @@ IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
|
||||
See also important notes about setting block sizes >512 bytes
|
||||
for VDISK FILEIO devices above.
|
||||
|
||||
In some cases, for instance working with SSD devices, which consume 100%
|
||||
8. In some cases, for instance working with SSD devices, which consume 100%
|
||||
of a single CPU load for data transfers in their internal threads, to
|
||||
maximize IOPS it can be needed to assign for those threads dedicated
|
||||
CPUs using Linux CPU affinity facilities. No IRQ processing should be
|
||||
|
||||
@@ -935,6 +935,21 @@ struct scst_tgt_template {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Threads pool types. Changing them don't forget to change
|
||||
* the corresponding *_STR values in scst_const.h!
|
||||
*/
|
||||
enum scst_dev_type_threads_pool_type {
|
||||
/* Each initiator will have dedicated threads pool. */
|
||||
SCST_THREADS_POOL_PER_INITIATOR = 0,
|
||||
|
||||
/* All connected initiators will use shared threads pool */
|
||||
SCST_THREADS_POOL_SHARED,
|
||||
|
||||
/* Invalid value for scst_parse_threads_pool_type() */
|
||||
SCST_THREADS_POOL_TYPE_INVALID,
|
||||
};
|
||||
|
||||
struct scst_dev_type {
|
||||
/* SCSI type of the supported device. MUST HAVE */
|
||||
int type;
|
||||
@@ -1122,11 +1137,15 @@ struct scst_dev_type {
|
||||
char name[SCST_MAX_NAME + 10];
|
||||
|
||||
/*
|
||||
* Number of dedicated threads. If 0 - no dedicated threads will
|
||||
* be created, if <0 - creation of dedicated threads is prohibited.
|
||||
* Number of threads in this handler's devices' threads pools.
|
||||
* If 0 - no threads will be created, if <0 - creation of the threads
|
||||
* pools is prohibited. Also pay attention to threads_pool_type below.
|
||||
*/
|
||||
int threads_num;
|
||||
|
||||
/* Threads pool type. Valid only if threads_num > 0. */
|
||||
enum scst_dev_type_threads_pool_type threads_pool_type;
|
||||
|
||||
/* Optional default log flags */
|
||||
const unsigned long default_trace_flags;
|
||||
|
||||
@@ -1403,19 +1422,25 @@ struct scst_session {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct scst_cmd_lists {
|
||||
struct scst_cmd_threads {
|
||||
spinlock_t cmd_list_lock;
|
||||
struct list_head active_cmd_list;
|
||||
wait_queue_head_t cmd_list_waitQ;
|
||||
|
||||
struct io_context *io_context;
|
||||
|
||||
int nr_threads;
|
||||
struct list_head threads_list;
|
||||
|
||||
struct list_head lists_list_entry;
|
||||
};
|
||||
|
||||
struct scst_cmd {
|
||||
/* List entry for below *_cmd_lists */
|
||||
/* List entry for below *_cmd_threads */
|
||||
struct list_head cmd_list_entry;
|
||||
|
||||
/* Pointer to lists of commands with the lock */
|
||||
struct scst_cmd_lists *cmd_lists;
|
||||
struct scst_cmd_threads *cmd_threads;
|
||||
|
||||
atomic_t cmd_ref;
|
||||
|
||||
@@ -1836,14 +1861,8 @@ struct scst_device {
|
||||
/* Corresponding real SCSI device, could be NULL for virtual devices */
|
||||
struct scsi_device *scsi_dev;
|
||||
|
||||
/* Pointer to lists of commands with the lock */
|
||||
struct scst_cmd_lists *p_cmd_lists;
|
||||
|
||||
/* Lists of commands with lock, if dedicated threads are used */
|
||||
struct scst_cmd_lists cmd_lists;
|
||||
|
||||
/* Per-device dedicated IO context */
|
||||
struct io_context *dev_io_ctx;
|
||||
struct scst_cmd_threads dev_cmd_threads;
|
||||
|
||||
/* How many cmds alive on this dev */
|
||||
atomic_t dev_cmd_count;
|
||||
@@ -1891,11 +1910,11 @@ struct scst_device {
|
||||
/* List of acg_dev's, one per acg, protected by scst_mutex */
|
||||
struct list_head dev_acg_dev_list;
|
||||
|
||||
/* List of dedicated threads, protected by scst_mutex */
|
||||
struct list_head threads_list;
|
||||
/* Number of threads in the device's threads pools */
|
||||
int threads_num;
|
||||
|
||||
/* Device number */
|
||||
int dev_num;
|
||||
/* Threads pool type of the device. Valid only if threads_num > 0. */
|
||||
enum scst_dev_type_threads_pool_type threads_pool_type;
|
||||
|
||||
/* Set if tgt_kobj was initialized */
|
||||
unsigned int dev_kobj_initialized:1;
|
||||
@@ -1977,8 +1996,11 @@ struct scst_tgt_dev {
|
||||
spinlock_t thr_data_lock;
|
||||
struct list_head thr_data_list;
|
||||
|
||||
/* Per-(device, session) dedicated IO context */
|
||||
struct io_context *tgt_dev_io_ctx;
|
||||
/* Pointer to lists of commands with the lock */
|
||||
struct scst_cmd_threads *active_cmd_threads;
|
||||
|
||||
/* Lists of commands with lock, if dedicated threads are used */
|
||||
struct scst_cmd_threads tgt_dev_cmd_threads;
|
||||
|
||||
spinlock_t tgt_dev_lock; /* per-session device lock */
|
||||
|
||||
@@ -2043,6 +2065,25 @@ struct scst_acg_dev {
|
||||
struct kobject acg_dev_kobj;
|
||||
};
|
||||
|
||||
/*
|
||||
* ACG MPIO types. Changing them don't forget to change
|
||||
* the corresponding *_STR values in scst_const.h!
|
||||
*/
|
||||
enum scst_acg_mpio {
|
||||
/*
|
||||
* All initiators with the same name connected to this group will have
|
||||
* shared IO context, for each name own context. All initiators with
|
||||
* different names will have own IO context.
|
||||
*/
|
||||
SCST_ACG_MPIO_AUTO = 0,
|
||||
|
||||
/* All initiators connected to this group will have shared IO context */
|
||||
SCST_ACG_MPIO_ENABLE,
|
||||
|
||||
/* Each initiator connected to this group will have own IO context */
|
||||
SCST_ACG_MPIO_DISABLE,
|
||||
};
|
||||
|
||||
/*
|
||||
* ACG - access control group. Used to store group related
|
||||
* control information.
|
||||
@@ -2068,6 +2109,9 @@ struct scst_acg {
|
||||
struct proc_dir_entry *acg_proc_root;
|
||||
#endif
|
||||
|
||||
/* Type of MPIO initiators groupping */
|
||||
enum scst_acg_mpio acg_mpio_type;
|
||||
|
||||
unsigned int acg_kobj_initialized:1;
|
||||
unsigned int in_tgt_acg_list:1;
|
||||
|
||||
@@ -3479,13 +3523,6 @@ static inline const char *scst_get_tgt_name(const struct scst_tgt *tgt)
|
||||
return tgt->tgt_name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds and deletes (stops) num of global SCST's threads. Returns 0 on
|
||||
* success, error code otherwise.
|
||||
*/
|
||||
int scst_add_global_threads(int num);
|
||||
void scst_del_global_threads(int num);
|
||||
|
||||
int scst_alloc_sense(struct scst_cmd *cmd, int atomic);
|
||||
int scst_alloc_set_sense(struct scst_cmd *cmd, int atomic,
|
||||
const uint8_t *sense, unsigned int len);
|
||||
@@ -3748,4 +3785,17 @@ void scst_restore_token_str(char *prev_lexem, char *token_str);
|
||||
*/
|
||||
char *scst_get_next_token_str(char **input_str);
|
||||
|
||||
/*
|
||||
* Converts string presentation of threads pool type to enum.
|
||||
* Returns SCST_THREADS_POOL_TYPE_INVALID if the string is invalid.
|
||||
*/
|
||||
enum scst_dev_type_threads_pool_type scst_parse_threads_pool_type(
|
||||
const char *p, int len);
|
||||
|
||||
/* Initializes scst_cmd_threads structure */
|
||||
void scst_init_threads(struct scst_cmd_threads *cmd_threads);
|
||||
|
||||
/* Deinitializes scst_cmd_threads structure */
|
||||
void scst_deinit_threads(struct scst_cmd_threads *cmd_threads);
|
||||
|
||||
#endif /* __SCST_H */
|
||||
|
||||
@@ -348,12 +348,26 @@ enum scst_cdb_flags {
|
||||
|
||||
#define SCST_MAX_OTHER_TIMEOUT (14000 * HZ)
|
||||
|
||||
/*************************************************************
|
||||
** ACG MPIO attribute values. Must match scst_acg_mpio!
|
||||
*************************************************************/
|
||||
#define SCST_ACG_MPIO_AUTO_STR "auto"
|
||||
#define SCST_ACG_MPIO_ENABLE_STR "enable"
|
||||
#define SCST_ACG_MPIO_DISABLE_STR "disable"
|
||||
|
||||
/*************************************************************
|
||||
** Threads pool type attribute values.
|
||||
** Must match scst_dev_type_threads_pool_type!
|
||||
*************************************************************/
|
||||
#define SCST_THREADS_POOL_PER_INITIATOR_STR "per_initiator"
|
||||
#define SCST_THREADS_POOL_SHARED_STR "shared"
|
||||
|
||||
/*************************************************************
|
||||
** Misc constants
|
||||
*************************************************************/
|
||||
#define SCST_SYSFS_BLOCK_SIZE PAGE_SIZE
|
||||
#define SCST_SYSFS_BLOCK_SIZE PAGE_SIZE
|
||||
|
||||
#define SCST_SYSFS_KEY_MARK "[key]"
|
||||
#define SCST_SYSFS_KEY_MARK "[key]"
|
||||
|
||||
#define SCST_MIN_REL_TGT_ID 1
|
||||
#define SCST_MAX_REL_TGT_ID 65535
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
diff -rup linux-source-2.6.26.orig/block/blk-ioc.c linux-source-2.6.26/block/blk-ioc.c
|
||||
--- linux-source-2.6.26.orig/block/blk-ioc.c 2008-07-13 17:51:29.000000000 -0400
|
||||
+++ linux-source-2.6.26/block/blk-ioc.c 2009-08-26 13:31:49.000000000 -0400
|
||||
@@ -65,6 +65,21 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ if (ioc->aic && ioc->aic->exit)
|
||||
+ ioc->aic->exit(ioc->aic);
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ put_io_context(ioc);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(void)
|
||||
{
|
||||
@@ -75,13 +90,7 @@ void exit_io_context(void)
|
||||
current->io_context = NULL;
|
||||
task_unlock(current);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- if (ioc->aic && ioc->aic->exit)
|
||||
- ioc->aic->exit(ioc->aic);
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- put_io_context(ioc);
|
||||
- }
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -105,7 +114,8 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
-
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
+
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
* Otherwise, return its existing IO context.
|
||||
diff -rup linux-source-2.6.26.orig/include/linux/iocontext.h linux-source-2.6.26/include/linux/iocontext.h
|
||||
--- linux-source-2.6.26.orig/include/linux/iocontext.h 2008-07-13 17:51:29.000000000 -0400
|
||||
+++ linux-source-2.6.26/include/linux/iocontext.h 2009-08-26 13:34:11.000000000 -0400
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <linux/radix-tree.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
+#define SCST_IO_CONTEXT
|
||||
+
|
||||
/*
|
||||
* This is the per-process anticipatory I/O scheduler state.
|
||||
*/
|
||||
@@ -99,4 +101,6 @@ static inline struct io_context *ioc_tas
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
+
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
diff -upkr linux-2.6.27.2/block/blk-ioc.c linux-2.6.27.2/block/blk-ioc.c
|
||||
--- linux-2.6.27.2/block/blk-ioc.c 2008-10-10 02:13:53.000000000 +0400
|
||||
+++ linux-2.6.27.2/block/blk-ioc.c 2009-03-23 21:32:37.000000000 +0300
|
||||
@@ -65,6 +65,21 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ if (ioc->aic && ioc->aic->exit)
|
||||
+ ioc->aic->exit(ioc->aic);
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ put_io_context(ioc);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(void)
|
||||
{
|
||||
@@ -75,13 +90,7 @@ void exit_io_context(void)
|
||||
current->io_context = NULL;
|
||||
task_unlock(current);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- if (ioc->aic && ioc->aic->exit)
|
||||
- ioc->aic->exit(ioc->aic);
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- put_io_context(ioc);
|
||||
- }
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -105,6 +114,7 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
diff -upkr linux-2.6.27.2/include/linux/iocontext.h linux-2.6.27.2/include/linux/iocontext.h
|
||||
--- linux-2.6.27.2/include/linux/iocontext.h 2008-10-10 02:13:53.000000000 +0400
|
||||
+++ linux-2.6.27.2/include/linux/iocontext.h 2009-03-23 21:32:37.000000000 +0300
|
||||
@@ -103,7 +103,9 @@ static inline struct io_context *ioc_tas
|
||||
int put_io_context(struct io_context *ioc);
|
||||
void exit_io_context(void);
|
||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||
+#define SCST_IO_CONTEXT
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
||||
#else
|
||||
static inline void exit_io_context(void)
|
||||
@@ -1,61 +0,0 @@
|
||||
diff -upkr linux-2.6.28/block/blk-ioc.c linux-2.6.28/block/blk-ioc.c
|
||||
--- linux-2.6.28/block/blk-ioc.c 2008-12-25 02:26:37.000000000 +0300
|
||||
+++ linux-2.6.28/block/blk-ioc.c 2009-03-23 14:28:48.000000000 +0300
|
||||
@@ -65,6 +65,21 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ if (ioc->aic && ioc->aic->exit)
|
||||
+ ioc->aic->exit(ioc->aic);
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ put_io_context(ioc);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(void)
|
||||
{
|
||||
@@ -75,13 +90,7 @@ void exit_io_context(void)
|
||||
current->io_context = NULL;
|
||||
task_unlock(current);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- if (ioc->aic && ioc->aic->exit)
|
||||
- ioc->aic->exit(ioc->aic);
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- put_io_context(ioc);
|
||||
- }
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -105,6 +114,7 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
diff -upkr linux-2.6.28/include/linux/iocontext.h linux-2.6.28/include/linux/iocontext.h
|
||||
--- linux-2.6.28/include/linux/iocontext.h 2008-12-25 02:26:37.000000000 +0300
|
||||
+++ linux-2.6.28/include/linux/iocontext.h 2009-03-23 14:05:01.000000000 +0300
|
||||
@@ -103,7 +103,9 @@ static inline struct io_context *ioc_tas
|
||||
int put_io_context(struct io_context *ioc);
|
||||
void exit_io_context(void);
|
||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||
+#define SCST_IO_CONTEXT
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
||||
#else
|
||||
static inline void exit_io_context(void)
|
||||
@@ -1,61 +0,0 @@
|
||||
diff -upkr linux-2.6.29/block/blk-ioc.c linux-2.6.29/block/blk-ioc.c
|
||||
--- linux-2.6.29/block/blk-ioc.c 2008-12-25 02:26:37.000000000 +0300
|
||||
+++ linux-2.6.29/block/blk-ioc.c 2009-03-23 14:28:48.000000000 +0300
|
||||
@@ -65,6 +65,21 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ if (ioc->aic && ioc->aic->exit)
|
||||
+ ioc->aic->exit(ioc->aic);
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ put_io_context(ioc);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(void)
|
||||
{
|
||||
@@ -75,13 +90,7 @@ void exit_io_context(void)
|
||||
current->io_context = NULL;
|
||||
task_unlock(current);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- if (ioc->aic && ioc->aic->exit)
|
||||
- ioc->aic->exit(ioc->aic);
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- put_io_context(ioc);
|
||||
- }
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -105,6 +114,7 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
diff -upkr linux-2.6.29/include/linux/iocontext.h linux-2.6.29/include/linux/iocontext.h
|
||||
--- linux-2.6.29/include/linux/iocontext.h 2008-12-25 02:26:37.000000000 +0300
|
||||
+++ linux-2.6.29/include/linux/iocontext.h 2009-03-23 14:05:01.000000000 +0300
|
||||
@@ -103,7 +103,9 @@ static inline struct io_context *ioc_tas
|
||||
int put_io_context(struct io_context *ioc);
|
||||
void exit_io_context(void);
|
||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||
+#define SCST_IO_CONTEXT
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
||||
#else
|
||||
static inline void exit_io_context(void)
|
||||
@@ -1,61 +0,0 @@
|
||||
diff -upkr linux-2.6.30.1/block/blk-ioc.c linux-2.6.30.1/block/blk-ioc.c
|
||||
--- linux-2.6.30.1/block/blk-ioc.c 2009-06-10 07:05:27.000000000 +0400
|
||||
+++ linux-2.6.30.1/block/blk-ioc.c 2009-07-01 15:55:08.000000000 +0400
|
||||
@@ -65,6 +65,21 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ if (ioc->aic && ioc->aic->exit)
|
||||
+ ioc->aic->exit(ioc->aic);
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ put_io_context(ioc);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(void)
|
||||
{
|
||||
@@ -75,13 +90,7 @@ void exit_io_context(void)
|
||||
current->io_context = NULL;
|
||||
task_unlock(current);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- if (ioc->aic && ioc->aic->exit)
|
||||
- ioc->aic->exit(ioc->aic);
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- put_io_context(ioc);
|
||||
- }
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -105,6 +114,7 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
diff -upkr linux-2.6.30.1/include/linux/iocontext.h linux-2.6.30.1/include/linux/iocontext.h
|
||||
--- linux-2.6.30.1/include/linux/iocontext.h 2009-06-10 07:05:27.000000000 +0400
|
||||
+++ linux-2.6.30.1/include/linux/iocontext.h 2009-07-01 15:20:24.000000000 +0400
|
||||
@@ -103,7 +103,9 @@ static inline struct io_context *ioc_tas
|
||||
int put_io_context(struct io_context *ioc);
|
||||
void exit_io_context(void);
|
||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||
+#define SCST_IO_CONTEXT
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
||||
#else
|
||||
static inline void exit_io_context(void)
|
||||
@@ -1,61 +0,0 @@
|
||||
diff -upkr linux-2.6.31/block/blk-ioc.c linux-2.6.31/block/blk-ioc.c
|
||||
--- linux-2.6.31/block/blk-ioc.c 2009-09-10 02:13:59.000000000 +0400
|
||||
+++ linux-2.6.31/block/blk-ioc.c 2009-09-23 14:17:17.000000000 +0400
|
||||
@@ -65,6 +65,21 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ if (ioc->aic && ioc->aic->exit)
|
||||
+ ioc->aic->exit(ioc->aic);
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ put_io_context(ioc);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(void)
|
||||
{
|
||||
@@ -75,13 +90,7 @@ void exit_io_context(void)
|
||||
current->io_context = NULL;
|
||||
task_unlock(current);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- if (ioc->aic && ioc->aic->exit)
|
||||
- ioc->aic->exit(ioc->aic);
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- put_io_context(ioc);
|
||||
- }
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -105,6 +114,7 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
diff -upkr linux-2.6.31/include/linux/iocontext.h linux-2.6.31/include/linux/iocontext.h
|
||||
--- linux-2.6.31/include/linux/iocontext.h 2009-09-10 02:13:59.000000000 +0400
|
||||
+++ linux-2.6.31/include/linux/iocontext.h 2009-09-23 14:17:17.000000000 +0400
|
||||
@@ -103,7 +103,9 @@ static inline struct io_context *ioc_tas
|
||||
int put_io_context(struct io_context *ioc);
|
||||
void exit_io_context(void);
|
||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||
+#define SCST_IO_CONTEXT
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
||||
#else
|
||||
static inline void exit_io_context(void)
|
||||
@@ -1,61 +0,0 @@
|
||||
diff -upkr linux-2.6.32.1/block/blk-ioc.c linux-2.6.32.1/block/blk-ioc.c
|
||||
--- linux-2.6.32.1/block/blk-ioc.c 2009-12-03 06:51:21.000000000 +0300
|
||||
+++ linux-2.6.32.1/block/blk-ioc.c 2009-12-16 15:20:36.000000000 +0300
|
||||
@@ -65,6 +65,21 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ if (ioc->aic && ioc->aic->exit)
|
||||
+ ioc->aic->exit(ioc->aic);
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ put_io_context(ioc);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(void)
|
||||
{
|
||||
@@ -75,13 +90,7 @@ void exit_io_context(void)
|
||||
current->io_context = NULL;
|
||||
task_unlock(current);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- if (ioc->aic && ioc->aic->exit)
|
||||
- ioc->aic->exit(ioc->aic);
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- put_io_context(ioc);
|
||||
- }
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -105,6 +114,7 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
diff -upkr linux-2.6.32.1/include/linux/iocontext.h linux-2.6.32.1/include/linux/iocontext.h
|
||||
--- linux-2.6.32.1/include/linux/iocontext.h 2009-12-03 06:51:21.000000000 +0300
|
||||
+++ linux-2.6.32.1/include/linux/iocontext.h 2009-12-16 15:20:36.000000000 +0300
|
||||
@@ -103,7 +103,9 @@ static inline struct io_context *ioc_tas
|
||||
int put_io_context(struct io_context *ioc);
|
||||
void exit_io_context(void);
|
||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||
+#define SCST_IO_CONTEXT
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
||||
#else
|
||||
static inline void exit_io_context(void)
|
||||
@@ -1,57 +0,0 @@
|
||||
diff -upkr linux-2.6.33/block/blk-ioc.c linux-2.6.33/block/blk-ioc.c
|
||||
--- linux-2.6.33/block/blk-ioc.c 2010-02-24 21:52:17.000000000 +0300
|
||||
+++ linux-2.6.33/block/blk-ioc.c 2010-03-01 15:39:49.000000000 +0300
|
||||
@@ -63,6 +63,19 @@ static void cfq_exit(struct io_context *
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+void __exit_io_context(struct io_context *ioc)
|
||||
+{
|
||||
+ if (ioc == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
+ cfq_exit(ioc);
|
||||
+
|
||||
+ }
|
||||
+ put_io_context(ioc);
|
||||
+}
|
||||
+EXPORT_SYMBOL(__exit_io_context);
|
||||
+
|
||||
/* Called by the exitting task */
|
||||
void exit_io_context(struct task_struct *task)
|
||||
{
|
||||
@@ -73,11 +86,7 @@ void exit_io_context(struct task_struct
|
||||
task->io_context = NULL;
|
||||
task_unlock(task);
|
||||
|
||||
- if (atomic_dec_and_test(&ioc->nr_tasks)) {
|
||||
- cfq_exit(ioc);
|
||||
-
|
||||
- }
|
||||
- put_io_context(ioc);
|
||||
+ __exit_io_context(ioc);
|
||||
}
|
||||
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
|
||||
@@ -100,6 +109,7 @@ struct io_context *alloc_io_context(gfp_
|
||||
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(alloc_io_context);
|
||||
|
||||
/*
|
||||
* If the current task has no IO context then create one and initialise it.
|
||||
diff -upkr linux-2.6.33/include/linux/iocontext.h linux-2.6.33/include/linux/iocontext.h
|
||||
--- linux-2.6.33/include/linux/iocontext.h 2010-02-24 21:52:17.000000000 +0300
|
||||
+++ linux-2.6.33/include/linux/iocontext.h 2010-03-01 15:38:54.000000000 +0300
|
||||
@@ -76,7 +76,9 @@ struct task_struct;
|
||||
int put_io_context(struct io_context *ioc);
|
||||
void exit_io_context(struct task_struct *task);
|
||||
struct io_context *get_io_context(gfp_t gfp_flags, int node);
|
||||
+#define SCST_IO_CONTEXT
|
||||
struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
|
||||
+void __exit_io_context(struct io_context *ioc);
|
||||
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
|
||||
#else
|
||||
static inline void exit_io_context(struct task_struct *task)
|
||||
@@ -41,9 +41,13 @@
|
||||
struct scst_user_dev {
|
||||
struct rw_semaphore dev_rwsem;
|
||||
|
||||
struct scst_cmd_lists cmd_lists;
|
||||
/*
|
||||
* Must be kept here, because it's needed on the cleanup time,
|
||||
* when corresponding scst_dev is already dead.
|
||||
*/
|
||||
struct scst_cmd_threads udev_cmd_threads;
|
||||
|
||||
/* Protected by cmd_lists.cmd_list_lock */
|
||||
/* Protected by udev_cmd_threads.cmd_list_lock */
|
||||
struct list_head ready_cmd_list;
|
||||
|
||||
/* Protected by dev_rwsem or don't need any protection */
|
||||
@@ -74,7 +78,7 @@ struct scst_user_dev {
|
||||
|
||||
struct scst_dev_type devtype;
|
||||
|
||||
/* Both protected by cmd_lists.cmd_list_lock */
|
||||
/* Both protected by udev_cmd_threads.cmd_list_lock */
|
||||
unsigned int handle_counter;
|
||||
struct list_head ucmd_hash[1 << DEV_USER_CMD_HASH_ORDER];
|
||||
|
||||
@@ -111,7 +115,7 @@ struct scst_user_cmd {
|
||||
|
||||
/*
|
||||
* Special flags, which can be accessed asynchronously (hence "long").
|
||||
* Protected by cmd_lists.cmd_list_lock.
|
||||
* Protected by udev_cmd_threads.cmd_list_lock.
|
||||
*/
|
||||
unsigned long sent_to_user:1;
|
||||
unsigned long jammed:1;
|
||||
@@ -245,7 +249,7 @@ static struct task_struct *cleanup_thread;
|
||||
|
||||
/*
|
||||
* Skip this command if result is not 0. Must be called under
|
||||
* cmd_lists.cmd_list_lock and IRQ off.
|
||||
* udev_cmd_threads.cmd_list_lock and IRQ off.
|
||||
*/
|
||||
static inline bool ucmd_get_check(struct scst_user_cmd *ucmd)
|
||||
{
|
||||
@@ -345,14 +349,14 @@ static void cmd_insert_hash(struct scst_user_cmd *ucmd)
|
||||
struct scst_user_cmd *u;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
do {
|
||||
ucmd->h = dev->handle_counter++;
|
||||
u = __ucmd_find_hash(dev, ucmd->h);
|
||||
} while (u != NULL);
|
||||
head = &dev->ucmd_hash[scst_user_cmd_hashfn(ucmd->h)];
|
||||
list_add_tail(&ucmd->hash_list_entry, head);
|
||||
spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_unlock_irqrestore(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
TRACE_DBG("Inserted ucmd %p, h=%d (dev %s)", ucmd, ucmd->h, dev->name);
|
||||
return;
|
||||
@@ -362,9 +366,9 @@ static inline void cmd_remove_hash(struct scst_user_cmd *ucmd)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ucmd->dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&ucmd->dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
list_del(&ucmd->hash_list_entry);
|
||||
spin_unlock_irqrestore(&ucmd->dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_unlock_irqrestore(&ucmd->dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
TRACE_DBG("Removed ucmd %p, h=%d", ucmd, ucmd->h);
|
||||
return;
|
||||
@@ -1073,7 +1077,7 @@ static void dev_user_add_to_ready(struct scst_user_cmd *ucmd)
|
||||
if (ucmd->cmd)
|
||||
do_wake |= ucmd->cmd->preprocessing_only;
|
||||
|
||||
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
ucmd->this_state_unjammed = 0;
|
||||
|
||||
@@ -1118,10 +1122,10 @@ static void dev_user_add_to_ready(struct scst_user_cmd *ucmd)
|
||||
|
||||
if (do_wake) {
|
||||
TRACE_DBG("Waking up dev %p", dev);
|
||||
wake_up(&dev->cmd_lists.cmd_list_waitQ);
|
||||
wake_up(&dev->udev_cmd_threads.cmd_list_waitQ);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_unlock_irqrestore(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -1504,7 +1508,7 @@ static int dev_user_process_reply(struct scst_user_dev *dev,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
ucmd = __ucmd_find_hash(dev, reply->cmd_h);
|
||||
if (unlikely(ucmd == NULL)) {
|
||||
@@ -1549,7 +1553,7 @@ static int dev_user_process_reply(struct scst_user_dev *dev,
|
||||
ucmd->sent_to_user = 0;
|
||||
|
||||
unlock_process:
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
switch (state) {
|
||||
case UCMD_STATE_PARSING:
|
||||
@@ -1602,11 +1606,11 @@ out_wrong_state:
|
||||
dev_user_unjam_cmd(ucmd, 0, NULL);
|
||||
|
||||
out_unlock_put:
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
goto out_put;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1682,7 +1686,7 @@ static int dev_user_get_ext_cdb(struct file *file, void __user *arg)
|
||||
|
||||
TRACE_BUFFER("Get ext cdb", &get, sizeof(get));
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
ucmd = __ucmd_find_hash(dev, get.cmd_h);
|
||||
if (unlikely(ucmd == NULL)) {
|
||||
@@ -1708,7 +1712,7 @@ static int dev_user_get_ext_cdb(struct file *file, void __user *arg)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
if (cmd == NULL)
|
||||
goto out_put;
|
||||
@@ -1739,27 +1743,27 @@ out:
|
||||
return res;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
static int dev_user_process_scst_commands(struct scst_user_dev *dev)
|
||||
__releases(&dev->cmd_lists.cmd_list_lock)
|
||||
__acquires(&dev->cmd_lists.cmd_list_lock)
|
||||
__releases(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
__acquires(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
while (!list_empty(&dev->cmd_lists.active_cmd_list)) {
|
||||
while (!list_empty(&dev->udev_cmd_threads.active_cmd_list)) {
|
||||
struct scst_cmd *cmd = list_entry(
|
||||
dev->cmd_lists.active_cmd_list.next, typeof(*cmd),
|
||||
dev->udev_cmd_threads.active_cmd_list.next, typeof(*cmd),
|
||||
cmd_list_entry);
|
||||
TRACE_DBG("Deleting cmd %p from active cmd list", cmd);
|
||||
list_del(&cmd->cmd_list_entry);
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
scst_process_active_cmd(cmd, false);
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
res++;
|
||||
}
|
||||
|
||||
@@ -1767,10 +1771,10 @@ static int dev_user_process_scst_commands(struct scst_user_dev *dev)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Called under cmd_lists.cmd_list_lock and IRQ off */
|
||||
/* Called under udev_cmd_threads.cmd_list_lock and IRQ off */
|
||||
static struct scst_user_cmd *__dev_user_get_next_cmd(struct list_head *cmd_list)
|
||||
__releases(&dev->cmd_lists.cmd_list_lock)
|
||||
__acquires(&dev->cmd_lists.cmd_list_lock)
|
||||
__releases(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
__acquires(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
{
|
||||
struct scst_user_cmd *u;
|
||||
|
||||
@@ -1792,7 +1796,7 @@ again:
|
||||
|
||||
EXTRACHECKS_BUG_ON(u->jammed);
|
||||
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
rc = scst_check_local_events(u->cmd);
|
||||
if (unlikely(rc != 0)) {
|
||||
@@ -1804,11 +1808,11 @@ again:
|
||||
* !! already freed !!
|
||||
*/
|
||||
spin_lock_irq(
|
||||
&dev->cmd_lists.cmd_list_lock);
|
||||
&dev->udev_cmd_threads.cmd_list_lock);
|
||||
goto again;
|
||||
}
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
} else if (unlikely(test_bit(SCST_CMD_ABORTED,
|
||||
&u->cmd->cmd_flags))) {
|
||||
switch (u->state) {
|
||||
@@ -1828,16 +1832,16 @@ again:
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline int test_cmd_lists(struct scst_user_dev *dev)
|
||||
static inline int test_cmd_threads(struct scst_user_dev *dev)
|
||||
{
|
||||
int res = !list_empty(&dev->cmd_lists.active_cmd_list) ||
|
||||
int res = !list_empty(&dev->udev_cmd_threads.active_cmd_list) ||
|
||||
!list_empty(&dev->ready_cmd_list) ||
|
||||
!dev->blocking || dev->cleanup_done ||
|
||||
signal_pending(current);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Called under cmd_lists.cmd_list_lock and IRQ off */
|
||||
/* Called under udev_cmd_threads.cmd_list_lock and IRQ off */
|
||||
static int dev_user_get_next_cmd(struct scst_user_dev *dev,
|
||||
struct scst_user_cmd **ucmd)
|
||||
{
|
||||
@@ -1849,20 +1853,20 @@ static int dev_user_get_next_cmd(struct scst_user_dev *dev,
|
||||
init_waitqueue_entry(&wait, current);
|
||||
|
||||
while (1) {
|
||||
if (!test_cmd_lists(dev)) {
|
||||
if (!test_cmd_threads(dev)) {
|
||||
add_wait_queue_exclusive_head(
|
||||
&dev->cmd_lists.cmd_list_waitQ,
|
||||
&dev->udev_cmd_threads.cmd_list_waitQ,
|
||||
&wait);
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (test_cmd_lists(dev))
|
||||
if (test_cmd_threads(dev))
|
||||
break;
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
schedule();
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&dev->cmd_lists.cmd_list_waitQ,
|
||||
remove_wait_queue(&dev->udev_cmd_threads.cmd_list_waitQ,
|
||||
&wait);
|
||||
}
|
||||
|
||||
@@ -1948,7 +1952,7 @@ static int dev_user_reply_get_cmd(struct file *file, void __user *arg)
|
||||
|
||||
kmem_cache_free(user_get_cmd_cachep, cmd);
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
again:
|
||||
res = dev_user_get_next_cmd(dev, &ucmd);
|
||||
if (res == 0) {
|
||||
@@ -1963,7 +1967,7 @@ again:
|
||||
/* Oops, this ucmd is already being destroyed. Retry. */
|
||||
goto again;
|
||||
}
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
EXTRACHECKS_BUG_ON(ucmd->user_cmd_payload_len == 0);
|
||||
|
||||
@@ -1977,10 +1981,10 @@ again:
|
||||
"%p back to head of ready cmd list", rc, ucmd);
|
||||
res = -EFAULT;
|
||||
/* Requeue ucmd back */
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
list_add(&ucmd->ready_cmd_list_entry,
|
||||
&dev->ready_cmd_list);
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
}
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
else
|
||||
@@ -1988,7 +1992,7 @@ again:
|
||||
#endif
|
||||
ucmd_put(ucmd);
|
||||
} else
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
out_up:
|
||||
up_read(&dev->dev_rwsem);
|
||||
@@ -2118,30 +2122,30 @@ static unsigned int dev_user_poll(struct file *file, poll_table *wait)
|
||||
down_read(&dev->dev_rwsem);
|
||||
mutex_unlock(&dev_priv_mutex);
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
if (!list_empty(&dev->ready_cmd_list) ||
|
||||
!list_empty(&dev->cmd_lists.active_cmd_list)) {
|
||||
!list_empty(&dev->udev_cmd_threads.active_cmd_list)) {
|
||||
res |= POLLIN | POLLRDNORM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
TRACE_DBG("Before poll_wait() (dev %s)", dev->name);
|
||||
poll_wait(file, &dev->cmd_lists.cmd_list_waitQ, wait);
|
||||
poll_wait(file, &dev->udev_cmd_threads.cmd_list_waitQ, wait);
|
||||
TRACE_DBG("After poll_wait() (dev %s)", dev->name);
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
if (!list_empty(&dev->ready_cmd_list) ||
|
||||
!list_empty(&dev->cmd_lists.active_cmd_list)) {
|
||||
!list_empty(&dev->udev_cmd_threads.active_cmd_list)) {
|
||||
res |= POLLIN | POLLRDNORM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
up_read(&dev->dev_rwsem);
|
||||
|
||||
@@ -2151,12 +2155,13 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* Called under cmd_lists.cmd_list_lock, but can drop it inside, then reacquire.
|
||||
* Called under udev_cmd_threads.cmd_list_lock, but can drop it inside,
|
||||
* then reacquire.
|
||||
*/
|
||||
static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
|
||||
unsigned long *flags)
|
||||
__releases(&dev->cmd_lists.cmd_list_lock)
|
||||
__acquires(&dev->cmd_lists.cmd_list_lock)
|
||||
__releases(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
__acquires(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
{
|
||||
int state = ucmd->state;
|
||||
struct scst_user_dev *dev = ucmd->dev;
|
||||
@@ -2189,16 +2194,16 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
|
||||
|
||||
TRACE_MGMT_DBG("Adding ucmd %p to active list", ucmd);
|
||||
list_add(&ucmd->cmd->cmd_list_entry,
|
||||
&ucmd->cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&ucmd->dev->cmd_lists.cmd_list_waitQ);
|
||||
&ucmd->cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&ucmd->cmd->cmd_threads->cmd_list_waitQ);
|
||||
break;
|
||||
|
||||
case UCMD_STATE_EXECING:
|
||||
if (flags != NULL)
|
||||
spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock,
|
||||
spin_unlock_irqrestore(&dev->udev_cmd_threads.cmd_list_lock,
|
||||
*flags);
|
||||
else
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
TRACE_MGMT_DBG("EXEC: unjamming ucmd %p", ucmd);
|
||||
|
||||
@@ -2217,10 +2222,10 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
|
||||
/* !! At this point cmd and ucmd can be already freed !! */
|
||||
|
||||
if (flags != NULL)
|
||||
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock,
|
||||
spin_lock_irqsave(&dev->udev_cmd_threads.cmd_list_lock,
|
||||
*flags);
|
||||
else
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
break;
|
||||
|
||||
case UCMD_STATE_ON_FREEING:
|
||||
@@ -2229,10 +2234,10 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
|
||||
case UCMD_STATE_ATTACH_SESS:
|
||||
case UCMD_STATE_DETACH_SESS:
|
||||
if (flags != NULL)
|
||||
spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock,
|
||||
spin_unlock_irqrestore(&dev->udev_cmd_threads.cmd_list_lock,
|
||||
*flags);
|
||||
else
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
switch (state) {
|
||||
case UCMD_STATE_ON_FREEING:
|
||||
@@ -2255,10 +2260,10 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
|
||||
}
|
||||
|
||||
if (flags != NULL)
|
||||
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock,
|
||||
spin_lock_irqsave(&dev->udev_cmd_threads.cmd_list_lock,
|
||||
*flags);
|
||||
else
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2273,8 +2278,8 @@ out:
|
||||
}
|
||||
|
||||
static int dev_user_unjam_dev(struct scst_user_dev *dev)
|
||||
__releases(&dev->cmd_lists.cmd_list_lock)
|
||||
__acquires(&dev->cmd_lists.cmd_list_lock)
|
||||
__releases(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
__acquires(&dev->udev_cmd_threads.cmd_list_lock)
|
||||
{
|
||||
int i, res = 0;
|
||||
struct scst_user_cmd *ucmd;
|
||||
@@ -2286,7 +2291,7 @@ static int dev_user_unjam_dev(struct scst_user_dev *dev)
|
||||
sgv_pool_flush(dev->pool);
|
||||
sgv_pool_flush(dev->pool_clust);
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
repeat:
|
||||
for (i = 0; i < (int)ARRAY_SIZE(dev->ucmd_hash); i++) {
|
||||
@@ -2306,9 +2311,9 @@ repeat:
|
||||
|
||||
dev_user_unjam_cmd(ucmd, 0, NULL);
|
||||
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
ucmd_put(ucmd);
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
goto repeat;
|
||||
}
|
||||
@@ -2317,7 +2322,7 @@ repeat:
|
||||
if (dev_user_process_scst_commands(dev) != 0)
|
||||
goto repeat;
|
||||
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
@@ -2359,7 +2364,7 @@ static void dev_user_abort_ready_commands(struct scst_user_dev *dev)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
again:
|
||||
list_for_each_entry(ucmd, &dev->ready_cmd_list, ready_cmd_list_entry) {
|
||||
if ((ucmd->cmd != NULL) && !ucmd->seen_by_user &&
|
||||
@@ -2376,7 +2381,7 @@ again:
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_unlock_irqrestore(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -2489,7 +2494,6 @@ static int dev_user_attach(struct scst_device *sdev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdev->p_cmd_lists = &dev->cmd_lists;
|
||||
sdev->dh_priv = dev;
|
||||
sdev->tst = dev->tst;
|
||||
sdev->queue_alg = dev->queue_alg;
|
||||
@@ -2536,7 +2540,7 @@ static int dev_user_process_reply_sess(struct scst_user_cmd *ucmd, int status)
|
||||
|
||||
TRACE_MGMT_DBG("ucmd %p, cmpl %p, status %d", ucmd, ucmd->cmpl, status);
|
||||
|
||||
spin_lock_irqsave(&ucmd->dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&ucmd->dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
if (ucmd->state == UCMD_STATE_ATTACH_SESS) {
|
||||
TRACE_MGMT_DBG("%s", "ATTACH_SESS finished");
|
||||
@@ -2549,7 +2553,7 @@ static int dev_user_process_reply_sess(struct scst_user_cmd *ucmd, int status)
|
||||
if (ucmd->cmpl != NULL)
|
||||
complete_all(ucmd->cmpl);
|
||||
|
||||
spin_unlock_irqrestore(&ucmd->dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_unlock_irqrestore(&ucmd->dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
ucmd_put(ucmd);
|
||||
|
||||
@@ -2567,6 +2571,8 @@ static int dev_user_attach_tgt(struct scst_tgt_dev *tgt_dev)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tgt_dev->active_cmd_threads = &dev->udev_cmd_threads;
|
||||
|
||||
/*
|
||||
* We can't replace tgt_dev->pool, because it can be used to allocate
|
||||
* memory for SCST local commands, like REPORT LUNS, where there is no
|
||||
@@ -2621,9 +2627,9 @@ static int dev_user_attach_tgt(struct scst_tgt_dev *tgt_dev)
|
||||
|
||||
sBUG_ON(irqs_disabled());
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
ucmd->cmpl = NULL;
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
ucmd_put(ucmd);
|
||||
|
||||
@@ -2801,9 +2807,6 @@ static int dev_user_register_dev(struct file *file,
|
||||
}
|
||||
|
||||
init_rwsem(&dev->dev_rwsem);
|
||||
spin_lock_init(&dev->cmd_lists.cmd_list_lock);
|
||||
INIT_LIST_HEAD(&dev->cmd_lists.active_cmd_list);
|
||||
init_waitqueue_head(&dev->cmd_lists.cmd_list_waitQ);
|
||||
INIT_LIST_HEAD(&dev->ready_cmd_list);
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
TRACE_DBG("%s", "Non-blocking operations");
|
||||
@@ -2813,6 +2816,8 @@ static int dev_user_register_dev(struct file *file,
|
||||
for (i = 0; i < (int)ARRAY_SIZE(dev->ucmd_hash); i++)
|
||||
INIT_LIST_HEAD(&dev->ucmd_hash[i]);
|
||||
|
||||
scst_init_threads(&dev->udev_cmd_threads);
|
||||
|
||||
strlcpy(dev->name, dev_desc->name, sizeof(dev->name)-1);
|
||||
|
||||
scst_init_mem_lim(&dev->udev_mem_lim);
|
||||
@@ -2980,7 +2985,7 @@ static int dev_user_unregister_dev(struct file *file)
|
||||
}
|
||||
|
||||
dev->blocking = 0;
|
||||
wake_up_all(&dev->cmd_lists.cmd_list_waitQ);
|
||||
wake_up_all(&dev->udev_cmd_threads.cmd_list_waitQ);
|
||||
|
||||
down_write(&dev->dev_rwsem);
|
||||
file->private_data = NULL;
|
||||
@@ -3333,7 +3338,7 @@ static int dev_user_exit_dev(struct scst_user_dev *dev)
|
||||
spin_unlock(&dev_list_lock);
|
||||
|
||||
dev->blocking = 0;
|
||||
wake_up_all(&dev->cmd_lists.cmd_list_waitQ);
|
||||
wake_up_all(&dev->udev_cmd_threads.cmd_list_waitQ);
|
||||
|
||||
spin_lock(&cleanup_lock);
|
||||
list_add_tail(&dev->cleanup_list_entry, &cleanup_list);
|
||||
@@ -3352,13 +3357,15 @@ static int dev_user_exit_dev(struct scst_user_dev *dev)
|
||||
dev->cleanup_done = 1;
|
||||
|
||||
wake_up(&cleanup_list_waitQ);
|
||||
wake_up(&dev->cmd_lists.cmd_list_waitQ);
|
||||
wake_up(&dev->udev_cmd_threads.cmd_list_waitQ);
|
||||
|
||||
wait_for_completion(&dev->cleanup_cmpl);
|
||||
|
||||
sgv_pool_del(dev->pool_clust);
|
||||
sgv_pool_del(dev->pool);
|
||||
|
||||
scst_deinit_threads(&dev->udev_cmd_threads);
|
||||
|
||||
TRACE_MGMT_DBG("Releasing completed (dev %p)", dev);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
@@ -3410,7 +3417,7 @@ static int dev_user_process_cleanup(struct scst_user_dev *dev)
|
||||
TRACE_ENTRY();
|
||||
|
||||
sBUG_ON(dev->blocking);
|
||||
wake_up_all(&dev->cmd_lists.cmd_list_waitQ); /* just in case */
|
||||
wake_up_all(&dev->udev_cmd_threads.cmd_list_waitQ); /* just in case */
|
||||
|
||||
while (1) {
|
||||
int rc1;
|
||||
@@ -3421,13 +3428,13 @@ static int dev_user_process_cleanup(struct scst_user_dev *dev)
|
||||
if ((rc1 == 0) && (rc == -EAGAIN) && dev->cleanup_done)
|
||||
break;
|
||||
|
||||
spin_lock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_lock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
rc = dev_user_get_next_cmd(dev, &ucmd);
|
||||
if (rc == 0)
|
||||
dev_user_unjam_cmd(ucmd, 1, NULL);
|
||||
|
||||
spin_unlock_irq(&dev->cmd_lists.cmd_list_lock);
|
||||
spin_unlock_irq(&dev->udev_cmd_threads.cmd_list_lock);
|
||||
|
||||
if (rc == -EAGAIN) {
|
||||
if (!dev->cleanup_done) {
|
||||
@@ -3478,7 +3485,7 @@ static ssize_t dev_user_sysfs_commands_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
udev = (struct scst_user_dev *)dev->dh_priv;
|
||||
|
||||
spin_lock_irqsave(&udev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&udev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
for (i = 0; i < (int)ARRAY_SIZE(udev->ucmd_hash); i++) {
|
||||
struct list_head *head = &udev->ucmd_hash[i];
|
||||
struct scst_user_cmd *ucmd;
|
||||
@@ -3501,7 +3508,7 @@ static ssize_t dev_user_sysfs_commands_show(struct kobject *kobj,
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&udev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_unlock_irqrestore(&udev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
@@ -3525,7 +3532,7 @@ static int dev_user_read_proc(struct seq_file *seq, struct scst_dev_type *dev_ty
|
||||
list_for_each_entry(dev, &dev_list, dev_list_entry) {
|
||||
int i;
|
||||
seq_printf(seq, "Device %s commands:\n", dev->name);
|
||||
spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
for (i = 0; i < (int)ARRAY_SIZE(dev->ucmd_hash); i++) {
|
||||
struct list_head *head = &dev->ucmd_hash[i];
|
||||
struct scst_user_cmd *ucmd;
|
||||
@@ -3539,7 +3546,7 @@ static int dev_user_read_proc(struct seq_file *seq, struct scst_dev_type *dev_ty
|
||||
ucmd->aborted, ucmd->jammed, ucmd->cmd);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock, flags);
|
||||
spin_unlock_irqrestore(&dev->udev_cmd_threads.cmd_list_lock, flags);
|
||||
}
|
||||
spin_unlock(&dev_list_lock);
|
||||
|
||||
|
||||
@@ -214,11 +214,15 @@ struct scst_vdisk_dev {
|
||||
must be <= SCSI Model + 1 */
|
||||
char *filename; /* File name, protected by
|
||||
scst_mutex and suspended activities */
|
||||
unsigned int t10_dev_id_set:1; /* true if t10_dev_id manually set */
|
||||
char t10_dev_id[16+8+2]; /* T10 device ID */
|
||||
char usn[MAX_USN_LEN];
|
||||
struct scst_device *dev;
|
||||
struct list_head vdev_list_entry;
|
||||
|
||||
int threads_num;
|
||||
enum scst_dev_type_threads_pool_type threads_pool_type;
|
||||
|
||||
struct mutex vdev_sysfs_mutex;
|
||||
struct scst_dev_type *vdev_devt;
|
||||
};
|
||||
@@ -443,7 +447,8 @@ static struct scst_dev_type vdisk_file_devtype = {
|
||||
.del_device = vdisk_del_device,
|
||||
.dev_attrs = vdisk_fileio_attrs,
|
||||
.add_device_parameters_help = "filename, blocksize, write_through, "
|
||||
"nv_cache, o_direct, read_only, removable",
|
||||
"nv_cache, o_direct, read_only, removable, threads_num, "
|
||||
"threads_pool_type",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -479,7 +484,7 @@ static struct scst_dev_type vdisk_blk_devtype = {
|
||||
.del_device = vdisk_del_device,
|
||||
.dev_attrs = vdisk_blockio_attrs,
|
||||
.add_device_parameters_help = "filename, blocksize, read_only, "
|
||||
"removable",
|
||||
"removable, threads_num, threads_pool_type",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -512,7 +517,8 @@ static struct scst_dev_type vdisk_null_devtype = {
|
||||
.add_device = vdisk_add_nullio_device,
|
||||
.del_device = vdisk_del_device,
|
||||
.dev_attrs = vdisk_nullio_attrs,
|
||||
.add_device_parameters_help = "blocksize, read_only, removable",
|
||||
.add_device_parameters_help = "blocksize, read_only, removable, "
|
||||
"threads_num, threads_pool_type",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -546,6 +552,7 @@ static struct scst_dev_type vcdrom_devtype = {
|
||||
.add_device = vcdrom_add_device,
|
||||
.del_device = vcdrom_del_device,
|
||||
.dev_attrs = vcdrom_attrs,
|
||||
.add_device_parameters_help = "threads_num, threads_pool_type",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -693,6 +700,8 @@ static int vdisk_attach(struct scst_device *dev)
|
||||
virt_dev->dev = dev;
|
||||
|
||||
dev->rd_only = virt_dev->rd_only;
|
||||
dev->threads_num = virt_dev->threads_num;
|
||||
dev->threads_pool_type = virt_dev->threads_pool_type;
|
||||
|
||||
if (!virt_dev->cdrom_empty) {
|
||||
if (virt_dev->nullio)
|
||||
@@ -2952,6 +2961,8 @@ static int vdev_create(struct scst_dev_type *devt,
|
||||
spin_lock_init(&virt_dev->flags_lock);
|
||||
mutex_init(&virt_dev->vdev_sysfs_mutex);
|
||||
virt_dev->vdev_devt = devt;
|
||||
virt_dev->threads_num = devt->threads_num;
|
||||
virt_dev->threads_pool_type = devt->threads_pool_type;
|
||||
|
||||
virt_dev->rd_only = DEF_RD_ONLY;
|
||||
virt_dev->removable = DEF_REMOVABLE;
|
||||
@@ -3018,24 +3029,15 @@ static struct scst_vdisk_dev *vdev_find(const char *name)
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
|
||||
/* scst_vdisk_mutex supposed to be held */
|
||||
static int vdev_fileio_add_device(const char *device_name, char *params)
|
||||
static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
|
||||
char *params, const char *allowed_params[])
|
||||
{
|
||||
int res = 0;
|
||||
unsigned long val;
|
||||
char *param, *p, *pp;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = vdev_create(&vdisk_file_devtype, device_name, &virt_dev);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
virt_dev->wt_flag = DEF_WRITE_THROUGH;
|
||||
virt_dev->nv_cache = DEF_NV_CACHE;
|
||||
virt_dev->o_direct_flag = DEF_O_DIRECT;
|
||||
|
||||
while (1) {
|
||||
param = scst_get_next_token_str(¶ms);
|
||||
if (param == NULL)
|
||||
@@ -3044,49 +3046,79 @@ static int vdev_fileio_add_device(const char *device_name, char *params)
|
||||
p = scst_get_next_lexem(¶m);
|
||||
if (*p == '\0') {
|
||||
PRINT_ERROR("Syntax error at %s (device %s)",
|
||||
param, device_name);
|
||||
param, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pp = scst_get_next_lexem(¶m);
|
||||
if (*pp == '\0') {
|
||||
PRINT_ERROR("Parameter %s value missed for device %s",
|
||||
p, device_name);
|
||||
p, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (scst_get_next_lexem(¶m)[0] != '\0') {
|
||||
PRINT_ERROR("Too many parameter's %s values (device %s)",
|
||||
p, device_name);
|
||||
p, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (allowed_params != NULL) {
|
||||
const char **a = allowed_params;
|
||||
bool allowed = false;
|
||||
|
||||
while (*a != NULL) {
|
||||
if (!strcasecmp(*a, p)) {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
a++;
|
||||
}
|
||||
|
||||
if (!allowed) {
|
||||
PRINT_ERROR("Unknown parameter %s (device %s)", p,
|
||||
virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcasecmp("filename", p)) {
|
||||
if (*pp != '/') {
|
||||
PRINT_ERROR("Filename %s must be global "
|
||||
"(device %s)", pp, device_name);
|
||||
"(device %s)", pp, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
goto out;
|
||||
}
|
||||
|
||||
virt_dev->filename = kstrdup(pp, GFP_KERNEL);
|
||||
if (virt_dev->filename == NULL) {
|
||||
PRINT_ERROR("Unable to duplicate file name %s "
|
||||
"(device %s)", pp, device_name);
|
||||
"(device %s)", pp, virt_dev->name);
|
||||
res = -ENOMEM;
|
||||
goto out_destroy;
|
||||
goto out;
|
||||
}
|
||||
continue;
|
||||
} else if (!strcasecmp("threads_pool_type", p)) {
|
||||
virt_dev->threads_pool_type = scst_parse_threads_pool_type(pp,
|
||||
strlen(pp));
|
||||
if (virt_dev->threads_pool_type == SCST_THREADS_POOL_TYPE_INVALID) {
|
||||
res = virt_dev->threads_pool_type;
|
||||
goto out;
|
||||
}
|
||||
TRACE_DBG("threads_pool_type %d",
|
||||
virt_dev->threads_pool_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = strict_strtoul(pp, 0, &val);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("strict_strtoul() for %s failed: %d "
|
||||
"(device %s)", pp, res, device_name);
|
||||
goto out_destroy;
|
||||
"(device %s)", pp, res, virt_dev->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strcasecmp("write_through", p)) {
|
||||
@@ -3102,7 +3134,7 @@ static int vdev_fileio_add_device(const char *device_name, char *params)
|
||||
#else
|
||||
PRINT_INFO("O_DIRECT flag doesn't currently"
|
||||
" work, ignoring it, use fileio_tgt "
|
||||
"in O_DIRECT mode instead (device %s)", device_name);
|
||||
"in O_DIRECT mode instead (device %s)", virt_dev->name);
|
||||
#endif
|
||||
} else if (!strcasecmp("read_only", p)) {
|
||||
virt_dev->rd_only = val;
|
||||
@@ -3110,25 +3142,53 @@ static int vdev_fileio_add_device(const char *device_name, char *params)
|
||||
} else if (!strcasecmp("removable", p)) {
|
||||
virt_dev->removable = val;
|
||||
TRACE_DBG("REMOVABLE %d", virt_dev->removable);
|
||||
} else if (!strcasecmp("threads_num", p)) {
|
||||
virt_dev->threads_num = val;
|
||||
TRACE_DBG("threads_num %d", virt_dev->threads_num);
|
||||
} else if (!strcasecmp("blocksize", p)) {
|
||||
virt_dev->block_size = val;
|
||||
virt_dev->block_shift = scst_calc_block_shift(
|
||||
virt_dev->block_size);
|
||||
if (virt_dev->block_shift < 9) {
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
goto out;
|
||||
}
|
||||
TRACE_DBG("block_size %d, block_shift %d",
|
||||
virt_dev->block_size,
|
||||
virt_dev->block_shift);
|
||||
} else {
|
||||
PRINT_ERROR("Unknown parameter %s (device %s)", p,
|
||||
device_name);
|
||||
virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_vdisk_mutex supposed to be held */
|
||||
static int vdev_fileio_add_device(const char *device_name, char *params)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = vdev_create(&vdisk_file_devtype, device_name, &virt_dev);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
virt_dev->wt_flag = DEF_WRITE_THROUGH;
|
||||
virt_dev->nv_cache = DEF_NV_CACHE;
|
||||
virt_dev->o_direct_flag = DEF_O_DIRECT;
|
||||
|
||||
res = vdev_parse_add_dev_params(virt_dev, params, NULL);
|
||||
if (res != 0)
|
||||
goto out_destroy;
|
||||
|
||||
if (virt_dev->rd_only && (virt_dev->wt_flag || virt_dev->nv_cache)) {
|
||||
PRINT_ERROR("Write options on read only device %s",
|
||||
virt_dev->name);
|
||||
@@ -3172,8 +3232,8 @@ out_destroy:
|
||||
static int vdev_blockio_add_device(const char *device_name, char *params)
|
||||
{
|
||||
int res = 0;
|
||||
unsigned long val;
|
||||
char *param, *p, *pp;
|
||||
const char *allowed_params[] = { "filename", "threads_pool_type",
|
||||
"read_only", "removable", "threads_num", "blocksize", NULL };
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -3184,83 +3244,9 @@ static int vdev_blockio_add_device(const char *device_name, char *params)
|
||||
|
||||
virt_dev->blockio = 1;
|
||||
|
||||
while (1) {
|
||||
param = scst_get_next_token_str(¶ms);
|
||||
if (param == NULL)
|
||||
break;
|
||||
|
||||
p = scst_get_next_lexem(¶m);
|
||||
if (*p == '\0') {
|
||||
PRINT_ERROR("Syntax error at %s (device %s)",
|
||||
param, device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
pp = scst_get_next_lexem(¶m);
|
||||
if (*pp == '\0') {
|
||||
PRINT_ERROR("Parameter %s value missed for device %s",
|
||||
p, device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
if (scst_get_next_lexem(¶m)[0] != '\0') {
|
||||
PRINT_ERROR("Too many parameter's %s values (device %s)",
|
||||
p, device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
if (!strcasecmp("filename", p)) {
|
||||
if (*pp != '/') {
|
||||
PRINT_ERROR("Filename %s must be global "
|
||||
"(device %s)", pp, device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
virt_dev->filename = kstrdup(pp, GFP_KERNEL);
|
||||
if (virt_dev->filename == NULL) {
|
||||
PRINT_ERROR("Unable to duplicate file name %s "
|
||||
"(device %s)", pp, device_name);
|
||||
res = -ENOMEM;
|
||||
goto out_destroy;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
res = strict_strtoul(pp, 0, &val);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("strict_strtoul() for %s failed: %d "
|
||||
"(device %s)", pp, res, device_name);
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
if (!strcasecmp("read_only", p)) {
|
||||
virt_dev->rd_only = val;
|
||||
TRACE_DBG("READ ONLY %d", virt_dev->rd_only);
|
||||
} else if (!strcasecmp("removable", p)) {
|
||||
virt_dev->removable = val;
|
||||
TRACE_DBG("REMOVABLE %d", virt_dev->removable);
|
||||
} else if (!strcasecmp("blocksize", p)) {
|
||||
virt_dev->block_size = val;
|
||||
virt_dev->block_shift = scst_calc_block_shift(
|
||||
virt_dev->block_size);
|
||||
if (virt_dev->block_shift < 9) {
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
TRACE_DBG("block_size %d, block_shift %d",
|
||||
virt_dev->block_size,
|
||||
virt_dev->block_shift);
|
||||
} else {
|
||||
PRINT_ERROR("Unknown parameter %s (device %s)", p,
|
||||
device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
}
|
||||
res = vdev_parse_add_dev_params(virt_dev, params, allowed_params);
|
||||
if (res != 0)
|
||||
goto out_destroy;
|
||||
|
||||
if (virt_dev->filename == NULL) {
|
||||
PRINT_ERROR("File name required (device %s)", virt_dev->name);
|
||||
@@ -3298,8 +3284,8 @@ out_destroy:
|
||||
static int vdev_nullio_add_device(const char *device_name, char *params)
|
||||
{
|
||||
int res = 0;
|
||||
unsigned long val;
|
||||
char *param, *p, *pp;
|
||||
const char *allowed_params[] = { "threads_pool_type",
|
||||
"read_only", "removable", "threads_num", "blocksize", NULL };
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -3310,65 +3296,9 @@ static int vdev_nullio_add_device(const char *device_name, char *params)
|
||||
|
||||
virt_dev->nullio = 1;
|
||||
|
||||
while (1) {
|
||||
param = scst_get_next_token_str(¶ms);
|
||||
if (param == NULL)
|
||||
break;
|
||||
|
||||
p = scst_get_next_lexem(¶m);
|
||||
if (*p == '\0') {
|
||||
PRINT_ERROR("Syntax error at %s (device %s)",
|
||||
param, device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
pp = scst_get_next_lexem(¶m);
|
||||
if (*pp == '\0') {
|
||||
PRINT_ERROR("Parameter %s value missed for device %s",
|
||||
p, device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
if (scst_get_next_lexem(¶m)[0] != '\0') {
|
||||
PRINT_ERROR("Too many parameter's %s values (device %s)",
|
||||
p, device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
res = strict_strtoul(pp, 0, &val);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("strict_strtoul() for %s failed: %d "
|
||||
"(device %s)", pp, res, device_name);
|
||||
goto out_destroy;
|
||||
}
|
||||
|
||||
if (!strcasecmp("read_only", p)) {
|
||||
virt_dev->rd_only = val;
|
||||
TRACE_DBG("READ ONLY %d", virt_dev->rd_only);
|
||||
} else if (!strcasecmp("removable", p)) {
|
||||
virt_dev->removable = val;
|
||||
TRACE_DBG("REMOVABLE %d", virt_dev->removable);
|
||||
} else if (!strcasecmp("blocksize", p)) {
|
||||
virt_dev->block_size = val;
|
||||
virt_dev->block_shift = scst_calc_block_shift(
|
||||
virt_dev->block_size);
|
||||
if (virt_dev->block_shift < 9) {
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
TRACE_DBG("block_size %d, block_shift %d",
|
||||
virt_dev->block_size,
|
||||
virt_dev->block_shift);
|
||||
} else {
|
||||
PRINT_ERROR("Unknown parameter %s (device %s)", p,
|
||||
device_name);
|
||||
res = -EINVAL;
|
||||
goto out_destroy;
|
||||
}
|
||||
}
|
||||
res = vdev_parse_add_dev_params(virt_dev, params, allowed_params);
|
||||
if (res != 0)
|
||||
goto out_destroy;
|
||||
|
||||
list_add_tail(&virt_dev->vdev_list_entry, &vdev_list);
|
||||
|
||||
@@ -3512,19 +3442,12 @@ out:
|
||||
static int __vcdrom_add_device(const char *device_name, char *params)
|
||||
{
|
||||
int res = 0;
|
||||
char *p;
|
||||
const char *allowed_params[] = { "threads_pool_type",
|
||||
"threads_num", NULL };
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
p = scst_get_next_token_str(¶ms);
|
||||
if (p != NULL) {
|
||||
PRINT_ERROR("No parameters extected for device %s",
|
||||
device_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = vdev_create(&vcdrom_devtype, device_name, &virt_dev);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
@@ -3536,6 +3459,10 @@ static int __vcdrom_add_device(const char *device_name, char *params)
|
||||
virt_dev->block_size = DEF_CDROM_BLOCKSIZE;
|
||||
virt_dev->block_shift = DEF_CDROM_BLOCKSIZE_SHIFT;
|
||||
|
||||
res = vdev_parse_add_dev_params(virt_dev, params, allowed_params);
|
||||
if (res != 0)
|
||||
goto out_destroy;
|
||||
|
||||
list_add_tail(&virt_dev->vdev_list_entry, &vdev_list);
|
||||
|
||||
vdisk_report_registering(virt_dev);
|
||||
@@ -3557,6 +3484,7 @@ out:
|
||||
out_del:
|
||||
list_del(&virt_dev->vdev_list_entry);
|
||||
|
||||
out_destroy:
|
||||
vdev_destroy(virt_dev);
|
||||
goto out;
|
||||
}
|
||||
@@ -4007,6 +3935,9 @@ static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj,
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
virt_dev->t10_dev_id_set = 1;
|
||||
|
||||
res = count;
|
||||
|
||||
PRINT_INFO("T10 device id for device %s changed to %s", virt_dev->name,
|
||||
@@ -4032,7 +3963,8 @@ static ssize_t vdev_sysfs_t10_dev_id_show(struct kobject *kobj,
|
||||
virt_dev = (struct scst_vdisk_dev *)dev->dh_priv;
|
||||
|
||||
read_lock_bh(&vdisk_t10_dev_id_rwlock);
|
||||
pos = sprintf(buf, "%s\n", virt_dev->t10_dev_id);
|
||||
pos = sprintf(buf, "%s\n%s", virt_dev->t10_dev_id,
|
||||
virt_dev->t10_dev_id_set ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
read_unlock_bh(&vdisk_t10_dev_id_rwlock);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
|
||||
@@ -562,12 +562,10 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
static void scst_tgt_retry_timer_fn(unsigned long arg);
|
||||
|
||||
#ifdef CONFIG_SCST_DEBUG_TM
|
||||
static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_acg_dev *acg_dev);
|
||||
static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev);
|
||||
static void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev);
|
||||
#else
|
||||
static inline void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_acg_dev *acg_dev) {}
|
||||
static inline void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev) {}
|
||||
static inline void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev) {}
|
||||
#endif /* CONFIG_SCST_DEBUG_TM */
|
||||
|
||||
@@ -1997,7 +1995,6 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
int res = 0;
|
||||
static int dev_num; /* protected by scst_mutex */
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2010,7 +2007,6 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
|
||||
}
|
||||
|
||||
dev->handler = &scst_null_devtype;
|
||||
dev->p_cmd_lists = &scst_main_cmd_lists;
|
||||
atomic_set(&dev->dev_cmd_count, 0);
|
||||
atomic_set(&dev->write_cmd_count, 0);
|
||||
scst_init_mem_lim(&dev->dev_mem_lim);
|
||||
@@ -2019,23 +2015,11 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
|
||||
INIT_LIST_HEAD(&dev->blocked_cmd_list);
|
||||
INIT_LIST_HEAD(&dev->dev_tgt_dev_list);
|
||||
INIT_LIST_HEAD(&dev->dev_acg_dev_list);
|
||||
INIT_LIST_HEAD(&dev->threads_list);
|
||||
init_waitqueue_head(&dev->on_dev_waitQ);
|
||||
dev->dev_double_ua_possible = 1;
|
||||
dev->queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
|
||||
dev->dev_num = dev_num++;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) && defined(SCST_IO_CONTEXT)
|
||||
#if defined(CONFIG_BLOCK)
|
||||
dev->dev_io_ctx = alloc_io_context(GFP_KERNEL, -1);
|
||||
if (dev->dev_io_ctx == NULL) {
|
||||
TRACE(TRACE_OUT_OF_MEM, "%s", "Failed to alloc dev IO context");
|
||||
res = -ENOMEM;
|
||||
kfree(dev);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
scst_init_threads(&dev->dev_cmd_threads);
|
||||
|
||||
*out_dev = dev;
|
||||
|
||||
@@ -2057,9 +2041,9 @@ void scst_free_device(struct scst_device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
kfree(dev->virt_name);
|
||||
__exit_io_context(dev->dev_io_ctx);
|
||||
scst_deinit_threads(&dev->dev_cmd_threads);
|
||||
|
||||
kfree(dev->virt_name);
|
||||
kfree(dev);
|
||||
|
||||
TRACE_EXIT();
|
||||
@@ -2284,6 +2268,227 @@ struct scst_acg *scst_tgt_find_acg(struct scst_tgt *tgt, const char *name)
|
||||
return acg_ret;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
static struct io_context *scst_find_shared_io_context(
|
||||
struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
struct io_context *res = NULL;
|
||||
struct scst_acg *acg = tgt_dev->acg_dev->acg;
|
||||
struct scst_tgt_dev *t;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
switch (acg->acg_mpio_type) {
|
||||
case SCST_ACG_MPIO_AUTO:
|
||||
if (tgt_dev->sess->initiator_name == NULL)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(t, &tgt_dev->dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if ((t == tgt_dev) ||
|
||||
(t->sess->initiator_name == NULL) ||
|
||||
(t->active_cmd_threads == NULL))
|
||||
continue;
|
||||
|
||||
TRACE_DBG("t name %s (tgt_dev name %s)",
|
||||
t->sess->initiator_name,
|
||||
tgt_dev->sess->initiator_name);
|
||||
|
||||
/* We check other ACG's as well */
|
||||
|
||||
if (strcmp(t->sess->initiator_name,
|
||||
tgt_dev->sess->initiator_name) == 0)
|
||||
goto found;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCST_ACG_MPIO_ENABLE:
|
||||
list_for_each_entry(t, &tgt_dev->dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if ((t == tgt_dev) || (t->active_cmd_threads == NULL))
|
||||
continue;
|
||||
|
||||
TRACE_DBG("t name %s (tgt_dev name %s)",
|
||||
t->sess->initiator_name,
|
||||
tgt_dev->sess->initiator_name);
|
||||
|
||||
goto found;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCST_ACG_MPIO_DISABLE:
|
||||
goto out;
|
||||
|
||||
default:
|
||||
PRINT_CRIT_ERROR("Unknown MPIO type %d (acg %s)",
|
||||
acg->acg_mpio_type, acg->acg_name);
|
||||
sBUG();
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES((unsigned long)res);
|
||||
return res;
|
||||
|
||||
found:
|
||||
if (t->active_cmd_threads == &scst_main_cmd_threads) {
|
||||
res = t->tgt_dev_cmd_threads.io_context;
|
||||
TRACE_DBG("Going to share async IO context %p (t %p, ini %s, "
|
||||
"dev %s, cmd_threads %p)", res, t,
|
||||
t->sess->initiator_name, t->dev->virt_name,
|
||||
&t->tgt_dev_cmd_threads);
|
||||
} else {
|
||||
res = t->active_cmd_threads->io_context;
|
||||
if (res == NULL) {
|
||||
TRACE_MGMT_DBG("IO context for t %p not yet "
|
||||
"initialized, waiting...", t);
|
||||
msleep(100);
|
||||
barrier();
|
||||
goto found;
|
||||
}
|
||||
TRACE_DBG("Going to share IO context %p (t %p, ini %s, "
|
||||
"dev %s, cmd_threads %p)", res, t,
|
||||
t->sess->initiator_name, t->dev->virt_name,
|
||||
t->active_cmd_threads);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
enum scst_dev_type_threads_pool_type scst_parse_threads_pool_type(const char *p,
|
||||
int len)
|
||||
{
|
||||
enum scst_dev_type_threads_pool_type res;
|
||||
|
||||
if (strncasecmp(p, SCST_THREADS_POOL_PER_INITIATOR_STR,
|
||||
min_t(int, strlen(SCST_THREADS_POOL_PER_INITIATOR_STR),
|
||||
len)) == 0)
|
||||
res = SCST_THREADS_POOL_PER_INITIATOR;
|
||||
else if (strncasecmp(p, SCST_THREADS_POOL_SHARED_STR,
|
||||
min_t(int, strlen(SCST_THREADS_POOL_SHARED_STR),
|
||||
len)) == 0)
|
||||
res = SCST_THREADS_POOL_SHARED;
|
||||
else {
|
||||
PRINT_ERROR("Unknown threads pool type %s", p);
|
||||
res = SCST_THREADS_POOL_TYPE_INVALID;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_parse_threads_pool_type);
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_device *dev = tgt_dev->dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (dev->threads_num <= 0) {
|
||||
tgt_dev->active_cmd_threads = &scst_main_cmd_threads;
|
||||
|
||||
if (dev->threads_num == 0) {
|
||||
struct io_context *shared_io_context;
|
||||
|
||||
shared_io_context = scst_find_shared_io_context(tgt_dev);
|
||||
if (shared_io_context != NULL) {
|
||||
TRACE_DBG("Linking async io context %p for "
|
||||
"shared tgt_dev %p (cmd_threads %p, "
|
||||
"dev %s)", shared_io_context, tgt_dev,
|
||||
&tgt_dev->tgt_dev_cmd_threads,
|
||||
tgt_dev->dev->virt_name);
|
||||
tgt_dev->tgt_dev_cmd_threads.io_context =
|
||||
ioc_task_link(shared_io_context);
|
||||
} else {
|
||||
/* Create new context */
|
||||
struct io_context *io_context = current->io_context;
|
||||
current->io_context = NULL;
|
||||
tgt_dev->tgt_dev_cmd_threads.io_context =
|
||||
ioc_task_link(get_io_context(GFP_KERNEL, -1));
|
||||
current->io_context = io_context;
|
||||
TRACE_DBG("Created async io context %p for "
|
||||
"not shared tgt_dev %p (cmd_threads %p, "
|
||||
"dev %s)", tgt_dev->tgt_dev_cmd_threads.io_context,
|
||||
tgt_dev, &tgt_dev->tgt_dev_cmd_threads,
|
||||
tgt_dev->dev->virt_name);
|
||||
}
|
||||
}
|
||||
|
||||
res = scst_add_threads(tgt_dev->active_cmd_threads, NULL, NULL,
|
||||
tgt_dev->sess->tgt->tgtt->threads_num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (dev->threads_pool_type) {
|
||||
case SCST_THREADS_POOL_PER_INITIATOR:
|
||||
{
|
||||
struct io_context *shared_io_context;
|
||||
|
||||
tgt_dev->active_cmd_threads = &tgt_dev->tgt_dev_cmd_threads;
|
||||
|
||||
shared_io_context = scst_find_shared_io_context(tgt_dev);
|
||||
if (shared_io_context != NULL) {
|
||||
TRACE_DBG("Linking io context %p for "
|
||||
"shared tgt_dev %p (cmd_threads %p)",
|
||||
shared_io_context, tgt_dev,
|
||||
tgt_dev->active_cmd_threads);
|
||||
tgt_dev->active_cmd_threads->io_context =
|
||||
ioc_task_link(shared_io_context);
|
||||
}
|
||||
|
||||
res = scst_add_threads(tgt_dev->active_cmd_threads, NULL,
|
||||
tgt_dev,
|
||||
dev->threads_num + tgt_dev->sess->tgt->tgtt->threads_num);
|
||||
break;
|
||||
}
|
||||
case SCST_THREADS_POOL_SHARED:
|
||||
tgt_dev->active_cmd_threads = &dev->dev_cmd_threads;
|
||||
|
||||
res = scst_add_threads(tgt_dev->active_cmd_threads, dev, NULL,
|
||||
tgt_dev->sess->tgt->tgtt->threads_num);
|
||||
break;
|
||||
default:
|
||||
PRINT_CRIT_ERROR("Unknown threads pool type %d (dev %s)",
|
||||
dev->threads_pool_type, dev->virt_name);
|
||||
sBUG();
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (res == 0)
|
||||
tm_dbg_init_tgt_dev(tgt_dev);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* scst_mutex supposed to be held */
|
||||
void scst_tgt_dev_stop_threads(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (tgt_dev->active_cmd_threads == &scst_main_cmd_threads) {
|
||||
/* Global async threads */
|
||||
scst_del_threads(tgt_dev->active_cmd_threads,
|
||||
tgt_dev->sess->tgt->tgtt->threads_num);
|
||||
put_io_context(tgt_dev->tgt_dev_cmd_threads.io_context);
|
||||
tgt_dev->tgt_dev_cmd_threads.io_context = NULL;
|
||||
} else if (tgt_dev->active_cmd_threads == &tgt_dev->dev->dev_cmd_threads) {
|
||||
/* Per device shared threads */
|
||||
scst_del_threads(tgt_dev->active_cmd_threads,
|
||||
tgt_dev->sess->tgt->tgtt->threads_num);
|
||||
} else if (tgt_dev->active_cmd_threads == &tgt_dev->tgt_dev_cmd_threads) {
|
||||
/* Per tgt_dev threads */
|
||||
scst_del_threads(tgt_dev->active_cmd_threads, -1);
|
||||
} /* else no threads (not yet initialized, e.g.) */
|
||||
|
||||
tm_dbg_deinit_tgt_dev(tgt_dev);
|
||||
tgt_dev->active_cmd_threads = NULL;
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* scst_mutex supposed to be held, there must not be parallel activity in this
|
||||
* session.
|
||||
@@ -2292,12 +2497,10 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
struct scst_acg_dev *acg_dev)
|
||||
{
|
||||
int ini_sg, ini_unchecked_isa_dma, ini_use_clustering;
|
||||
struct scst_tgt_dev *tgt_dev, *t = NULL;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct scst_device *dev = acg_dev->dev;
|
||||
struct list_head *sess_tgt_dev_list_head;
|
||||
struct scst_tgt_template *vtt = sess->tgt->tgtt;
|
||||
int rc, i, sl;
|
||||
bool share_io_ctx = false;
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -2360,6 +2563,8 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
for (i = 0; i < (int)ARRAY_SIZE(tgt_dev->sn_slots); i++)
|
||||
atomic_set(&tgt_dev->sn_slots[i], 0);
|
||||
|
||||
scst_init_threads(&tgt_dev->tgt_dev_cmd_threads);
|
||||
|
||||
if (dev->handler->parse_atomic &&
|
||||
(sess->tgt->tgtt->preprocessing_done == NULL)) {
|
||||
if (sess->tgt->tgtt->rdy_to_xfer_atomic)
|
||||
@@ -2388,64 +2593,18 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
dev->d_sense, SCST_LOAD_SENSE(scst_sense_reset_UA));
|
||||
scst_alloc_set_UA(tgt_dev, sense_buffer, sl, 0);
|
||||
|
||||
tm_dbg_init_tgt_dev(tgt_dev, acg_dev);
|
||||
|
||||
if (tgt_dev->sess->initiator_name != NULL) {
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
list_for_each_entry(t, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
TRACE_DBG("t name %s (tgt_dev name %s)",
|
||||
t->sess->initiator_name,
|
||||
tgt_dev->sess->initiator_name);
|
||||
if (t->sess->initiator_name == NULL)
|
||||
continue;
|
||||
if (strcmp(t->sess->initiator_name,
|
||||
tgt_dev->sess->initiator_name) == 0) {
|
||||
share_io_ctx = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
}
|
||||
|
||||
if (share_io_ctx) {
|
||||
TRACE_MGMT_DBG("Sharing IO context %p (tgt_dev %p, ini %s)",
|
||||
t->tgt_dev_io_ctx, tgt_dev,
|
||||
tgt_dev->sess->initiator_name);
|
||||
tgt_dev->tgt_dev_io_ctx = ioc_task_link(t->tgt_dev_io_ctx);
|
||||
} else {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) && defined(SCST_IO_CONTEXT)
|
||||
#if defined(CONFIG_BLOCK)
|
||||
tgt_dev->tgt_dev_io_ctx = alloc_io_context(GFP_KERNEL, -1);
|
||||
if (tgt_dev->tgt_dev_io_ctx == NULL) {
|
||||
TRACE(TRACE_OUT_OF_MEM, "Failed to alloc tgt_dev IO "
|
||||
"context for dev %s (initiator %s)",
|
||||
dev->virt_name, sess->initiator_name);
|
||||
goto out_free;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
if (vtt->threads_num > 0) {
|
||||
rc = 0;
|
||||
if (dev->handler->threads_num > 0)
|
||||
rc = scst_add_dev_threads(dev, vtt->threads_num);
|
||||
else if (dev->handler->threads_num == 0)
|
||||
rc = scst_add_global_threads(vtt->threads_num);
|
||||
if (rc != 0)
|
||||
goto out_free;
|
||||
}
|
||||
rc = scst_tgt_dev_setup_threads(tgt_dev);
|
||||
if (rc != 0)
|
||||
goto out_free;
|
||||
|
||||
if (dev->handler && dev->handler->attach_tgt) {
|
||||
TRACE_DBG("Calling dev handler's attach_tgt(%p)",
|
||||
tgt_dev);
|
||||
TRACE_DBG("Calling dev handler's attach_tgt(%p)", tgt_dev);
|
||||
rc = dev->handler->attach_tgt(tgt_dev);
|
||||
TRACE_DBG("%s", "Dev handler's attach_tgt() returned");
|
||||
if (rc != 0) {
|
||||
PRINT_ERROR("Device handler's %s attach_tgt() "
|
||||
"failed: %d", dev->handler->name, rc);
|
||||
goto out_thr_free;
|
||||
goto out_stop_threads;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2464,17 +2623,11 @@ out:
|
||||
TRACE_EXIT();
|
||||
return tgt_dev;
|
||||
|
||||
out_thr_free:
|
||||
if (vtt->threads_num > 0) {
|
||||
if (dev->handler->threads_num > 0)
|
||||
scst_del_dev_threads(dev, vtt->threads_num);
|
||||
else if (dev->handler->threads_num == 0)
|
||||
scst_del_global_threads(vtt->threads_num);
|
||||
}
|
||||
out_stop_threads:
|
||||
scst_tgt_dev_stop_threads(tgt_dev);
|
||||
|
||||
out_free:
|
||||
scst_free_all_UA(tgt_dev);
|
||||
__exit_io_context(tgt_dev->tgt_dev_io_ctx);
|
||||
|
||||
kmem_cache_free(scst_tgtd_cachep, tgt_dev);
|
||||
tgt_dev = NULL;
|
||||
@@ -2513,12 +2666,9 @@ void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA)
|
||||
static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
struct scst_device *dev = tgt_dev->dev;
|
||||
struct scst_tgt_template *vtt = tgt_dev->sess->tgt->tgtt;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tm_dbg_deinit_tgt_dev(tgt_dev);
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
list_del(&tgt_dev->dev_tgt_dev_list_entry);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
@@ -2535,14 +2685,11 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
TRACE_DBG("%s", "Dev handler's detach_tgt() returned");
|
||||
}
|
||||
|
||||
if (vtt->threads_num > 0) {
|
||||
if (dev->handler->threads_num > 0)
|
||||
scst_del_dev_threads(dev, vtt->threads_num);
|
||||
else if (dev->handler->threads_num == 0)
|
||||
scst_del_global_threads(vtt->threads_num);
|
||||
}
|
||||
scst_tgt_dev_stop_threads(tgt_dev);
|
||||
|
||||
__exit_io_context(tgt_dev->tgt_dev_io_ctx);
|
||||
scst_deinit_threads(&tgt_dev->tgt_dev_cmd_threads);
|
||||
|
||||
sBUG_ON(!list_empty(&tgt_dev->thr_data_list));
|
||||
|
||||
kmem_cache_free(scst_tgtd_cachep, tgt_dev);
|
||||
|
||||
@@ -2837,7 +2984,7 @@ static struct scst_cmd *scst_create_prepare_internal_cmd(
|
||||
if (res == NULL)
|
||||
goto out;
|
||||
|
||||
res->cmd_lists = orig_cmd->cmd_lists;
|
||||
res->cmd_threads = orig_cmd->cmd_threads;
|
||||
res->sess = orig_cmd->sess;
|
||||
res->atomic = scst_cmd_atomic(orig_cmd);
|
||||
res->internal = 1;
|
||||
@@ -2894,10 +3041,10 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
|
||||
|
||||
TRACE_MGMT_DBG("Adding REQUEST SENSE cmd %p to head of active "
|
||||
"cmd list", rs_cmd);
|
||||
spin_lock_irq(&rs_cmd->cmd_lists->cmd_list_lock);
|
||||
list_add(&rs_cmd->cmd_list_entry, &rs_cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&rs_cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irq(&rs_cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&rs_cmd->cmd_threads->cmd_list_lock);
|
||||
list_add(&rs_cmd->cmd_list_entry, &rs_cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&rs_cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock_irq(&rs_cmd->cmd_threads->cmd_list_lock);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -2938,10 +3085,10 @@ static void scst_complete_request_sense(struct scst_cmd *req_cmd)
|
||||
|
||||
TRACE_MGMT_DBG("Adding orig cmd %p to head of active "
|
||||
"cmd list", orig_cmd);
|
||||
spin_lock_irq(&orig_cmd->cmd_lists->cmd_list_lock);
|
||||
list_add(&orig_cmd->cmd_list_entry, &orig_cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&orig_cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irq(&orig_cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&orig_cmd->cmd_threads->cmd_list_lock);
|
||||
list_add(&orig_cmd->cmd_list_entry, &orig_cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&orig_cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock_irq(&orig_cmd->cmd_threads->cmd_list_lock);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -3293,7 +3440,7 @@ struct scst_cmd *scst_alloc_cmd(gfp_t gfp_mask)
|
||||
cmd->state = SCST_CMD_STATE_INIT_WAIT;
|
||||
cmd->start_time = jiffies;
|
||||
atomic_set(&cmd->cmd_ref, 1);
|
||||
cmd->cmd_lists = &scst_main_cmd_lists;
|
||||
cmd->cmd_threads = &scst_main_cmd_threads;
|
||||
INIT_LIST_HEAD(&cmd->mgmt_cmd_list);
|
||||
cmd->queue_type = SCST_CMD_QUEUE_SIMPLE;
|
||||
cmd->timeout = SCST_DEFAULT_TIMEOUT;
|
||||
@@ -3446,11 +3593,11 @@ void scst_check_retries(struct scst_tgt *tgt)
|
||||
TRACE_RETRY("Moving retry cmd %p to head of active "
|
||||
"cmd list (retry_cmds left %d)",
|
||||
c, tgt->retry_cmds);
|
||||
spin_lock(&c->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&c->cmd_threads->cmd_list_lock);
|
||||
list_move(&c->cmd_list_entry,
|
||||
&c->cmd_lists->active_cmd_list);
|
||||
wake_up(&c->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&c->cmd_lists->cmd_list_lock);
|
||||
&c->cmd_threads->active_cmd_list);
|
||||
wake_up(&c->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock(&c->cmd_threads->cmd_list_lock);
|
||||
|
||||
need_wake_up++;
|
||||
if (need_wake_up >= 2) /* "slow start" */
|
||||
@@ -5053,11 +5200,11 @@ void scst_process_reset(struct scst_device *dev,
|
||||
list_del(&cmd->blocked_cmd_list_entry);
|
||||
TRACE_MGMT_DBG("Adding aborted blocked cmd %p "
|
||||
"to active cmd list", cmd);
|
||||
spin_lock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5365,13 +5512,13 @@ restart:
|
||||
if (res == NULL)
|
||||
res = cmd;
|
||||
else {
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&cmd->cmd_threads->cmd_list_lock);
|
||||
TRACE_SN("Adding cmd %p to active cmd list",
|
||||
cmd);
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5462,12 +5609,12 @@ void scst_dev_del_all_thr_data(struct scst_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(scst_dev_del_all_thr_data);
|
||||
|
||||
struct scst_thr_data_hdr *__scst_find_thr_data(struct scst_tgt_dev *tgt_dev,
|
||||
struct task_struct *tsk)
|
||||
/* thr_data_lock supposed to be held */
|
||||
static struct scst_thr_data_hdr *__scst_find_thr_data_locked(
|
||||
struct scst_tgt_dev *tgt_dev, struct task_struct *tsk)
|
||||
{
|
||||
struct scst_thr_data_hdr *res = NULL, *d;
|
||||
|
||||
spin_lock(&tgt_dev->thr_data_lock);
|
||||
list_for_each_entry(d, &tgt_dev->thr_data_list, thr_data_list_entry) {
|
||||
if (d->owner_thr == tsk) {
|
||||
res = d;
|
||||
@@ -5475,11 +5622,47 @@ struct scst_thr_data_hdr *__scst_find_thr_data(struct scst_tgt_dev *tgt_dev,
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct scst_thr_data_hdr *__scst_find_thr_data(struct scst_tgt_dev *tgt_dev,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
struct scst_thr_data_hdr *res;
|
||||
|
||||
spin_lock(&tgt_dev->thr_data_lock);
|
||||
res = __scst_find_thr_data_locked(tgt_dev, tsk);
|
||||
spin_unlock(&tgt_dev->thr_data_lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(__scst_find_thr_data);
|
||||
|
||||
bool scst_del_thr_data(struct scst_tgt_dev *tgt_dev, struct task_struct *tsk)
|
||||
{
|
||||
bool res;
|
||||
struct scst_thr_data_hdr *td;
|
||||
|
||||
spin_lock(&tgt_dev->thr_data_lock);
|
||||
|
||||
td = __scst_find_thr_data_locked(tgt_dev, tsk);
|
||||
if (td != NULL) {
|
||||
list_del(&td->thr_data_list_entry);
|
||||
res = true;
|
||||
} else
|
||||
res = false;
|
||||
|
||||
spin_unlock(&tgt_dev->thr_data_lock);
|
||||
|
||||
if (td != NULL) {
|
||||
/* the find() fn also gets it */
|
||||
scst_thr_data_put(td);
|
||||
scst_thr_data_put(td);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* dev_lock supposed to be held and BH disabled */
|
||||
void __scst_block_dev(struct scst_device *dev)
|
||||
{
|
||||
@@ -5623,15 +5806,15 @@ static void scst_unblock_cmds(struct scst_device *dev)
|
||||
blocked_cmd_list_entry) {
|
||||
list_del(&cmd->blocked_cmd_list_entry);
|
||||
TRACE_MGMT_DBG("Adding blocked cmd %p to active cmd list", cmd);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&cmd->cmd_threads->cmd_list_lock);
|
||||
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
|
||||
list_add(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
else
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
@@ -5948,10 +6131,9 @@ static struct scst_tgt_dev *tm_dbg_tgt_dev;
|
||||
|
||||
static const int tm_dbg_on_state_num_passes[] = { 5, 1, 0x7ffffff };
|
||||
|
||||
static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_acg_dev *acg_dev)
|
||||
static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
if (acg_dev->lun == 6) {
|
||||
if (tgt_dev->lun == 6) {
|
||||
unsigned long flags;
|
||||
|
||||
if (tm_dbg_tgt_dev != NULL)
|
||||
@@ -5990,7 +6172,7 @@ static void tm_dbg_timer_fn(unsigned long arg)
|
||||
tm_dbg_flags.tm_dbg_release = 1;
|
||||
/* Used to make sure that all woken up threads see the new value */
|
||||
smp_wmb();
|
||||
wake_up_all(&tm_dbg_tgt_dev->dev->p_cmd_lists->cmd_list_waitQ);
|
||||
wake_up_all(&tm_dbg_tgt_dev->active_cmd_threads->cmd_list_waitQ);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6033,9 +6215,9 @@ static void tm_dbg_delay_cmd(struct scst_cmd *cmd)
|
||||
sBUG();
|
||||
}
|
||||
/* IRQs already off */
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&cmd->cmd_threads->cmd_list_lock);
|
||||
list_add_tail(&cmd->cmd_list_entry, &tm_dbg_delayed_cmd_list);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
|
||||
cmd->tm_dbg_delayed = 1;
|
||||
tm_dbg_delayed_cmds_count++;
|
||||
return;
|
||||
@@ -6052,10 +6234,10 @@ void tm_dbg_check_released_cmds(void)
|
||||
TRACE_MGMT_DBG("Releasing timed cmd %p (tag %llu), "
|
||||
"delayed_cmds_count=%d", cmd, cmd->tag,
|
||||
tm_dbg_delayed_cmds_count);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&cmd->cmd_threads->cmd_list_lock);
|
||||
list_move(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
|
||||
}
|
||||
tm_dbg_flags.tm_dbg_release = 0;
|
||||
spin_unlock_irq(&scst_tm_dbg_lock);
|
||||
@@ -6161,11 +6343,11 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&cmd->cmd_threads->cmd_list_lock);
|
||||
list_move(&c->cmd_list_entry,
|
||||
&c->cmd_lists->active_cmd_list);
|
||||
wake_up(&c->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
&c->cmd_threads->active_cmd_list);
|
||||
wake_up(&c->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -6198,7 +6380,7 @@ void tm_dbg_task_mgmt(struct scst_device *dev, const char *fn, int force)
|
||||
*/
|
||||
smp_wmb();
|
||||
if (tm_dbg_tgt_dev != NULL)
|
||||
wake_up_all(&tm_dbg_tgt_dev->dev->p_cmd_lists->cmd_list_waitQ);
|
||||
wake_up_all(&tm_dbg_tgt_dev->active_cmd_threads->cmd_list_waitQ);
|
||||
} else {
|
||||
TRACE_MGMT_DBG("%s: while OFFLINE state, doing nothing", fn);
|
||||
}
|
||||
|
||||
@@ -53,17 +53,6 @@
|
||||
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) */
|
||||
#endif /* !defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
|
||||
#if !defined(SCST_IO_CONTEXT)
|
||||
#warning "Patch io_context-<kernel-version> was not applied\
|
||||
on your kernel. SCST will be working with not the best performance."
|
||||
#endif
|
||||
#else
|
||||
#warning "There is no patch io_context-<kernel-version>\
|
||||
for your kernel version. For performance reasons it is strongly recommended\
|
||||
to upgrade your kernel to version >= 2.6.26.x."
|
||||
#endif
|
||||
|
||||
/**
|
||||
** SCST global variables. They are all uninitialized to have their layout in
|
||||
** memory be exactly as specified. Otherwise compiler puts zero-initialized
|
||||
@@ -123,7 +112,7 @@ unsigned long scst_trace_flag;
|
||||
unsigned long scst_flags;
|
||||
atomic_t scst_cmd_count;
|
||||
|
||||
struct scst_cmd_lists scst_main_cmd_lists;
|
||||
struct scst_cmd_threads scst_main_cmd_threads;
|
||||
|
||||
struct scst_tasklet scst_tasklets[NR_CPUS];
|
||||
|
||||
@@ -141,12 +130,9 @@ wait_queue_head_t scst_dev_cmd_waitQ;
|
||||
|
||||
static struct mutex scst_suspend_mutex;
|
||||
/* protected by scst_suspend_mutex */
|
||||
static struct list_head scst_cmd_lists_list;
|
||||
static struct list_head scst_cmd_threads_list;
|
||||
|
||||
static int scst_threads;
|
||||
struct mutex scst_global_threads_mutex;
|
||||
u32 scst_nr_global_threads;
|
||||
static struct list_head scst_global_threads_list;
|
||||
int scst_threads;
|
||||
static struct task_struct *scst_init_cmd_thread;
|
||||
static struct task_struct *scst_mgmt_thread;
|
||||
static struct task_struct *scst_mgmt_cmd_thread;
|
||||
@@ -685,7 +671,7 @@ EXPORT_SYMBOL(scst_suspend_activity);
|
||||
|
||||
static void __scst_resume_activity(void)
|
||||
{
|
||||
struct scst_cmd_lists *l;
|
||||
struct scst_cmd_threads *l;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -701,7 +687,7 @@ static void __scst_resume_activity(void)
|
||||
*/
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
list_for_each_entry(l, &scst_cmd_lists_list, lists_list_entry) {
|
||||
list_for_each_entry(l, &scst_cmd_threads_list, lists_list_entry) {
|
||||
wake_up_all(&l->cmd_list_waitQ);
|
||||
}
|
||||
wake_up_all(&scst_init_cmd_list_waitQ);
|
||||
@@ -1324,155 +1310,177 @@ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type)
|
||||
}
|
||||
EXPORT_SYMBOL(scst_unregister_virtual_dev_driver);
|
||||
|
||||
/* Called under scst_mutex */
|
||||
int scst_add_dev_threads(struct scst_device *dev, int num)
|
||||
/* scst_mutex supposed to be held */
|
||||
int scst_add_threads(struct scst_cmd_threads *cmd_threads,
|
||||
struct scst_device *dev, struct scst_tgt_dev *tgt_dev, int num)
|
||||
{
|
||||
int i, res = 0;
|
||||
int n = 0;
|
||||
int res, i;
|
||||
struct scst_cmd_thread_t *thr;
|
||||
char nm[12];
|
||||
int n = 0, tgt_dev_num = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
list_for_each_entry(thr, &dev->threads_list, thread_list_entry) {
|
||||
list_for_each_entry(thr, &cmd_threads->threads_list, thread_list_entry) {
|
||||
n++;
|
||||
}
|
||||
|
||||
if (tgt_dev != NULL) {
|
||||
struct scst_tgt_dev *t;
|
||||
list_for_each_entry(t, &tgt_dev->dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if (t == tgt_dev)
|
||||
break;
|
||||
tgt_dev_num++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct scst_cmd_thread_t *thr;
|
||||
|
||||
thr = kmalloc(sizeof(*thr), GFP_KERNEL);
|
||||
if (!thr) {
|
||||
res = -ENOMEM;
|
||||
PRINT_ERROR("Failed to allocate thr %d", res);
|
||||
goto out_del;
|
||||
PRINT_ERROR("fail to allocate thr %d", res);
|
||||
goto out_error;
|
||||
}
|
||||
strlcpy(nm, dev->handler->name, ARRAY_SIZE(nm));
|
||||
|
||||
thr->cmd_thread = kthread_create(scst_cmd_thread,
|
||||
&dev->cmd_lists, "%sd%d_%d", nm, dev->dev_num, n++);
|
||||
if (dev != NULL) {
|
||||
char nm[14]; /* to limit the name's len */
|
||||
strlcpy(nm, dev->virt_name, ARRAY_SIZE(nm));
|
||||
thr->cmd_thread = kthread_create(scst_cmd_thread,
|
||||
cmd_threads, "%s%d", nm, n++);
|
||||
} else if (tgt_dev != NULL) {
|
||||
char nm[11]; /* to limit the name's len */
|
||||
strlcpy(nm, tgt_dev->dev->virt_name, ARRAY_SIZE(nm));
|
||||
thr->cmd_thread = kthread_create(scst_cmd_thread,
|
||||
cmd_threads, "%s%d_%d", nm, tgt_dev_num, n++);
|
||||
} else
|
||||
thr->cmd_thread = kthread_create(scst_cmd_thread,
|
||||
cmd_threads, "scsi_tgt%d", n++);
|
||||
|
||||
if (IS_ERR(thr->cmd_thread)) {
|
||||
res = PTR_ERR(thr->cmd_thread);
|
||||
PRINT_ERROR("kthread_create() failed: %d", res);
|
||||
kfree(thr);
|
||||
goto out_del;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
list_add(&thr->thread_list_entry, &dev->threads_list);
|
||||
|
||||
/*
|
||||
* ToDo: better to use tgt_dev_io_context instead, but we
|
||||
* are not ready for that yet.
|
||||
*/
|
||||
__exit_io_context(thr->cmd_thread->io_context);
|
||||
thr->cmd_thread->io_context = ioc_task_link(dev->dev_io_ctx);
|
||||
TRACE_DBG("Setting dev io ctx %p on thr %d", dev->dev_io_ctx,
|
||||
thr->cmd_thread->pid);
|
||||
list_add(&thr->thread_list_entry, &cmd_threads->threads_list);
|
||||
cmd_threads->nr_threads++;
|
||||
|
||||
wake_up_process(thr->cmd_thread);
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_del:
|
||||
scst_del_dev_threads(dev, i);
|
||||
out_error:
|
||||
scst_del_threads(cmd_threads, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Called under scst_mutex and suspended activity */
|
||||
static int scst_create_dev_threads(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int threads_num;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (dev->handler->threads_num <= 0)
|
||||
goto out;
|
||||
|
||||
threads_num = dev->handler->threads_num;
|
||||
|
||||
spin_lock_init(&dev->cmd_lists.cmd_list_lock);
|
||||
INIT_LIST_HEAD(&dev->cmd_lists.active_cmd_list);
|
||||
init_waitqueue_head(&dev->cmd_lists.cmd_list_waitQ);
|
||||
|
||||
res = scst_add_dev_threads(dev, threads_num);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&scst_suspend_mutex);
|
||||
list_add_tail(&dev->cmd_lists.lists_list_entry,
|
||||
&scst_cmd_lists_list);
|
||||
mutex_unlock(&scst_suspend_mutex);
|
||||
|
||||
dev->p_cmd_lists = &dev->cmd_lists;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Called under scst_mutex */
|
||||
void scst_del_dev_threads(struct scst_device *dev, int num)
|
||||
/* scst_mutex supposed to be held */
|
||||
void scst_del_threads(struct scst_cmd_threads *cmd_threads, int num)
|
||||
{
|
||||
struct scst_cmd_thread_t *ct, *tmp;
|
||||
int i = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (num == 0)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_safe_reverse(ct, tmp, &dev->threads_list,
|
||||
list_for_each_entry_safe_reverse(ct, tmp, &cmd_threads->threads_list,
|
||||
thread_list_entry) {
|
||||
int rc;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
struct scst_thr_data_hdr *td;
|
||||
td = __scst_find_thr_data(tgt_dev, ct->cmd_thread);
|
||||
if (td != NULL) {
|
||||
scst_thr_data_put(td);
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct scst_device *dev;
|
||||
|
||||
rc = kthread_stop(ct->cmd_thread);
|
||||
if (rc < 0)
|
||||
TRACE_MGMT_DBG("kthread_stop() failed: %d", rc);
|
||||
|
||||
list_del(&ct->thread_list_entry);
|
||||
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
if (scst_del_thr_data(tgt_dev, ct->cmd_thread))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(ct);
|
||||
|
||||
if ((num > 0) && (++i >= num))
|
||||
cmd_threads->nr_threads--;
|
||||
|
||||
--num;
|
||||
if (num == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd_threads->nr_threads == 0) {
|
||||
put_io_context(cmd_threads->io_context);
|
||||
cmd_threads->io_context = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Called under scst_mutex and suspended activity */
|
||||
static void scst_stop_dev_threads(struct scst_device *dev)
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
void scst_stop_dev_threads(struct scst_device *dev)
|
||||
{
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (list_empty(&dev->threads_list))
|
||||
goto out;
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
scst_tgt_dev_stop_threads(tgt_dev);
|
||||
}
|
||||
|
||||
scst_del_dev_threads(dev, -1);
|
||||
if ((dev->threads_num > 0) &&
|
||||
(dev->threads_pool_type == SCST_THREADS_POOL_SHARED))
|
||||
scst_del_threads(&dev->dev_cmd_threads, -1);
|
||||
|
||||
if (dev->p_cmd_lists == &dev->cmd_lists) {
|
||||
mutex_lock(&scst_suspend_mutex);
|
||||
list_del(&dev->cmd_lists.lists_list_entry);
|
||||
mutex_unlock(&scst_suspend_mutex);
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
int scst_create_dev_threads(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
res = scst_tgt_dev_setup_threads(tgt_dev);
|
||||
if (res != 0)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if ((dev->threads_num > 0) &&
|
||||
(dev->threads_pool_type == SCST_THREADS_POOL_SHARED)) {
|
||||
res = scst_add_threads(&dev->dev_cmd_threads, dev, NULL,
|
||||
dev->threads_num);
|
||||
if (res != 0)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_err:
|
||||
scst_stop_dev_threads(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The activity supposed to be suspended and scst_mutex held */
|
||||
@@ -1519,14 +1527,13 @@ assign:
|
||||
if (handler == NULL)
|
||||
goto out;
|
||||
|
||||
dev->threads_num = handler->threads_num;
|
||||
dev->threads_pool_type = handler->threads_pool_type;
|
||||
|
||||
res = scst_create_devt_dev_sysfs(dev);
|
||||
if (res != 0)
|
||||
goto out_null;
|
||||
|
||||
res = scst_create_dev_threads(dev);
|
||||
if (res != 0)
|
||||
goto out_remove_sysfs;
|
||||
|
||||
if (handler->attach) {
|
||||
TRACE_DBG("Calling new dev handler's attach(%p)", dev);
|
||||
res = handler->attach(dev);
|
||||
@@ -1534,7 +1541,7 @@ assign:
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("New device handler's %s attach() "
|
||||
"failed: %d", handler->name, res);
|
||||
goto out_thr_null;
|
||||
goto out_remove_sysfs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1555,6 +1562,10 @@ assign:
|
||||
}
|
||||
}
|
||||
|
||||
res = scst_create_dev_threads(dev);
|
||||
if (res != 0)
|
||||
goto out_err_detach_tgt;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
@@ -1575,9 +1586,6 @@ out_err_detach_tgt:
|
||||
TRACE_DBG("%s", "Handler's detach() returned");
|
||||
}
|
||||
|
||||
out_thr_null:
|
||||
scst_stop_dev_threads(dev);
|
||||
|
||||
out_remove_sysfs:
|
||||
scst_devt_dev_sysfs_put(dev);
|
||||
|
||||
@@ -1586,139 +1594,56 @@ out_null:
|
||||
goto out;
|
||||
}
|
||||
|
||||
int scst_global_threads_count(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Just to lower the race window, when user can get just changed value
|
||||
*/
|
||||
mutex_lock(&scst_global_threads_mutex);
|
||||
i = scst_nr_global_threads;
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void scst_threads_info_init(void)
|
||||
{
|
||||
mutex_init(&scst_global_threads_mutex);
|
||||
INIT_LIST_HEAD(&scst_global_threads_list);
|
||||
}
|
||||
|
||||
/* scst_global_threads_mutex supposed to be held */
|
||||
void __scst_del_global_threads(int num)
|
||||
{
|
||||
struct scst_cmd_thread_t *ct, *tmp;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (num == 0)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_safe(ct, tmp, &scst_global_threads_list,
|
||||
thread_list_entry) {
|
||||
int res;
|
||||
|
||||
res = kthread_stop(ct->cmd_thread);
|
||||
if (res < 0)
|
||||
TRACE_MGMT_DBG("kthread_stop() failed: %d", res);
|
||||
list_del(&ct->thread_list_entry);
|
||||
kfree(ct);
|
||||
scst_nr_global_threads--;
|
||||
--num;
|
||||
if (num == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* scst_global_threads_mutex supposed to be held */
|
||||
int __scst_add_global_threads(int num)
|
||||
{
|
||||
int res = 0, i;
|
||||
static int scst_thread_num;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct scst_cmd_thread_t *thr;
|
||||
|
||||
thr = kmalloc(sizeof(*thr), GFP_KERNEL);
|
||||
if (!thr) {
|
||||
res = -ENOMEM;
|
||||
PRINT_ERROR("fail to allocate thr %d", res);
|
||||
goto out_error;
|
||||
}
|
||||
thr->cmd_thread = kthread_create(scst_cmd_thread,
|
||||
&scst_main_cmd_lists, "scsi_tgt%d",
|
||||
scst_thread_num++);
|
||||
if (IS_ERR(thr->cmd_thread)) {
|
||||
res = PTR_ERR(thr->cmd_thread);
|
||||
PRINT_ERROR("kthread_create() failed: %d", res);
|
||||
kfree(thr);
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
list_add(&thr->thread_list_entry, &scst_global_threads_list);
|
||||
scst_nr_global_threads++;
|
||||
|
||||
wake_up_process(thr->cmd_thread);
|
||||
}
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_error:
|
||||
__scst_del_global_threads(i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int scst_add_global_threads(int num)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_global_threads_mutex);
|
||||
res = __scst_add_global_threads(num);
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_add_global_threads);
|
||||
|
||||
void scst_del_global_threads(int num)
|
||||
void scst_init_threads(struct scst_cmd_threads *cmd_threads)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_global_threads_mutex);
|
||||
__scst_del_global_threads(num);
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
spin_lock_init(&cmd_threads->cmd_list_lock);
|
||||
INIT_LIST_HEAD(&cmd_threads->active_cmd_list);
|
||||
init_waitqueue_head(&cmd_threads->cmd_list_waitQ);
|
||||
INIT_LIST_HEAD(&cmd_threads->threads_list);
|
||||
|
||||
mutex_lock(&scst_suspend_mutex);
|
||||
list_add_tail(&cmd_threads->lists_list_entry,
|
||||
&scst_cmd_threads_list);
|
||||
mutex_unlock(&scst_suspend_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_del_global_threads);
|
||||
EXPORT_SYMBOL(scst_init_threads);
|
||||
|
||||
void scst_deinit_threads(struct scst_cmd_threads *cmd_threads)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_suspend_mutex);
|
||||
list_del(&cmd_threads->lists_list_entry);
|
||||
mutex_unlock(&scst_suspend_mutex);
|
||||
|
||||
sBUG_ON(cmd_threads->io_context);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_deinit_threads);
|
||||
|
||||
static void scst_stop_all_threads(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_global_threads_mutex);
|
||||
__scst_del_global_threads(-1);
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
scst_del_threads(&scst_main_cmd_threads, -1);
|
||||
|
||||
if (scst_mgmt_cmd_thread)
|
||||
kthread_stop(scst_mgmt_cmd_thread);
|
||||
if (scst_mgmt_thread)
|
||||
kthread_stop(scst_mgmt_thread);
|
||||
if (scst_init_cmd_thread)
|
||||
kthread_stop(scst_init_cmd_thread);
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
@@ -1730,10 +1655,11 @@ static int scst_start_all_threads(int num)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_global_threads_mutex);
|
||||
res = __scst_add_global_threads(num);
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
res = scst_add_threads(&scst_main_cmd_threads, NULL, NULL, num);
|
||||
if (res < 0)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
|
||||
scst_init_cmd_thread = kthread_run(scst_init_thread,
|
||||
NULL, "scsi_tgt_init");
|
||||
@@ -1741,7 +1667,7 @@ static int scst_start_all_threads(int num)
|
||||
res = PTR_ERR(scst_init_cmd_thread);
|
||||
PRINT_ERROR("kthread_create() for init cmd failed: %d", res);
|
||||
scst_init_cmd_thread = NULL;
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
scst_mgmt_cmd_thread = kthread_run(scst_tm_thread,
|
||||
@@ -1750,7 +1676,7 @@ static int scst_start_all_threads(int num)
|
||||
res = PTR_ERR(scst_mgmt_cmd_thread);
|
||||
PRINT_ERROR("kthread_create() for TM failed: %d", res);
|
||||
scst_mgmt_cmd_thread = NULL;
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
scst_mgmt_thread = kthread_run(scst_global_mgmt_thread,
|
||||
@@ -1759,11 +1685,12 @@ static int scst_start_all_threads(int num)
|
||||
res = PTR_ERR(scst_mgmt_thread);
|
||||
PRINT_ERROR("kthread_create() for mgmt failed: %d", res);
|
||||
scst_mgmt_thread = NULL;
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
out_unlock:
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
@@ -1940,18 +1867,6 @@ static int __init init_scst(void)
|
||||
BUILD_BUG_ON(sizeof(c->sn) != sizeof(t->expected_sn));
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
|
||||
#if !defined(SCST_IO_CONTEXT)
|
||||
PRINT_WARNING("%s", "Patch io_context was not applied on "
|
||||
"your kernel. SCST will be working with not the best "
|
||||
"performance.");
|
||||
#endif
|
||||
#else
|
||||
PRINT_WARNING("%s", "There is no patch io_context for your kernel "
|
||||
"version. For performance reasons it is strongly recommended "
|
||||
"to upgrade your kernel to version >= 2.6.27.x.");
|
||||
#endif
|
||||
|
||||
mutex_init(&scst_mutex);
|
||||
INIT_LIST_HEAD(&scst_template_list);
|
||||
INIT_LIST_HEAD(&scst_dev_list);
|
||||
@@ -1977,13 +1892,10 @@ static int __init init_scst(void)
|
||||
INIT_LIST_HEAD(&scst_sess_shut_list);
|
||||
init_waitqueue_head(&scst_dev_cmd_waitQ);
|
||||
mutex_init(&scst_suspend_mutex);
|
||||
INIT_LIST_HEAD(&scst_cmd_lists_list);
|
||||
INIT_LIST_HEAD(&scst_cmd_threads_list);
|
||||
scst_virt_dev_last_id = 1;
|
||||
spin_lock_init(&scst_main_cmd_lists.cmd_list_lock);
|
||||
INIT_LIST_HEAD(&scst_main_cmd_lists.active_cmd_list);
|
||||
init_waitqueue_head(&scst_main_cmd_lists.cmd_list_waitQ);
|
||||
list_add_tail(&scst_main_cmd_lists.lists_list_entry,
|
||||
&scst_cmd_lists_list);
|
||||
|
||||
scst_init_threads(&scst_main_cmd_threads);
|
||||
|
||||
res = scst_lib_init();
|
||||
if (res != 0)
|
||||
@@ -2001,8 +1913,6 @@ static int __init init_scst(void)
|
||||
scst_threads = scst_num_cpus;
|
||||
}
|
||||
|
||||
scst_threads_info_init();
|
||||
|
||||
#define INIT_CACHEP(p, s, o) do { \
|
||||
p = KMEM_CACHE(s, SCST_SLAB_FLAGS); \
|
||||
TRACE_MEM("Slab create: %s at %p size %zd", #s, p, \
|
||||
@@ -2225,6 +2135,8 @@ static void __exit exit_scst(void)
|
||||
|
||||
scst_stop_all_threads();
|
||||
|
||||
scst_deinit_threads(&scst_main_cmd_threads);
|
||||
|
||||
scsi_unregister_interface(&scst_interface);
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
scst_destroy_acg(scst_default_acg);
|
||||
|
||||
@@ -129,6 +129,8 @@ extern unsigned long scst_trace_flag;
|
||||
#define SCST_LUN_ADDR_METHOD_PERIPHERAL 0
|
||||
#define SCST_LUN_ADDR_METHOD_FLAT 1
|
||||
|
||||
extern int scst_threads;
|
||||
|
||||
extern unsigned int scst_max_dev_cmd_mem;
|
||||
|
||||
extern mempool_t *scst_mgmt_mempool;
|
||||
@@ -165,7 +167,7 @@ extern struct list_head scst_init_cmd_list;
|
||||
extern wait_queue_head_t scst_init_cmd_list_waitQ;
|
||||
extern unsigned int scst_init_poll_cnt;
|
||||
|
||||
extern struct scst_cmd_lists scst_main_cmd_lists;
|
||||
extern struct scst_cmd_threads scst_main_cmd_threads;
|
||||
|
||||
extern spinlock_t scst_mcmd_lock;
|
||||
/* The following lists protected by scst_mcmd_lock */
|
||||
@@ -190,22 +192,22 @@ struct scst_cmd_thread_t {
|
||||
struct list_head thread_list_entry;
|
||||
};
|
||||
|
||||
#if defined(SCST_IO_CONTEXT)
|
||||
|
||||
static inline bool scst_set_io_context(struct scst_cmd *cmd,
|
||||
struct io_context **old)
|
||||
{
|
||||
bool res;
|
||||
|
||||
if (cmd->cmd_lists == &scst_main_cmd_lists) {
|
||||
if (cmd->cmd_threads == &scst_main_cmd_threads) {
|
||||
EXTRACHECKS_BUG_ON(in_interrupt());
|
||||
/*
|
||||
* No need to call ioc_task_link(), because io_context
|
||||
* supposed to be cleared in the end of the caller function.
|
||||
*/
|
||||
current->io_context = cmd->tgt_dev->tgt_dev_io_ctx;
|
||||
current->io_context = cmd->tgt_dev->tgt_dev_cmd_threads.io_context;
|
||||
res = true;
|
||||
TRACE_DBG("io_context %p", cmd->tgt_dev->tgt_dev_io_ctx);
|
||||
TRACE_DBG("io_context %p (cmd_threads %p)", current->io_context,
|
||||
&cmd->tgt_dev->tgt_dev_cmd_threads);
|
||||
EXTRACHECKS_BUG_ON(current->io_context == NULL);
|
||||
} else
|
||||
res = false;
|
||||
|
||||
@@ -220,31 +222,18 @@ static inline void scst_reset_io_context(struct scst_tgt_dev *tgt_dev,
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
extern int scst_add_threads(struct scst_cmd_threads *cmd_threads,
|
||||
struct scst_device *dev, struct scst_tgt_dev *tgt_dev, int num);
|
||||
extern void scst_del_threads(struct scst_cmd_threads *cmd_threads, int num);
|
||||
|
||||
static inline bool scst_set_io_context(struct scst_cmd *cmd,
|
||||
struct io_context **old)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline void scst_reset_io_context(struct scst_tgt_dev *tgt_dev,
|
||||
struct io_context *old) {}
|
||||
static inline void __exit_io_context(struct io_context *ioc) {}
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
|
||||
static inline struct io_context *ioc_task_link(struct io_context *ioc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
extern int scst_create_dev_threads(struct scst_device *dev);
|
||||
extern void scst_stop_dev_threads(struct scst_device *dev);
|
||||
|
||||
#endif
|
||||
extern int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev);
|
||||
extern void scst_tgt_dev_stop_threads(struct scst_tgt_dev *tgt_dev);
|
||||
|
||||
extern struct mutex scst_global_threads_mutex;
|
||||
extern u32 scst_nr_global_threads;
|
||||
|
||||
extern int scst_global_threads_count(void);
|
||||
extern int __scst_add_global_threads(int num);
|
||||
extern void __scst_del_global_threads(int num);
|
||||
extern bool scst_del_thr_data(struct scst_tgt_dev *tgt_dev,
|
||||
struct task_struct *tsk);
|
||||
|
||||
extern struct scst_dev_type scst_null_devtype;
|
||||
|
||||
@@ -269,11 +258,11 @@ static inline void scst_make_deferred_commands_active(
|
||||
c = __scst_check_deferred_commands(tgt_dev);
|
||||
if (c != NULL) {
|
||||
TRACE_SN("Adding cmd %p to active cmd list", c);
|
||||
spin_lock_irq(&c->cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&c->cmd_threads->cmd_list_lock);
|
||||
list_add_tail(&c->cmd_list_entry,
|
||||
&c->cmd_lists->active_cmd_list);
|
||||
wake_up(&c->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irq(&c->cmd_lists->cmd_list_lock);
|
||||
&c->cmd_threads->active_cmd_list);
|
||||
wake_up(&c->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock_irq(&c->cmd_threads->cmd_list_lock);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -294,9 +283,6 @@ int scst_init_thread(void *arg);
|
||||
int scst_tm_thread(void *arg);
|
||||
int scst_global_mgmt_thread(void *arg);
|
||||
|
||||
int scst_add_dev_threads(struct scst_device *dev, int num);
|
||||
void scst_del_dev_threads(struct scst_device *dev, int num);
|
||||
|
||||
int scst_queue_retry_cmd(struct scst_cmd *cmd, int finished_cmds);
|
||||
|
||||
static inline void scst_tgtt_cleanup(struct scst_tgt_template *tgtt) { }
|
||||
|
||||
@@ -1223,9 +1223,9 @@ static ssize_t scst_proc_threads_write(struct file *file,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
mutex_lock(&scst_global_threads_mutex);
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
oldtn = scst_nr_global_threads;
|
||||
oldtn = scst_main_cmd_threads.nr_threads;
|
||||
newtn = simple_strtoul(buffer, NULL, 0);
|
||||
if (newtn <= 0) {
|
||||
PRINT_ERROR("Illegal threads num value %d", newtn);
|
||||
@@ -1234,14 +1234,18 @@ static ssize_t scst_proc_threads_write(struct file *file,
|
||||
}
|
||||
delta = newtn - oldtn;
|
||||
if (delta < 0)
|
||||
__scst_del_global_threads(-delta);
|
||||
else
|
||||
__scst_add_global_threads(delta);
|
||||
scst_del_threads(&scst_main_cmd_threads, -delta);
|
||||
else {
|
||||
int rc = scst_add_threads(&scst_main_cmd_threads, NULL, NULL,
|
||||
delta);
|
||||
if (rc != 0)
|
||||
res = rc;
|
||||
}
|
||||
|
||||
PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
|
||||
|
||||
out_up_thr_free:
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
mutex_unlock(&scst_proc_mutex);
|
||||
|
||||
@@ -2648,7 +2652,7 @@ static int scst_threads_info_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
seq_printf(seq, "%d\n", scst_global_threads_count());
|
||||
seq_printf(seq, "%d\n", scst_main_cmd_threads.nr_threads);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
|
||||
@@ -112,6 +112,12 @@ static ssize_t scst_tgt_addr_method_show(struct kobject *kobj,
|
||||
static ssize_t scst_tgt_addr_method_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
static ssize_t scst_tgt_mpio_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf);
|
||||
static ssize_t scst_tgt_mpio_type_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf);
|
||||
@@ -139,6 +145,12 @@ static ssize_t scst_acg_addr_method_show(struct kobject *kobj,
|
||||
static ssize_t scst_acg_addr_method_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
static ssize_t scst_acg_mpio_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf);
|
||||
static ssize_t scst_acg_mpio_type_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
static ssize_t scst_acn_file_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
|
||||
@@ -529,6 +541,10 @@ static struct kobj_attribute scst_tgt_addr_method =
|
||||
__ATTR(addr_method, S_IRUGO | S_IWUSR, scst_tgt_addr_method_show,
|
||||
scst_tgt_addr_method_store);
|
||||
|
||||
static struct kobj_attribute scst_tgt_mpio_type =
|
||||
__ATTR(mpio_type, S_IRUGO | S_IWUSR, scst_tgt_mpio_type_show,
|
||||
scst_tgt_mpio_type_store);
|
||||
|
||||
static struct kobj_attribute scst_rel_tgt_id =
|
||||
__ATTR(rel_tgt_id, S_IRUGO | S_IWUSR, scst_rel_tgt_id_show,
|
||||
scst_rel_tgt_id_store);
|
||||
@@ -537,6 +553,10 @@ static struct kobj_attribute scst_acg_addr_method =
|
||||
__ATTR(addr_method, S_IRUGO | S_IWUSR, scst_acg_addr_method_show,
|
||||
scst_acg_addr_method_store);
|
||||
|
||||
static struct kobj_attribute scst_acg_mpio_type =
|
||||
__ATTR(mpio_type, S_IRUGO | S_IWUSR, scst_acg_mpio_type_show,
|
||||
scst_acg_mpio_type_store);
|
||||
|
||||
static ssize_t scst_tgt_enable_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -700,6 +720,14 @@ int scst_create_tgt_sysfs(struct scst_tgt *tgt)
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&scst_tgt_mpio_type.attr);
|
||||
if (retval != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_tgt_mpio_type.attr.name, tgt->tgt_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pattr = tgt->tgtt->tgt_attrs;
|
||||
if (pattr != NULL) {
|
||||
while (*pattr != NULL) {
|
||||
@@ -787,8 +815,189 @@ ssize_t scst_device_sysfs_type_show(struct kobject *kobj,
|
||||
static struct kobj_attribute device_type_attr =
|
||||
__ATTR(type, S_IRUGO, scst_device_sysfs_type_show, NULL);
|
||||
|
||||
static ssize_t scst_device_sysfs_threads_num_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_device *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
pos = sprintf(buf, "%d\n%s", dev->threads_num,
|
||||
(dev->threads_num != dev->handler->threads_num) ?
|
||||
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t scst_device_sysfs_threads_data_store(struct scst_device *dev,
|
||||
int threads_num, enum scst_dev_type_threads_pool_type threads_pool_type)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if ((threads_num == dev->threads_num) &&
|
||||
(threads_pool_type == dev->threads_pool_type))
|
||||
goto out;
|
||||
|
||||
res = scst_suspend_activity(true);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
if (mutex_lock_interruptible(&scst_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out_resume;
|
||||
}
|
||||
|
||||
scst_stop_dev_threads(dev);
|
||||
|
||||
dev->threads_num = threads_num;
|
||||
dev->threads_pool_type = threads_pool_type;
|
||||
|
||||
res = scst_create_dev_threads(dev);
|
||||
if (res != 0)
|
||||
goto out_up;
|
||||
|
||||
out_up:
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out_resume:
|
||||
scst_resume_activity();
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_device_sysfs_threads_num_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
struct scst_device *dev;
|
||||
long newtn;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
res = strict_strtoul(buf, 0, &newtn);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("strict_strtoul() for %s failed: %d ", buf, res);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (newtn <= 0) {
|
||||
PRINT_ERROR("Illegal threads num value %ld", newtn);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = scst_device_sysfs_threads_data_store(dev, newtn,
|
||||
dev->threads_pool_type);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
PRINT_INFO("Changed cmd threads num to %ld", newtn);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct kobj_attribute device_threads_num_attr =
|
||||
__ATTR(threads_num, S_IRUGO | S_IWUSR,
|
||||
scst_device_sysfs_threads_num_show,
|
||||
scst_device_sysfs_threads_num_store);
|
||||
|
||||
static ssize_t scst_device_sysfs_threads_pool_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_device *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
if (dev->threads_num == 0) {
|
||||
pos = sprintf(buf, "Async\n");
|
||||
goto out;
|
||||
} else if (dev->threads_num < 0) {
|
||||
pos = sprintf(buf, "Not valid\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (dev->threads_pool_type) {
|
||||
case SCST_THREADS_POOL_PER_INITIATOR:
|
||||
pos = sprintf(buf, "%s\n%s", SCST_THREADS_POOL_PER_INITIATOR_STR,
|
||||
(dev->threads_pool_type != dev->handler->threads_pool_type) ?
|
||||
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
break;
|
||||
case SCST_THREADS_POOL_SHARED:
|
||||
pos = sprintf(buf, "%s\n%s", SCST_THREADS_POOL_SHARED_STR,
|
||||
(dev->threads_pool_type != dev->handler->threads_pool_type) ?
|
||||
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
break;
|
||||
default:
|
||||
pos = sprintf(buf, "Unknown\n");
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t scst_device_sysfs_threads_pool_type_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
struct scst_device *dev;
|
||||
enum scst_dev_type_threads_pool_type newtpt;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
newtpt = scst_parse_threads_pool_type(buf, count);
|
||||
if (newtpt == SCST_THREADS_POOL_TYPE_INVALID) {
|
||||
PRINT_ERROR("Illegal threads pool type %s", buf);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE_DBG("buf %s, count %d, newtpt %d", buf, count, newtpt);
|
||||
|
||||
res = scst_device_sysfs_threads_data_store(dev, dev->threads_num,
|
||||
newtpt);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
PRINT_INFO("Changed cmd threads pool type to %d", newtpt);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static struct kobj_attribute device_threads_pool_type_attr =
|
||||
__ATTR(threads_pool_type, S_IRUGO | S_IWUSR,
|
||||
scst_device_sysfs_threads_pool_type_show,
|
||||
scst_device_sysfs_threads_pool_type_store);
|
||||
|
||||
static struct attribute *scst_device_attrs[] = {
|
||||
&device_type_attr.attr,
|
||||
&device_threads_num_attr.attr,
|
||||
&device_threads_pool_type_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -1750,6 +1959,109 @@ static ssize_t scst_tgt_addr_method_store(struct kobject *kobj,
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t __scst_acg_mpio_type_show(struct scst_acg *acg, char *buf)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (acg->acg_mpio_type) {
|
||||
case SCST_ACG_MPIO_AUTO:
|
||||
res = sprintf(buf, "auto\n");
|
||||
break;
|
||||
case SCST_ACG_MPIO_ENABLE:
|
||||
res = sprintf(buf, "enable\n%s\n", SCST_SYSFS_KEY_MARK);
|
||||
break;
|
||||
case SCST_ACG_MPIO_DISABLE:
|
||||
res = sprintf(buf, "disable\n%s\n", SCST_SYSFS_KEY_MARK);
|
||||
break;
|
||||
default:
|
||||
res = sprintf(buf, "Unknown\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t __scst_acg_mpio_type_store(struct scst_acg *acg,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int res = count;
|
||||
enum scst_acg_mpio prev = acg->acg_mpio_type;
|
||||
struct scst_acg_dev *acg_dev;
|
||||
|
||||
if (strncasecmp(buf, SCST_ACG_MPIO_AUTO_STR,
|
||||
min_t(int, strlen(SCST_ACG_MPIO_AUTO_STR), count)) == 0)
|
||||
acg->acg_mpio_type = SCST_ACG_MPIO_AUTO;
|
||||
else if (strncasecmp(buf, SCST_ACG_MPIO_ENABLE_STR,
|
||||
min_t(int, strlen(SCST_ACG_MPIO_ENABLE_STR), count)) == 0)
|
||||
acg->acg_mpio_type = SCST_ACG_MPIO_ENABLE;
|
||||
else if (strncasecmp(buf, SCST_ACG_MPIO_DISABLE_STR,
|
||||
min_t(int, strlen(SCST_ACG_MPIO_DISABLE_STR), count)) == 0)
|
||||
acg->acg_mpio_type = SCST_ACG_MPIO_DISABLE;
|
||||
else {
|
||||
PRINT_ERROR("Unknown MPIO type %s", buf);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prev == acg->acg_mpio_type)
|
||||
goto out;
|
||||
|
||||
res = scst_suspend_activity(true);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
if (mutex_lock_interruptible(&scst_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out_resume;
|
||||
}
|
||||
|
||||
list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
|
||||
int rc;
|
||||
|
||||
scst_stop_dev_threads(acg_dev->dev);
|
||||
|
||||
rc = scst_create_dev_threads(acg_dev->dev);
|
||||
if (rc != 0)
|
||||
res = rc;
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out_resume:
|
||||
scst_resume_activity();
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_tgt_mpio_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct scst_acg *acg;
|
||||
struct scst_tgt *tgt;
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
acg = tgt->default_acg;
|
||||
|
||||
return __scst_acg_mpio_type_show(acg, buf);
|
||||
}
|
||||
|
||||
static ssize_t scst_tgt_mpio_type_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
struct scst_acg *acg;
|
||||
struct scst_tgt *tgt;
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
acg = tgt->default_acg;
|
||||
|
||||
res = __scst_acg_mpio_type_store(acg, buf, count);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_create_acg_sysfs(struct scst_tgt *tgt,
|
||||
struct scst_acg *acg)
|
||||
{
|
||||
@@ -1801,10 +2113,17 @@ static int scst_create_acg_sysfs(struct scst_tgt *tgt,
|
||||
retval = sysfs_create_file(&acg->acg_kobj, &scst_acg_addr_method.attr);
|
||||
if (retval != 0) {
|
||||
PRINT_ERROR("Can't add tgt attr %s for tgt %s",
|
||||
scst_acg_addr_method.attr.name,
|
||||
tgt->tgt_name);
|
||||
scst_acg_addr_method.attr.name, tgt->tgt_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = sysfs_create_file(&acg->acg_kobj, &scst_acg_mpio_type.attr);
|
||||
if (retval != 0) {
|
||||
PRINT_ERROR("Can't add tgt attr %s for tgt %s",
|
||||
scst_acg_mpio_type.attr.name, tgt->tgt_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(retval);
|
||||
return retval;
|
||||
@@ -1856,6 +2175,30 @@ static ssize_t scst_acg_addr_method_store(struct kobject *kobj,
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_acg_mpio_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct scst_acg *acg;
|
||||
|
||||
acg = container_of(kobj, struct scst_acg, acg_kobj);
|
||||
|
||||
return __scst_acg_mpio_type_show(acg, buf);
|
||||
}
|
||||
|
||||
static ssize_t scst_acg_mpio_type_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
struct scst_acg *acg;
|
||||
|
||||
acg = container_of(kobj, struct scst_acg, acg_kobj);
|
||||
|
||||
res = __scst_acg_mpio_type_store(acg, buf, count);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -2509,7 +2852,9 @@ static ssize_t scst_threads_show(struct kobject *kobj,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
count = sprintf(buf, "%d\n", scst_global_threads_count());
|
||||
count = sprintf(buf, "%d\n%s", scst_main_cmd_threads.nr_threads,
|
||||
(scst_main_cmd_threads.nr_threads != scst_threads) ?
|
||||
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
|
||||
TRACE_EXIT();
|
||||
return count;
|
||||
@@ -2523,12 +2868,12 @@ static ssize_t scst_threads_store(struct kobject *kobj,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (mutex_lock_interruptible(&scst_global_threads_mutex) != 0) {
|
||||
if (mutex_lock_interruptible(&scst_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
oldtn = scst_nr_global_threads;
|
||||
oldtn = scst_main_cmd_threads.nr_threads;
|
||||
|
||||
res = strict_strtoul(buf, 0, &newtn);
|
||||
if (res != 0) {
|
||||
@@ -2536,18 +2881,27 @@ static ssize_t scst_threads_store(struct kobject *kobj,
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
if (newtn <= 0) {
|
||||
PRINT_ERROR("Illegal threads num value %ld", newtn);
|
||||
res = -EINVAL;
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
delta = newtn - oldtn;
|
||||
if (delta < 0)
|
||||
__scst_del_global_threads(-delta);
|
||||
else
|
||||
__scst_add_global_threads(delta);
|
||||
scst_del_threads(&scst_main_cmd_threads, -delta);
|
||||
else {
|
||||
res = scst_add_threads(&scst_main_cmd_threads, NULL, NULL, delta);
|
||||
if (res != 0)
|
||||
goto out_up;
|
||||
}
|
||||
|
||||
PRINT_INFO("Changed cmd threads num: old %ld, new %ld", oldtn, newtn);
|
||||
|
||||
res = count;
|
||||
|
||||
out_up:
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
|
||||
@@ -315,16 +315,16 @@ active:
|
||||
pref_context);
|
||||
/* go through */
|
||||
case SCST_CONTEXT_THREAD:
|
||||
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&cmd->cmd_threads->cmd_list_lock, flags);
|
||||
TRACE_DBG("Adding cmd %p to active cmd list", cmd);
|
||||
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
|
||||
list_add(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
else
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irqrestore(&cmd->cmd_lists->cmd_list_lock, flags);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock_irqrestore(&cmd->cmd_threads->cmd_list_lock, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1066,16 +1066,16 @@ static void scst_process_redirect_cmd(struct scst_cmd *cmd,
|
||||
case SCST_CONTEXT_THREAD:
|
||||
if (check_retries)
|
||||
scst_check_retries(tgt);
|
||||
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
|
||||
spin_lock_irqsave(&cmd->cmd_threads->cmd_list_lock, flags);
|
||||
TRACE_DBG("Adding cmd %p to active cmd list", cmd);
|
||||
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
|
||||
list_add(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
else
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irqrestore(&cmd->cmd_lists->cmd_list_lock, flags);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock_irqrestore(&cmd->cmd_threads->cmd_list_lock, flags);
|
||||
break;
|
||||
|
||||
case SCST_CONTEXT_TASKLET:
|
||||
@@ -3307,7 +3307,7 @@ static int scst_translate_lun(struct scst_cmd *cmd)
|
||||
break;
|
||||
}
|
||||
|
||||
cmd->cmd_lists = tgt_dev->dev->p_cmd_lists;
|
||||
cmd->cmd_threads = tgt_dev->active_cmd_threads;
|
||||
cmd->tgt_dev = tgt_dev;
|
||||
cmd->dev = tgt_dev->dev;
|
||||
|
||||
@@ -3333,7 +3333,7 @@ static int scst_translate_lun(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
/*
|
||||
* No locks, but might be on IRQ
|
||||
* No locks, but might be on IRQ.
|
||||
*
|
||||
* Returns 0 on success, > 0 when we need to wait for unblock,
|
||||
* < 0 if there is no device (lun) or device type handler.
|
||||
@@ -3462,16 +3462,16 @@ restart:
|
||||
list_del(&cmd->cmd_list_entry);
|
||||
spin_unlock(&scst_init_lock);
|
||||
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&cmd->cmd_threads->cmd_list_lock);
|
||||
TRACE_MGMT_DBG("Adding cmd %p to active cmd list", cmd);
|
||||
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
|
||||
list_add(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
else
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
|
||||
|
||||
spin_lock(&scst_init_lock);
|
||||
goto restart;
|
||||
@@ -3664,7 +3664,7 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
|
||||
if (res == SCST_CMD_STATE_RES_CONT_NEXT) {
|
||||
/* None */
|
||||
} else if (res == SCST_CMD_STATE_RES_NEED_THREAD) {
|
||||
spin_lock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
switch (cmd->state) {
|
||||
case SCST_CMD_STATE_DEV_PARSE:
|
||||
@@ -3680,20 +3680,20 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
|
||||
TRACE_DBG("Adding cmd %p to head of active cmd list",
|
||||
cmd);
|
||||
list_add(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
break;
|
||||
default:
|
||||
PRINT_CRIT_ERROR("cmd %p is in invalid state %d)", cmd,
|
||||
cmd->state);
|
||||
spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_unlock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
sBUG();
|
||||
spin_lock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
} else
|
||||
sBUG();
|
||||
|
||||
@@ -3731,9 +3731,9 @@ static void scst_do_job_active(struct list_head *cmd_list,
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int test_cmd_lists(struct scst_cmd_lists *p_cmd_lists)
|
||||
static inline int test_cmd_threads(struct scst_cmd_threads *p_cmd_threads)
|
||||
{
|
||||
int res = !list_empty(&p_cmd_lists->active_cmd_list) ||
|
||||
int res = !list_empty(&p_cmd_threads->active_cmd_list) ||
|
||||
unlikely(kthread_should_stop()) ||
|
||||
tm_dbg_is_release();
|
||||
return res;
|
||||
@@ -3741,62 +3741,81 @@ static inline int test_cmd_lists(struct scst_cmd_lists *p_cmd_lists)
|
||||
|
||||
int scst_cmd_thread(void *arg)
|
||||
{
|
||||
struct scst_cmd_lists *p_cmd_lists = (struct scst_cmd_lists *)arg;
|
||||
struct scst_cmd_threads *p_cmd_threads = (struct scst_cmd_threads *)arg;
|
||||
static DEFINE_MUTEX(io_context_mutex);
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Processing thread started, PID %d", current->pid);
|
||||
PRINT_INFO("Processing thread %s (PID %d) started", current->comm,
|
||||
current->pid);
|
||||
|
||||
#if 0
|
||||
set_user_nice(current, 10);
|
||||
#endif
|
||||
current->flags |= PF_NOFREEZE;
|
||||
|
||||
spin_lock_irq(&p_cmd_lists->cmd_list_lock);
|
||||
mutex_lock(&io_context_mutex);
|
||||
|
||||
WARN_ON(current->io_context);
|
||||
|
||||
if (p_cmd_threads != &scst_main_cmd_threads) {
|
||||
if (p_cmd_threads->io_context == NULL) {
|
||||
p_cmd_threads->io_context = ioc_task_link(
|
||||
get_io_context(GFP_KERNEL, -1));
|
||||
TRACE_DBG("Alloced new IO context %p "
|
||||
"(p_cmd_threads %p)",
|
||||
p_cmd_threads->io_context,
|
||||
p_cmd_threads);
|
||||
} else {
|
||||
put_io_context(current->io_context);
|
||||
current->io_context = ioc_task_link(
|
||||
p_cmd_threads->io_context);
|
||||
TRACE_DBG("Linked IO context %p "
|
||||
"(p_cmd_threads %p)",
|
||||
p_cmd_threads->io_context,
|
||||
p_cmd_threads);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&io_context_mutex);
|
||||
|
||||
spin_lock_irq(&p_cmd_threads->cmd_list_lock);
|
||||
while (!kthread_should_stop()) {
|
||||
wait_queue_t wait;
|
||||
init_waitqueue_entry(&wait, current);
|
||||
|
||||
if (!test_cmd_lists(p_cmd_lists)) {
|
||||
if (!test_cmd_threads(p_cmd_threads)) {
|
||||
add_wait_queue_exclusive_head(
|
||||
&p_cmd_lists->cmd_list_waitQ,
|
||||
&p_cmd_threads->cmd_list_waitQ,
|
||||
&wait);
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (test_cmd_lists(p_cmd_lists))
|
||||
if (test_cmd_threads(p_cmd_threads))
|
||||
break;
|
||||
spin_unlock_irq(&p_cmd_lists->cmd_list_lock);
|
||||
spin_unlock_irq(&p_cmd_threads->cmd_list_lock);
|
||||
schedule();
|
||||
spin_lock_irq(&p_cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&p_cmd_threads->cmd_list_lock);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&p_cmd_lists->cmd_list_waitQ, &wait);
|
||||
remove_wait_queue(&p_cmd_threads->cmd_list_waitQ, &wait);
|
||||
}
|
||||
|
||||
if (tm_dbg_is_release()) {
|
||||
spin_unlock_irq(&p_cmd_lists->cmd_list_lock);
|
||||
spin_unlock_irq(&p_cmd_threads->cmd_list_lock);
|
||||
tm_dbg_check_released_cmds();
|
||||
spin_lock_irq(&p_cmd_lists->cmd_list_lock);
|
||||
spin_lock_irq(&p_cmd_threads->cmd_list_lock);
|
||||
}
|
||||
|
||||
scst_do_job_active(&p_cmd_lists->active_cmd_list,
|
||||
&p_cmd_lists->cmd_list_lock, false);
|
||||
scst_do_job_active(&p_cmd_threads->active_cmd_list,
|
||||
&p_cmd_threads->cmd_list_lock, false);
|
||||
}
|
||||
spin_unlock_irq(&p_cmd_lists->cmd_list_lock);
|
||||
spin_unlock_irq(&p_cmd_threads->cmd_list_lock);
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
/*
|
||||
* If kthread_should_stop() is true, we are guaranteed to be either
|
||||
* on the module unload, or there must be at least one other thread to
|
||||
* process the commands lists.
|
||||
*/
|
||||
if (p_cmd_lists == &scst_main_cmd_lists) {
|
||||
sBUG_ON((scst_nr_global_threads == 1) &&
|
||||
!list_empty(&scst_main_cmd_lists.active_cmd_list));
|
||||
}
|
||||
#endif
|
||||
EXTRACHECKS_BUG_ON((p_cmd_threads->nr_threads == 1) &&
|
||||
!list_empty(&p_cmd_threads->active_cmd_list));
|
||||
|
||||
PRINT_INFO("Processing thread PID %d finished", current->pid);
|
||||
PRINT_INFO("Processing thread %s (PID %d) finished", current->comm,
|
||||
current->pid);
|
||||
|
||||
TRACE_EXIT();
|
||||
return 0;
|
||||
@@ -4224,11 +4243,11 @@ static bool __scst_check_unblock_aborted_cmd(struct scst_cmd *cmd,
|
||||
bool res;
|
||||
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
list_del(list_entry);
|
||||
spin_lock(&cmd->cmd_lists->cmd_list_lock);
|
||||
spin_lock(&cmd->cmd_threads->cmd_list_lock);
|
||||
list_add_tail(&cmd->cmd_list_entry,
|
||||
&cmd->cmd_lists->active_cmd_list);
|
||||
wake_up(&cmd->cmd_lists->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_lists->cmd_list_lock);
|
||||
&cmd->cmd_threads->active_cmd_list);
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
spin_unlock(&cmd->cmd_threads->cmd_list_lock);
|
||||
res = 1;
|
||||
} else
|
||||
res = 0;
|
||||
|
||||
Reference in New Issue
Block a user