mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-17 12:46:27 +00:00
Sysfs interface for targets made uniform. ISCSI-SCST made confirming the uniformity requirements. See README for details.
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1511 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -1,461 +0,0 @@
|
||||
Summary of changes from v0.4.15 to v0.4.16
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o fix overzealous assert() in digest_data()
|
||||
o add checking on return value of ISCSI_PARAM_GET
|
||||
o 2.6.22, 2.6.23 and 2.6.24 compile fixes
|
||||
o add conn->rwsize check
|
||||
o avoid potential NULL-ptr dereferences in rx and tx buffer
|
||||
o fix the shell syntax in init scripts
|
||||
|
||||
Dave Jiang
|
||||
o fix digest endieness on LE archs
|
||||
|
||||
FUJITA Tomonori
|
||||
o fix SPARC alignment issues (based on a patch from joel.bertrand@systella.fr)
|
||||
|
||||
Ross S. W. Walker
|
||||
o fix DISTDIR in Makefile for /etc install
|
||||
o add support to nullio for volumes > 2TB
|
||||
o remove init.d memory size adjustment
|
||||
o add error code reporting to blockio_open_path
|
||||
o blockio gen_scsiid bug fix
|
||||
o add verbosity to kernel output and task management
|
||||
|
||||
|
||||
Summary of changes from v0.4.14 to v0.4.15
|
||||
=================================
|
||||
|
||||
Juhani Rautiainen
|
||||
o Add RELEASE/RESERVE support
|
||||
|
||||
Ross S. W. Walker
|
||||
o Improve the build system to support several kernel versions
|
||||
o Add block-io support
|
||||
|
||||
|
||||
Summary of changes from v0.4.13 to v0.4.14
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Kill unused "state" in struct iscsi_cmnd.
|
||||
o Fixed fileio_sync() to propagate error to the caller (and initiator).
|
||||
o Don't attempt to show target/session params if communication with ietd
|
||||
fails.
|
||||
o Fixes to ietadm parameters handling.
|
||||
|
||||
FUJITA Tomonori
|
||||
o rewritten iSNS code, many iSNS fixes.
|
||||
o added iSNS SCN support.
|
||||
o IPv6 fixes to userspace.
|
||||
|
||||
Ming Zhang
|
||||
o Fix the READ_* commands error handling bug.
|
||||
o fix the mode sense response.
|
||||
o wrong #endif sequence in misc.h
|
||||
|
||||
Richard Bollinger
|
||||
o add a patch to ietd.c that allows defunct sessions to go away.
|
||||
o add write-back cache and read-only support.
|
||||
|
||||
Frederic Temporelli
|
||||
o Fix for the combination of 32-bit userland and 64-bit kernel on mips.
|
||||
|
||||
Henry Liu
|
||||
o corrected many task management functions, prevent crashing on
|
||||
LUN RESET, TARGET WARM RESET.
|
||||
|
||||
K Chapman
|
||||
o Fixed a typo in check_segment_length().
|
||||
|
||||
Emmanuel Florac
|
||||
o Add ietadm manpage.
|
||||
|
||||
|
||||
Summary of changes from v0.4.12 to v0.4.13
|
||||
=================================
|
||||
Arne Redlich
|
||||
o patch to avoid digest calculation for PDUs whose data has been skipped
|
||||
already for various reasons.
|
||||
o Correct a bug managing non-default MaxRxDSL.
|
||||
o added to ietadm ability to show target parameters.
|
||||
o add on the workaround to AIX initiator MaxCmdSN bug.
|
||||
|
||||
FUJITA Tomonori
|
||||
o added to ietadm ability to show the iSCSI parameters for an established
|
||||
session.
|
||||
|
||||
Ming Zhang
|
||||
o Fixed this bug : ietd should manage the iscsi name in a case insensitive
|
||||
way to conform to the RFC.
|
||||
o workaround to AIX initiator MaxCmdSN bug.
|
||||
o Fixed socket() return value judgment.
|
||||
|
||||
Bastiaan Bakker
|
||||
o add 'condrestart' command to the RedHat initscript.
|
||||
|
||||
Robert Whitehead
|
||||
o correct the bug that prevents iet to start if there isn't
|
||||
an /etc/ietd.conf file.
|
||||
|
||||
Summary of changes from v0.4.11 to v0.4.12
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Fix MaxRecvDataSegmentLength handling.
|
||||
o Fix login parameter handling.
|
||||
o Update man pages.
|
||||
|
||||
Bastiaan Bakker
|
||||
o Add features to specify the listen address and port.
|
||||
o Fix setuid and setgid bugs in ietd daemon.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Add IPv6 support.
|
||||
|
||||
Junjiro Okajima
|
||||
o Fix a bug about getting parameters from kernel space.
|
||||
|
||||
Krzysztof Blaszkowski
|
||||
o Fix for requests with unaligned to 4 length.
|
||||
|
||||
|
||||
Summary of changes from v0.4.10 to v0.4.11
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix Task Management Function bugs.
|
||||
|
||||
Ming Zhang
|
||||
o Update man pages.
|
||||
|
||||
|
||||
Summary of changes from v0.4.9 to v0.4.10
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Fix 0x83 inquiry output.
|
||||
o Fix iSCSI parameter handling bugs.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Add the access control based on initiator address
|
||||
and target name patterns.
|
||||
|
||||
Junjiro Okajima
|
||||
o Fix parameter checking bugs.
|
||||
|
||||
Ming Zhang
|
||||
o Add the nullio mode (only useful for performance evaluation).
|
||||
|
||||
|
||||
Summary of changes from v0.4.8 to v0.4.9
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix parameter negotiation handling bugs.
|
||||
|
||||
Wang Zhenyu
|
||||
o Fix digest negotiation handling bugs.
|
||||
|
||||
|
||||
Summary of changes from v0.4.7 to v0.4.8
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix unsolicited data handling bugs.
|
||||
o Rewrite parameter handling code.
|
||||
o Rewrite ietadm tool.
|
||||
o Improve dynamic configuration support.
|
||||
o Cleanups on the kernel-user interface.
|
||||
o Improve wrong PDU handling.
|
||||
o Implement a framework to handle multiple configuration methods.
|
||||
o Implement basic access control support.
|
||||
|
||||
|
||||
Summary of changes from v0.4.6 to v0.4.7
|
||||
=================================
|
||||
|
||||
Florian Zierer
|
||||
o Add the startup script for Gentoo.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Rewrite parameter handling code.
|
||||
o Fix task management code bug.
|
||||
o Fix 0x83 inquiry output (Thanks to Christophe Varoqui).
|
||||
|
||||
Ming Zhang
|
||||
o Acquire T10 ID.
|
||||
o Fix parameter handling bugs.
|
||||
o Some user-space cleanups.
|
||||
|
||||
Philipp Hug
|
||||
o Fix ietd.8 man typo.
|
||||
|
||||
|
||||
Summary of changes from v0.4.5 to v0.4.6
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Replace the makeshift event notification code with netlink.
|
||||
o Add task management code except for ACA and reassign stuff.
|
||||
o Fix r2t lun bug (Thanks to Ming Zhang).
|
||||
|
||||
|
||||
Summary of changes from v0.4.4 to v0.4.5
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Rewrite the iSCSI command handling code.
|
||||
o Rewrite the I/O data handling code.
|
||||
o Fix worker thread.
|
||||
o Several cleanups.
|
||||
|
||||
|
||||
Summary of changes from v0.4.3 to v0.4.4
|
||||
=================================
|
||||
|
||||
Krzysztof Blaszkowski
|
||||
o Fix an out-of-memory bug.
|
||||
|
||||
|
||||
Summary of changes from v0.4.2 to v0.4.3
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Fix header digest bug.
|
||||
o Fix unexpected closed connection bug.
|
||||
o Fix iSCSI parameter bug.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix network thread.
|
||||
|
||||
|
||||
Summary of changes from v0.4.1 to v0.4.2
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix network thread.
|
||||
o Fix MaxOutstandingR2T handling.
|
||||
|
||||
Ming Zhang
|
||||
o Add large volume support (over 2TB).
|
||||
|
||||
|
||||
Summary of changes from v0.4.0 to v0.4.1
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Add mutual CHAP support. Note that you need to replace "User"
|
||||
with "IncomingUser" in ietd.conf.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix InitialR2T=No support.
|
||||
o Fix INQUIRY command handling.
|
||||
o Fix network and worker thread.
|
||||
o Start to split SCSI stuff.
|
||||
o Rewrite the R2T handling code.
|
||||
o Several cleanups.
|
||||
|
||||
|
||||
Summary of changes from v0.3.8 to v0.4.0
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o iSNS bug fix.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Move to 2.6 kernels.
|
||||
o Rewrite the kernel thread performing network I/O.
|
||||
o Add header and data digests (Thanks to Arne Redlich).
|
||||
|
||||
Ming Zhang
|
||||
o Add mode sense page 0x3 and 0x4 support (Thanks to K Chapman).
|
||||
o iSNS bug fix.
|
||||
|
||||
|
||||
Summary of changes from v0.3.7 to v0.3.8
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Fix ietadm global option bug.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix TCP option bugs (Thanks to Chuck Berg).
|
||||
o Fix REPORT LUN (handling lots of LUs).
|
||||
|
||||
|
||||
Summary of changes from v0.3.6 to v0.3.7
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Fix target_alloc_pages().
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix REPORT LUN bug.
|
||||
|
||||
|
||||
Summary of changes from v0.3.5 to v0.3.6
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Fix bugs about rejecting PDUs.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Cleanups on target_cmnd structure.
|
||||
o Kill highmem stuff.
|
||||
o Fix REPORT LUN (handling lots of LUs).
|
||||
|
||||
|
||||
Summary of changes from v0.3.4 to v0.3.5
|
||||
=================================
|
||||
|
||||
Arne Redlich
|
||||
o Fix ietd security hole.
|
||||
o Fix REPORT LUN bug.
|
||||
o FIX NOOP_OUT padding bug.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Rewrite event notification code.
|
||||
|
||||
Libor Vanek
|
||||
o Add max_sessions option.
|
||||
o Fix command parsing bug.
|
||||
|
||||
Ming Zhang
|
||||
o Cleanups for 64-bit architectures.
|
||||
|
||||
|
||||
Summary of changes from v0.3.3 to v0.3.4
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Improve dynamic configuration support (adding targets and users).
|
||||
|
||||
|
||||
Summary of changes from v0.3.2 to v0.3.3
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix Makefile for the startup script.
|
||||
|
||||
|
||||
Summary of changes from v0.3.1 to v0.3.2
|
||||
=================================
|
||||
|
||||
Ali Lehmann
|
||||
o Add a new startup script for Debian.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix the istd's handling of connections in out-of-memory situations.
|
||||
o Fix bugs in regular file support.
|
||||
o Fix `ietadm --mode del all`.
|
||||
|
||||
Libor Vanek
|
||||
o Add a new startup script for RedHat.
|
||||
|
||||
Ming Zhang
|
||||
o Add uid/gid option to ietd daemon.
|
||||
o Fix a access freed-memory bug in kernel/daemon.c.
|
||||
|
||||
|
||||
Summary of changes from v0.3.0 to v0.3.1
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix memory leaks in ietd daemon (Thanks to Ming).
|
||||
o Fix bugs about REPORT_LUNS commands (Thanks to Ming).
|
||||
o Fix a bug about Target Task Tag.
|
||||
o Add regular file support to fileio mode.
|
||||
|
||||
|
||||
Summary of changes from v0.2.6 to v0.3.0
|
||||
=================================
|
||||
|
||||
Ali Lehmann
|
||||
o Update ietd.8 man page.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix shutdown code.
|
||||
o Fix istd kernel thread bugs.
|
||||
o Replace procfs interface with ioctl.
|
||||
o Add dynamic configuration support.
|
||||
o Update README and the boot script.
|
||||
|
||||
Ming Zhang
|
||||
o Add config option to ietd daemon.
|
||||
|
||||
|
||||
Summary of changes from v0.2.5 to v0.2.6
|
||||
=================================
|
||||
|
||||
Ali Lehmann
|
||||
o Add ietd.8 and ietd.conf.5 man pages.
|
||||
|
||||
FUJITA Tomonori
|
||||
o Update README, Makefile, and the boot script.
|
||||
|
||||
|
||||
Summary of changes from v0.2.4 to v0.2.5
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Update README.
|
||||
|
||||
|
||||
Summary of changes from v0.2.3 to v0.2.4
|
||||
=================================
|
||||
|
||||
Ming Zhang
|
||||
o Add a preliminary iSNS support.
|
||||
o Fix merge mistakes that I made at the previous release.
|
||||
|
||||
|
||||
Summary of changes from v0.2.2 to v0.2.3
|
||||
=================================
|
||||
|
||||
Ming Zhang
|
||||
o Improve INQUIRY, REQUEST_SENSE, and MODE_SENSE command supports
|
||||
o Add fake RESERVE* and RELEASE* command supports
|
||||
|
||||
|
||||
Summary of changes from v0.2.1 to v0.2.2
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Improve the write performance of the file IO mode
|
||||
|
||||
Ming Zhang
|
||||
o Fix unupdated pg_cnt when allocating a new tcmnd
|
||||
o Several cleanups
|
||||
|
||||
|
||||
Summary of changes from v0.2.0 to v0.2.1
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Fix a bug that makes the target use CPU unnecessarily
|
||||
o Add a feature that enable you to pass options to an IO mode
|
||||
|
||||
|
||||
Summary of changes from v0.1.0 to v0.2.0
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Rewrite read and write kernel threads which perform network IO
|
||||
o Fix race issues in the proc interface
|
||||
o Fix shutdown code
|
||||
|
||||
Ming Zhang
|
||||
o Fix memory leaks in file and block IO modes
|
||||
|
||||
|
||||
Summary of changes from the ardis v20040211 to v0.1.0
|
||||
=================================
|
||||
|
||||
FUJITA Tomonori
|
||||
o Remove a kernel patch. Multiple threads execute I/O operations
|
||||
o Replace IO functions with the kernel standard functions
|
||||
o Add multiple IO modes feature
|
||||
o Fix several race issues
|
||||
o Fix several out-of-memory situation bugs
|
||||
+417
-32
@@ -1,7 +1,7 @@
|
||||
iSCSI SCST target driver
|
||||
========================
|
||||
|
||||
Version 1.0.2, XX XXXXX 2009
|
||||
Version 2.0.0, XX XXXXX 2010
|
||||
----------------------------
|
||||
|
||||
ISCSI-SCST is a deeply reworked fork of iSCSI Enterprise Target (IET)
|
||||
@@ -14,7 +14,7 @@ ISCSI-SCST is a deeply reworked fork of iSCSI Enterprise Target (IET)
|
||||
|
||||
See more info at http://scst.sourceforge.net/target_iscsi.html.
|
||||
|
||||
This version is compatible with SCST version 1.0.2 and higher.
|
||||
This version is compatible with SCST version 2.0.0 and higher.
|
||||
|
||||
|
||||
Installation if your Linux kernel already has iSCSI-SCST built-in
|
||||
@@ -26,8 +26,7 @@ Simply run "make all", then "make install".
|
||||
Installation out of Linux kernel tree
|
||||
-------------------------------------
|
||||
|
||||
Basically as in README-IET, where file names are changed as specified
|
||||
above.
|
||||
See HOWTOs in the doc/ subdirectory.
|
||||
|
||||
Only vanilla kernels from kernel.org and RHEL/CentOS 5.2 kernels are
|
||||
supported, but it should work on other (vendors') kernels, if you manage
|
||||
@@ -52,20 +51,18 @@ recent kernel messages).
|
||||
To use full power of TCP zero-copy transmit functions, especially
|
||||
dealing with user space supplied via scst_user module memory, iSCSI-SCST
|
||||
needs to be notified when Linux networking finished data transmission.
|
||||
Patch put_page_callback-<kernel-version>.patch provides such
|
||||
functionality. The corresponding version of it should be applied on your
|
||||
kernel. Then you should enable CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
kernel config option. This is highly recommended, but not required. Basically,
|
||||
you should consider using of this patch as some optimization, which IET
|
||||
doesn't have, so if you don't use it, you will just revert to the
|
||||
original IET behavior, when for data transmission:
|
||||
For that you should enable CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
kernel config option. This is highly recommended, but not required.
|
||||
Basically, iSCSI-SCST works fine with an unpatched Linux kernel with the
|
||||
same or better speed as other open source iSCSI targets, including IET,
|
||||
but if you want even better performance you have to patch and rebuild
|
||||
the kernel. Without CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
enabled you will just revert to the original behavior of other open
|
||||
source iSCSI targets, when for data transmission:
|
||||
|
||||
- For in-kernel allocated memory (scst_vdisk and pass-through
|
||||
handlers) usage of SGV cache on transmit path (READ-type commands)
|
||||
will be disabled, but data will still be sent in zero-copy manner.
|
||||
The performance hit will be not big, but performance will still
|
||||
remain better, than for IET, because SGV cache will remain used on
|
||||
receive path while IET doesn't have such feature.
|
||||
|
||||
- For user space allocated memory (scst_user handler) all transmitted
|
||||
data will be additionally copied into temporary TCP buffers. The
|
||||
@@ -109,24 +106,16 @@ or
|
||||
Usage
|
||||
-----
|
||||
|
||||
See in doc/iscsi-scst-howto.txt examples how to configure iSCSI-SCST.
|
||||
See HOWTOs in the doc/ subdirectory.
|
||||
|
||||
ISCSI parameters like iSNS, CHAP and target parameters are configured in
|
||||
iscsi-scstd.conf. All LUN information is configured using the
|
||||
corresponding SCST interface. See in SCST README file section "Access
|
||||
and devices visibility management (LUN masking)" to find out how to do
|
||||
it. It is highly recommended to use scstadmin utility for that purpose.
|
||||
The LUN information in iscsi-scstd.conf will be ignored. This is because
|
||||
now responsibilities are divided between the target driver (iSCSI-SCST)
|
||||
and the SCST core as it logically should be: the target driver is
|
||||
responsible for handling targets and their parameters, SCST core is
|
||||
responsible for handling backstorage.
|
||||
In 2.0.0 usage of iscsi-scstd.conf as well as iscsi-scst-adm is
|
||||
obsolete. Use the sysfs interface facilities instead.
|
||||
|
||||
It is recommended to use TEST UNIT READY ("tur") command to check if
|
||||
iSCSI-SCST target is alive.
|
||||
|
||||
IMPORTANT: All LUN information (access control) MUST be configured
|
||||
========= BEFORE iscsi-scstd started!
|
||||
IMPORTANT: In the procfs build all LUN information (access control)
|
||||
========= MUST be configured BEFORE iscsi-scstd started!
|
||||
|
||||
Also see SCST README file how to tune for the best performance.
|
||||
|
||||
@@ -134,6 +123,405 @@ CAUTION: Working of target and initiator on the same host isn't fully
|
||||
======= supported. See SCST README file for details.
|
||||
|
||||
|
||||
Sysfs interface
|
||||
---------------
|
||||
|
||||
Starting from 2.0.0 iSCSI-SCST has sysfs interface. You can switch to it
|
||||
by running "make disable_proc". To switch back to the procfs interface
|
||||
you should run "make enable_proc". The procfs interface from version
|
||||
2.0.0 is obsolete and will be removed in one of the next versions.
|
||||
|
||||
Root of SCST sysfs interface is /sys/kernel/scst_tgt. Root of iSCSI-SCST
|
||||
is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
|
||||
|
||||
- None, one or more subdirectories for targets with name equal to names
|
||||
of the corresponding targets.
|
||||
|
||||
- IncomingUser[num] - optional one or more attributes containing user
|
||||
name and password for incoming discovery user name. Not exist by
|
||||
default and can be added through "mgmt" entry, see below.
|
||||
|
||||
- OutgoingUser - optional attribute containing user name and password
|
||||
for outgoing discovery user name. Not exist by default and can be
|
||||
added through "mgmt" entry, see below.
|
||||
|
||||
- iSNSServer - contains name or IP address of iSNS server with optional
|
||||
"AccessControl" attribute, which allows to enable iSNS access
|
||||
control. Empty by default.
|
||||
|
||||
- enabled - using this attribute you can enable or disable iSCSI-SCST
|
||||
accept new connections. It allows to finish configuring global
|
||||
iSCSI-SCST attributes before it starts accepting new connections. 0
|
||||
by default.
|
||||
|
||||
- open_state - read-only attribute, which allows to see if the user
|
||||
space part of iSCSI-SCST connected to the kernel part.
|
||||
|
||||
- trace_level - allows to enable and disable various tracing
|
||||
facilities. See content of this file for help how to use it.
|
||||
|
||||
- version - read-only attribute, which allows to see version of
|
||||
iSCSI-SCST and enabled optional features.
|
||||
|
||||
- mgmt - main management entry, which allows to configure iSCSI-SCST.
|
||||
Namely, add/delete targets as well as add/delete optional global and
|
||||
per-target attributes. See content of this file for help how to use
|
||||
it.
|
||||
|
||||
Each iSCSI-SCST attribute can contain in the last line mark "[key]". It
|
||||
is automatically added mark used to allow scstadmin to see which
|
||||
attributes it should save in the config file. You can ignore it.
|
||||
|
||||
Each target subdirectory contains the following entries:
|
||||
|
||||
- ini_group - subdirectory defining initiator groups for this target,
|
||||
used to define per-initiator access control. See SCST core README for
|
||||
more details.
|
||||
|
||||
- luns - subdirectory defining LUNs of this target. See SCST core
|
||||
README for more details.
|
||||
|
||||
- sessions - subdirectory containing connected to this target sessions.
|
||||
|
||||
- IncomingUser[num] - optional one or more attributes containing user
|
||||
name and password for incoming user name. Not exist by default and can
|
||||
be added through the "mgmt" entry, see above.
|
||||
|
||||
- OutgoingUser - optional attribute containing user name and password
|
||||
for outgoing user name. Not exist by default and can be added through
|
||||
the "mgmt" entry, see above.
|
||||
|
||||
- Entries defining default iSCSI parameters values used during iSCSI
|
||||
parameters negotiation.
|
||||
|
||||
- QueuedCommands - defines maximum number of commands queued to any
|
||||
session of this target.
|
||||
|
||||
- enabled - using this attribute you can enable or disable iSCSI-SCST
|
||||
accept new connections to this target. It allows to finish
|
||||
configuring it before it starts accepting new connections. 0 by
|
||||
default.
|
||||
|
||||
- tid - TID of this target.
|
||||
|
||||
Subdirectory "sessions" contains one subdirectory for each connected
|
||||
session with name equal to name of the connected initiator.
|
||||
|
||||
Each session subdirectory contains the following entries:
|
||||
|
||||
- One subdirectory for each TCP connection in this session. ISCSI-SCST
|
||||
supports 1 connection per session, but the session subdirectory can
|
||||
contain several connections: one active and other being closed.
|
||||
|
||||
- Entries defining negotiated iSCSI parameters.
|
||||
|
||||
- initiator_name - contains initiator name
|
||||
|
||||
- sid - contains SID of this session
|
||||
|
||||
- reinstating - contains reinstatement state of this session
|
||||
|
||||
- force_close - write-only attribute, which allows to force close this
|
||||
session. This is the only writable session attribute.
|
||||
|
||||
- active_commands - contains number of active, i.e. not yet or being
|
||||
executed, SCSI commands in this session.
|
||||
|
||||
- commands - contains overall number of SCSI commands in this session.
|
||||
|
||||
Each connection subdirectory contains the following entries:
|
||||
|
||||
- cid - contains CID of this connection.
|
||||
|
||||
- ip - contains IP address of the connected initiator.
|
||||
|
||||
- state - contains processing state of this connection.
|
||||
|
||||
Below is a sample script, which configures 1 virtual disk "disk1" using
|
||||
/disk1 image and one target iqn.2006-10.net.vlnb:tgt with all default
|
||||
parameters:
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
modprobe scst
|
||||
modprobe scst_vdisk
|
||||
|
||||
echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
|
||||
|
||||
service iscsi-scst start
|
||||
|
||||
echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
|
||||
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
|
||||
|
||||
|
||||
Below is more advanced sample script, which configures more virtual
|
||||
devices of various types, including virtual CDROM and 2 targets, one
|
||||
with all default parameters, another one with some not default
|
||||
parameters, incoming and outgoing user names for CHAP authentification,
|
||||
and special permissions for initiator iqn.2005-03.org.open-iscsi:cacdcd2520,
|
||||
which will see another set of devices. Also this sample configures CHAP
|
||||
authentication for discovery sessions and iSNS server with access control.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
modprobe scst
|
||||
modprobe scst_vdisk
|
||||
|
||||
echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
|
||||
echo "open disk2 /disk2 4096 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
|
||||
echo "open blockio /dev/sda5" >/sys/kernel/scst_tgt/handlers/vdisk_blockio/mgmt
|
||||
echo "open nullio none" >/sys/kernel/scst_tgt/handlers/vdisk_nullio/mgmt
|
||||
echo "open cdrom" >/sys/kernel/scst_tgt/handlers/vcdrom/mgmt
|
||||
|
||||
service iscsi-scst start
|
||||
|
||||
echo "192.168.1.16 AccessControl" >/sys/kernel/scst_tgt/targets/iscsi/iSNSServer
|
||||
echo "add_attribute IncomingUser joeD 12charsecret" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
echo "add_attribute OutgoingUser jackD 12charsecret1" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
|
||||
echo "add cdrom 1" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
|
||||
|
||||
echo "add_target iqn.2006-10.net.vlnb:tgt1 \
|
||||
IncomingUser1 joe2 12charsecret2; \
|
||||
IncomingUser joe 12charsecret; \
|
||||
OutgoingUser jim1 12charpasswd; \
|
||||
InitialR2T No; \
|
||||
ImmediateData Yes; \
|
||||
MaxRecvDataSegmentLength 8192; \
|
||||
MaxXmitDataSegmentLength 8192; \
|
||||
MaxBurstLength 131072; \
|
||||
FirstBurstLength 32768; \
|
||||
MaxOutstandingR2T 1; \
|
||||
HeaderDigest CRC32C,None; \
|
||||
DataDigest CRC32C,None; \
|
||||
QueuedCommands 8; \
|
||||
" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add disk2 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
|
||||
echo "add nullio 26" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
|
||||
|
||||
echo "create special_ini" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/mgmt
|
||||
echo "add blockio 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/mgmt
|
||||
echo "add iqn.2005-03.org.open-iscsi:cacdcd2520" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/initiators/mgmt
|
||||
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/enabled
|
||||
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
|
||||
|
||||
The resulting overall SCST sysfs hierarchy with an initiator connected to
|
||||
both iSCSI-SCST targets will look like:
|
||||
|
||||
/sys/kernel/scst_tgt
|
||||
|-- devices
|
||||
| |-- blockio
|
||||
| | |-- block_size
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/0
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vdisk_blockio
|
||||
| | |-- read_only
|
||||
| | |-- removable
|
||||
| | |-- resync_size
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | `-- type
|
||||
| |-- cdrom
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/1
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vcdrom
|
||||
| | |-- removable
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | `-- type
|
||||
| |-- disk1
|
||||
| | |-- block_size
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/0
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vdisk_fileio
|
||||
| | |-- nv_cache
|
||||
| | |-- o_direct
|
||||
| | |-- read_only
|
||||
| | |-- removable
|
||||
| | |-- resync_size
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | |-- type
|
||||
| | `-- write_through
|
||||
| |-- disk2
|
||||
| | |-- block_size
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/0
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vdisk_fileio
|
||||
| | |-- nv_cache
|
||||
| | |-- o_direct
|
||||
| | |-- read_only
|
||||
| | |-- removable
|
||||
| | |-- resync_size
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | |-- type
|
||||
| | `-- write_through
|
||||
| `-- nullio
|
||||
| |-- block_size
|
||||
| |-- exported
|
||||
| | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/26
|
||||
| |-- handler -> ../../handlers/vdisk_nullio
|
||||
| |-- read_only
|
||||
| |-- removable
|
||||
| |-- size
|
||||
| |-- t10_dev_id
|
||||
| `-- type
|
||||
|-- handlers
|
||||
| |-- vcdrom
|
||||
| | |-- mgmt
|
||||
| | |-- trace_level
|
||||
| | `-- type
|
||||
| |-- vdisk_blockio
|
||||
| | |-- mgmt
|
||||
| | |-- trace_level
|
||||
| | `-- type
|
||||
| |-- vdisk_fileio
|
||||
| | |-- mgmt
|
||||
| | |-- trace_level
|
||||
| | `-- type
|
||||
| `-- vdisk_nullio
|
||||
| |-- mgmt
|
||||
| |-- trace_level
|
||||
| `-- type
|
||||
|-- sgv
|
||||
| |-- global_stats
|
||||
| |-- sgv
|
||||
| | `-- stats
|
||||
| |-- sgv-clust
|
||||
| | `-- stats
|
||||
| `-- sgv-dma
|
||||
| `-- stats
|
||||
|-- targets
|
||||
| `-- iscsi
|
||||
| |-- IncomingUser
|
||||
| |-- OutgoingUser
|
||||
| |-- enabled
|
||||
| |-- iSNSServer
|
||||
| |-- iqn.2006-10.net.vlnb:tgt
|
||||
| | |-- DataDigest
|
||||
| | |-- FirstBurstLength
|
||||
| | |-- HeaderDigest
|
||||
| | |-- ImmediateData
|
||||
| | |-- InitialR2T
|
||||
| | |-- MaxBurstLength
|
||||
| | |-- MaxOutstandingR2T
|
||||
| | |-- MaxRecvDataSegmentLength
|
||||
| | |-- MaxXmitDataSegmentLength
|
||||
| | |-- QueuedCommands
|
||||
| | |-- enabled
|
||||
| | |-- ini_group
|
||||
| | | `-- mgmt
|
||||
| | |-- luns
|
||||
| | | |-- 0
|
||||
| | | | |-- device -> ../../../../../devices/disk1
|
||||
| | | | `-- read_only
|
||||
| | | |-- 1
|
||||
| | | | |-- device -> ../../../../../devices/cdrom
|
||||
| | | | `-- read_only
|
||||
| | | `-- mgmt
|
||||
| | |-- sessions
|
||||
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
|
||||
| | | |-- 10.170.75.2
|
||||
| | | | |-- cid
|
||||
| | | | |-- ip
|
||||
| | | | `-- state
|
||||
| | | |-- DataDigest
|
||||
| | | |-- FirstBurstLength
|
||||
| | | |-- HeaderDigest
|
||||
| | | |-- ImmediateData
|
||||
| | | |-- InitialR2T
|
||||
| | | |-- MaxBurstLength
|
||||
| | | |-- MaxOutstandingR2T
|
||||
| | | |-- MaxRecvDataSegmentLength
|
||||
| | | |-- MaxXmitDataSegmentLength
|
||||
| | | |-- active_commands
|
||||
| | | |-- commands
|
||||
| | | |-- force_close
|
||||
| | | |-- initiator_name
|
||||
| | | |-- reinstating
|
||||
| | | `-- sid
|
||||
| | `-- tid
|
||||
| |-- iqn.2006-10.net.vlnb:tgt1
|
||||
| | |-- DataDigest
|
||||
| | |-- FirstBurstLength
|
||||
| | |-- HeaderDigest
|
||||
| | |-- ImmediateData
|
||||
| | |-- IncomingUser
|
||||
| | |-- IncomingUser1
|
||||
| | |-- InitialR2T
|
||||
| | |-- MaxBurstLength
|
||||
| | |-- MaxOutstandingR2T
|
||||
| | |-- MaxRecvDataSegmentLength
|
||||
| | |-- MaxXmitDataSegmentLength
|
||||
| | |-- OutgoingUser
|
||||
| | |-- QueuedCommands
|
||||
| | |-- enabled
|
||||
| | |-- ini_group
|
||||
| | | |-- mgmt
|
||||
| | | `-- special_ini
|
||||
| | | |-- initiators
|
||||
| | | | |-- iqn.2005-03.org.open-iscsi:cacdcd2520
|
||||
| | | | `-- mgmt
|
||||
| | | `-- luns
|
||||
| | | |-- 0
|
||||
| | | | |-- device -> ../../../../../../../devices/blockio
|
||||
| | | | `-- read_only
|
||||
| | | `-- mgmt
|
||||
| | |-- luns
|
||||
| | | |-- 0
|
||||
| | | | |-- device -> ../../../../../devices/disk2
|
||||
| | | | `-- read_only
|
||||
| | | |-- 26
|
||||
| | | | |-- device -> ../../../../../devices/nullio
|
||||
| | | | `-- read_only
|
||||
| | | `-- mgmt
|
||||
| | |-- sessions
|
||||
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
|
||||
| | | |-- 10.170.75.2
|
||||
| | | | |-- cid
|
||||
| | | | |-- ip
|
||||
| | | | `-- state
|
||||
| | | |-- DataDigest
|
||||
| | | |-- FirstBurstLength
|
||||
| | | |-- HeaderDigest
|
||||
| | | |-- ImmediateData
|
||||
| | | |-- InitialR2T
|
||||
| | | |-- MaxBurstLength
|
||||
| | | |-- MaxOutstandingR2T
|
||||
| | | |-- MaxRecvDataSegmentLength
|
||||
| | | |-- MaxXmitDataSegmentLength
|
||||
| | | |-- active_commands
|
||||
| | | |-- commands
|
||||
| | | |-- force_close
|
||||
| | | |-- initiator_name
|
||||
| | | |-- reinstating
|
||||
| | | `-- sid
|
||||
| | `-- tid
|
||||
| |-- mgmt
|
||||
| |-- open_state
|
||||
| |-- trace_level
|
||||
| `-- version
|
||||
|-- threads
|
||||
|-- trace_level
|
||||
`-- version
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
@@ -160,9 +548,8 @@ abort or reset messages. It can happen under high I/O load, when your
|
||||
target's backstorage gets overloaded, or working over a slow link, when
|
||||
the link can't serve all the queued commands on time,
|
||||
|
||||
To workaround it you can reduce QueuedCommands parameter in
|
||||
iscsi-scstd.conf file for the corresponding target to some lower value,
|
||||
like 8 (default is 32).
|
||||
To workaround it you can reduce QueuedCommands parameter for the
|
||||
corresponding target to some lower value, like 8 (default is 32).
|
||||
|
||||
Also see SCST README file for more details about that issue and ways to
|
||||
prevent it.
|
||||
@@ -229,8 +616,6 @@ Credits
|
||||
|
||||
Thanks to:
|
||||
|
||||
* IET developers for IET
|
||||
|
||||
* Ming Zhang <blackmagic02881@gmail.com> for fixes
|
||||
|
||||
* Krzysztof Blaszkowski <kb@sysmikro.com.pl> for many fixes
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
Introduction
|
||||
-------------
|
||||
iSCSI Enterprise Target is for building an iSCSI storage system on
|
||||
Linux. It is aimed at developing an iSCSI target satisfying enterprise
|
||||
requirements.
|
||||
|
||||
We borrow code from an Ardis iSCSI target (with respect to the GPL).
|
||||
|
||||
|
||||
Installation
|
||||
-------------
|
||||
The iSCSI target requires a host running the Linux operating system
|
||||
with a kernel version of 2.6.19 (2.6.14 - 2.6.18 kernels using
|
||||
backward compatibility patches, see below) or newer. You need to
|
||||
enable "Cryptographic API" under "Cryptographic options" in the kernel
|
||||
config. You also need to enable "CRC32c CRC algorithm" if you use
|
||||
header or data digests. They are the kernel options, CONFIG_CRYPTO and
|
||||
CONFIG_CRYPTO_CRC32C, respectively. The user-space code requires
|
||||
OpenSSL library (http://www.openssl.org/).
|
||||
|
||||
The iSCSI target consists of kernel modules and a daemon. Since IET
|
||||
is generally targeted at the latest stable mainline kernel, you might
|
||||
need to apply a backward compatibility patch to compile it against
|
||||
older kernel versions:
|
||||
|
||||
patch -p0 < patches/compat-2.6.14-2.6.18.patch
|
||||
|
||||
Compilation of the kernel modules require the path to the kernel
|
||||
sources:
|
||||
|
||||
make KSRC=<kernel-src>
|
||||
|
||||
The path can also be set by editing the main Makefile. If KSRC is
|
||||
omitted, make program will try to locate the kernel sources for
|
||||
current running kernel. Be sure to check whether it finds the right
|
||||
kernel sources.
|
||||
|
||||
This will build the modules, the daemon, and the control tool. To
|
||||
install both, use:
|
||||
|
||||
make KSRC=<kernel-src> install
|
||||
|
||||
The kernel modules will be install in the module directory of the
|
||||
kernel. The daemon and the control tool will be installed as ietd and
|
||||
ietadm under /usr/sbin. The boot script will be installed as
|
||||
iscsi-targt under /etc/init.d.
|
||||
|
||||
If you use Linux distribution that does not have /etc/init.d, the
|
||||
boot script will not be installed. So you need to install it to an
|
||||
appropriate directory manually.
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
The daemon is configured via the configuration file /etc/ietd.conf.
|
||||
See the man page and the example file for the current syntax.
|
||||
|
||||
The ietadm utility is for managing IET software dynamically. You can
|
||||
change the configurations of running targets. See the help message.
|
||||
|
||||
The access control based on initiator address and target name patterns
|
||||
is configured via two configuration files (/etc/initiators.allow and
|
||||
/etc/initiators.deny). These files work like tcpd files
|
||||
(/etc/hosts.allow and /etc/hosts.deny). This feature enables you to
|
||||
hide a particular targets from some initiators. See the example files
|
||||
for the supported expressions. You can change the configuration
|
||||
dynamically. The modifications to the files become effective
|
||||
immediately.
|
||||
|
||||
|
||||
Starting
|
||||
-------------
|
||||
The target is not started automatically. So execute:
|
||||
|
||||
/etc/init.d/iscsi-target start
|
||||
|
||||
Note that you must edit the configuration file before starting the
|
||||
target.
|
||||
|
||||
|
||||
Stopping
|
||||
-------------
|
||||
Execute:
|
||||
|
||||
/etc/init.d/iscsi-target stop
|
||||
|
||||
Contact
|
||||
-------------
|
||||
Please send bug reports, comments, feature requests etc. to our
|
||||
mailing list <iscsitarget-devel@lists.sourceforge.net>.
|
||||
|
||||
|
||||
Developer Notes
|
||||
----------------
|
||||
The central resource for IET development is the
|
||||
<iscsitarget-devel@lists.sourceforge.net> mailing list.
|
||||
|
||||
Our subversion repository can be found at: svn://svn.berlios.de/iscsitarget
|
||||
|
||||
When submitting patches, please diff against the code in our repository's
|
||||
trunk and adhere otherwise to the same rules that apply to Linux kernel
|
||||
development, in particular the Linux kernel coding style
|
||||
($KSRC/Documentation/CodingStyle) and the rules for submitting patches
|
||||
($KSRC/Documentation/SubmittingPatches), i.e. please send patches inline as
|
||||
plain text.
|
||||
+411
-62
@@ -1,54 +1,15 @@
|
||||
iSCSI SCST target driver
|
||||
========================
|
||||
|
||||
Version 1.0.2, XX XXXXX 2009
|
||||
----------------------------
|
||||
ISCSI-SCST is a deeply reworked fork of iSCSI Enterprise Target (IET)
|
||||
(http://iscsitarget.sourceforge.net). Reasons of the fork were:
|
||||
|
||||
This driver is a forked with all respects version of iSCSI Enterprise
|
||||
Target (IET) (http://iscsitarget.sourceforge.net/) with updates to work
|
||||
over SCST as well as with many improvements and bugfixes (see ChangeLog
|
||||
file). The reason of fork is that the necessary changes are intrusive
|
||||
and with the current IET merge policy, where only simple bugfix-like
|
||||
patches, which doesn't touch the core code, could be merged, it is very
|
||||
unlikely that they will be merged in the main IET trunk.
|
||||
- To be able to use full power of SCST core.
|
||||
|
||||
To let it be installed and work at the same host together with IET
|
||||
simultaneously all the driver's modules and files were renamed:
|
||||
|
||||
* ietd.conf -> iscsi-scstd.conf
|
||||
* ietadm -> iscsi-scst-adm
|
||||
* ietd -> iscsi-scstd
|
||||
* iscsi-target -> iscsi-scst
|
||||
* iscsi-target.ko -> iscsi-scst.ko
|
||||
|
||||
To use full power of TCP zero-copy transmit functions, especially
|
||||
dealing with user space supplied via scst_user module memory, iSCSI-SCST
|
||||
needs to be notified when Linux networking finished data transmission.
|
||||
For that you should enable CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
kernel config option. This is highly recommended, but not required. Basically,
|
||||
you should consider usage of this option as some optimization, which IET
|
||||
doesn't have, so if you don't use it, you will just revert to the
|
||||
original IET behavior, when for data transmission:
|
||||
|
||||
- For in-kernel allocated memory (scst_vdisk and pass-through
|
||||
handlers) usage of SGV cache on transmit path (READ-type commands)
|
||||
will be disabled, but data will still be sent in zero-copy manner.
|
||||
The performance hit will be not big, but performance will still
|
||||
remain better, than for IET, because SGV cache will remain used on
|
||||
receive path while IET doesn't have such feature.
|
||||
|
||||
- For user space allocated memory (scst_user handler) all transmitted
|
||||
data will be additionally copied into temporary TCP buffers. The
|
||||
performance hit will be quite noticeable.
|
||||
|
||||
Note, that if your network hardware does not support TX offload
|
||||
functions or has them disabled, then TCP zero-copy transmit functions on
|
||||
your system will not be used by Linux networking in any case, so
|
||||
put_page_callback patch will not be able to improve performance for you.
|
||||
You can check your network hardware offload capabilities by command
|
||||
"ethtool -k ethX", where X is the network device number. At least
|
||||
"tx-checksumming" and "scatter-gather" should be enabled.
|
||||
- To fix all the problems, corner cases issues and iSCSI standard
|
||||
violations which IET has.
|
||||
|
||||
See more info at http://scst.sourceforge.net/target_iscsi.html.
|
||||
|
||||
Usage
|
||||
-----
|
||||
@@ -56,22 +17,14 @@ Usage
|
||||
See in http://scst.sourceforge.net/iscsi-scst-howto.txt how to configure
|
||||
iSCSI-SCST.
|
||||
|
||||
ISCSI parameters like iSNS, CHAP and target parameters are configured in
|
||||
iscsi-scstd.conf. All LUN information is configured using the
|
||||
corresponding SCST interface. See in SCST README file section "Access
|
||||
and devices visibility management (LUN masking)" to find out how to do
|
||||
it. It is highly recommended to use scstadmin utility for that purpose.
|
||||
The LUN information in iscsi-scstd.conf will be ignored. This is because
|
||||
now responsibilities are divided between the target driver (iSCSI-SCST)
|
||||
and the SCST core as it logically should be: the target driver is
|
||||
responsible for handling targets and their parameters, SCST core is
|
||||
responsible for handling backstorage.
|
||||
In 2.0.0 usage of iscsi-scstd.conf as well as iscsi-scst-adm is
|
||||
obsolete. Use the sysfs interface facilities instead.
|
||||
|
||||
It is recommended to use TEST UNIT READY ("tur") command to check if
|
||||
iSCSI-SCST target is alive.
|
||||
|
||||
IMPORTANT: All LUN information (access control) MUST be configured
|
||||
========= BEFORE iscsi-scstd started!
|
||||
IMPORTANT: In the procfs build all LUN information (access control)
|
||||
========= MUST be configured BEFORE iscsi-scstd started!
|
||||
|
||||
Also see SCST README file how to tune for the best performance.
|
||||
|
||||
@@ -79,6 +32,405 @@ CAUTION: Working of target and initiator on the same host isn't fully
|
||||
======= supported. See SCST README file for details.
|
||||
|
||||
|
||||
Sysfs interface
|
||||
---------------
|
||||
|
||||
Starting from 2.0.0 iSCSI-SCST has sysfs interface. You can switch to it
|
||||
by running "make disable_proc". To switch back to the procfs interface
|
||||
you should run "make enable_proc". The procfs interface from version
|
||||
2.0.0 is obsolete and will be removed in one of the next versions.
|
||||
|
||||
Root of SCST sysfs interface is /sys/kernel/scst_tgt. Root of iSCSI-SCST
|
||||
is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
|
||||
|
||||
- None, one or more subdirectories for targets with name equal to names
|
||||
of the corresponding targets.
|
||||
|
||||
- IncomingUser[num] - optional one or more attributes containing user
|
||||
name and password for incoming discovery user name. Not exist by
|
||||
default and can be added through "mgmt" entry, see below.
|
||||
|
||||
- OutgoingUser - optional attribute containing user name and password
|
||||
for outgoing discovery user name. Not exist by default and can be
|
||||
added through "mgmt" entry, see below.
|
||||
|
||||
- iSNSServer - contains name or IP address of iSNS server with optional
|
||||
"AccessControl" attribute, which allows to enable iSNS access
|
||||
control. Empty by default.
|
||||
|
||||
- enabled - using this attribute you can enable or disable iSCSI-SCST
|
||||
accept new connections. It allows to finish configuring global
|
||||
iSCSI-SCST attributes before it starts accepting new connections. 0
|
||||
by default.
|
||||
|
||||
- open_state - read-only attribute, which allows to see if the user
|
||||
space part of iSCSI-SCST connected to the kernel part.
|
||||
|
||||
- trace_level - allows to enable and disable various tracing
|
||||
facilities. See content of this file for help how to use it.
|
||||
|
||||
- version - read-only attribute, which allows to see version of
|
||||
iSCSI-SCST and enabled optional features.
|
||||
|
||||
- mgmt - main management entry, which allows to configure iSCSI-SCST.
|
||||
Namely, add/delete targets as well as add/delete optional global and
|
||||
per-target attributes. See content of this file for help how to use
|
||||
it.
|
||||
|
||||
Each iSCSI-SCST attribute can contain in the last line mark "[key]". It
|
||||
is automatically added mark used to allow scstadmin to see which
|
||||
attributes it should save in the config file. You can ignore it.
|
||||
|
||||
Each target subdirectory contains the following entries:
|
||||
|
||||
- ini_group - subdirectory defining initiator groups for this target,
|
||||
used to define per-initiator access control. See SCST core README for
|
||||
more details.
|
||||
|
||||
- luns - subdirectory defining LUNs of this target. See SCST core
|
||||
README for more details.
|
||||
|
||||
- sessions - subdirectory containing connected to this target sessions.
|
||||
|
||||
- IncomingUser[num] - optional one or more attributes containing user
|
||||
name and password for incoming user name. Not exist by default and can
|
||||
be added through the "mgmt" entry, see above.
|
||||
|
||||
- OutgoingUser - optional attribute containing user name and password
|
||||
for outgoing user name. Not exist by default and can be added through
|
||||
the "mgmt" entry, see above.
|
||||
|
||||
- Entries defining default iSCSI parameters values used during iSCSI
|
||||
parameters negotiation.
|
||||
|
||||
- QueuedCommands - defines maximum number of commands queued to any
|
||||
session of this target.
|
||||
|
||||
- enabled - using this attribute you can enable or disable iSCSI-SCST
|
||||
accept new connections to this target. It allows to finish
|
||||
configuring it before it starts accepting new connections. 0 by
|
||||
default.
|
||||
|
||||
- tid - TID of this target.
|
||||
|
||||
Subdirectory "sessions" contains one subdirectory for each connected
|
||||
session with name equal to name of the connected initiator.
|
||||
|
||||
Each session subdirectory contains the following entries:
|
||||
|
||||
- One subdirectory for each TCP connection in this session. ISCSI-SCST
|
||||
supports 1 connection per session, but the session subdirectory can
|
||||
contain several connections: one active and other being closed.
|
||||
|
||||
- Entries defining negotiated iSCSI parameters.
|
||||
|
||||
- initiator_name - contains initiator name
|
||||
|
||||
- sid - contains SID of this session
|
||||
|
||||
- reinstating - contains reinstatement state of this session
|
||||
|
||||
- force_close - write-only attribute, which allows to force close this
|
||||
session. This is the only writable session attribute.
|
||||
|
||||
- active_commands - contains number of active, i.e. not yet or being
|
||||
executed, SCSI commands in this session.
|
||||
|
||||
- commands - contains overall number of SCSI commands in this session.
|
||||
|
||||
Each connection subdirectory contains the following entries:
|
||||
|
||||
- cid - contains CID of this connection.
|
||||
|
||||
- ip - contains IP address of the connected initiator.
|
||||
|
||||
- state - contains processing state of this connection.
|
||||
|
||||
Below is a sample script, which configures 1 virtual disk "disk1" using
|
||||
/disk1 image and one target iqn.2006-10.net.vlnb:tgt with all default
|
||||
parameters:
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
modprobe scst
|
||||
modprobe scst_vdisk
|
||||
|
||||
echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
|
||||
|
||||
service iscsi-scst start
|
||||
|
||||
echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
|
||||
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
|
||||
|
||||
|
||||
Below is more advanced sample script, which configures more virtual
|
||||
devices of various types, including virtual CDROM and 2 targets, one
|
||||
with all default parameters, another one with some not default
|
||||
parameters, incoming and outgoing user names for CHAP authentification,
|
||||
and special permissions for initiator iqn.2005-03.org.open-iscsi:cacdcd2520,
|
||||
which will see another set of devices. Also this sample configures CHAP
|
||||
authentication for discovery sessions and iSNS server with access control.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
modprobe scst
|
||||
modprobe scst_vdisk
|
||||
|
||||
echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
|
||||
echo "open disk2 /disk2 4096 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
|
||||
echo "open blockio /dev/sda5" >/sys/kernel/scst_tgt/handlers/vdisk_blockio/mgmt
|
||||
echo "open nullio none" >/sys/kernel/scst_tgt/handlers/vdisk_nullio/mgmt
|
||||
echo "open cdrom" >/sys/kernel/scst_tgt/handlers/vcdrom/mgmt
|
||||
|
||||
service iscsi-scst start
|
||||
|
||||
echo "192.168.1.16 AccessControl" >/sys/kernel/scst_tgt/targets/iscsi/iSNSServer
|
||||
echo "add_attribute IncomingUser joeD 12charsecret" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
echo "add_attribute OutgoingUser jackD 12charsecret1" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
|
||||
echo "add cdrom 1" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
|
||||
|
||||
echo "add_target iqn.2006-10.net.vlnb:tgt1 \
|
||||
IncomingUser1 joe2 12charsecret2; \
|
||||
IncomingUser joe 12charsecret; \
|
||||
OutgoingUser jim1 12charpasswd; \
|
||||
InitialR2T No; \
|
||||
ImmediateData Yes; \
|
||||
MaxRecvDataSegmentLength 8192; \
|
||||
MaxXmitDataSegmentLength 8192; \
|
||||
MaxBurstLength 131072; \
|
||||
FirstBurstLength 32768; \
|
||||
MaxOutstandingR2T 1; \
|
||||
HeaderDigest CRC32C,None; \
|
||||
DataDigest CRC32C,None; \
|
||||
QueuedCommands 8; \
|
||||
" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
|
||||
|
||||
echo "add disk2 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
|
||||
echo "add nullio 26" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
|
||||
|
||||
echo "create special_ini" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/mgmt
|
||||
echo "add blockio 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/mgmt
|
||||
echo "add iqn.2005-03.org.open-iscsi:cacdcd2520" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/initiators/mgmt
|
||||
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/enabled
|
||||
|
||||
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
|
||||
|
||||
The resulting overall SCST sysfs hierarchy with an initiator connected to
|
||||
both iSCSI-SCST targets will look like:
|
||||
|
||||
/sys/kernel/scst_tgt
|
||||
|-- devices
|
||||
| |-- blockio
|
||||
| | |-- block_size
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/0
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vdisk_blockio
|
||||
| | |-- read_only
|
||||
| | |-- removable
|
||||
| | |-- resync_size
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | `-- type
|
||||
| |-- cdrom
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/1
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vcdrom
|
||||
| | |-- removable
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | `-- type
|
||||
| |-- disk1
|
||||
| | |-- block_size
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/0
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vdisk_fileio
|
||||
| | |-- nv_cache
|
||||
| | |-- o_direct
|
||||
| | |-- read_only
|
||||
| | |-- removable
|
||||
| | |-- resync_size
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | |-- type
|
||||
| | `-- write_through
|
||||
| |-- disk2
|
||||
| | |-- block_size
|
||||
| | |-- exported
|
||||
| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/0
|
||||
| | |-- filename
|
||||
| | |-- handler -> ../../handlers/vdisk_fileio
|
||||
| | |-- nv_cache
|
||||
| | |-- o_direct
|
||||
| | |-- read_only
|
||||
| | |-- removable
|
||||
| | |-- resync_size
|
||||
| | |-- size
|
||||
| | |-- t10_dev_id
|
||||
| | |-- type
|
||||
| | `-- write_through
|
||||
| `-- nullio
|
||||
| |-- block_size
|
||||
| |-- exported
|
||||
| | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/26
|
||||
| |-- handler -> ../../handlers/vdisk_nullio
|
||||
| |-- read_only
|
||||
| |-- removable
|
||||
| |-- size
|
||||
| |-- t10_dev_id
|
||||
| `-- type
|
||||
|-- handlers
|
||||
| |-- vcdrom
|
||||
| | |-- mgmt
|
||||
| | |-- trace_level
|
||||
| | `-- type
|
||||
| |-- vdisk_blockio
|
||||
| | |-- mgmt
|
||||
| | |-- trace_level
|
||||
| | `-- type
|
||||
| |-- vdisk_fileio
|
||||
| | |-- mgmt
|
||||
| | |-- trace_level
|
||||
| | `-- type
|
||||
| `-- vdisk_nullio
|
||||
| |-- mgmt
|
||||
| |-- trace_level
|
||||
| `-- type
|
||||
|-- sgv
|
||||
| |-- global_stats
|
||||
| |-- sgv
|
||||
| | `-- stats
|
||||
| |-- sgv-clust
|
||||
| | `-- stats
|
||||
| `-- sgv-dma
|
||||
| `-- stats
|
||||
|-- targets
|
||||
| `-- iscsi
|
||||
| |-- IncomingUser
|
||||
| |-- OutgoingUser
|
||||
| |-- enabled
|
||||
| |-- iSNSServer
|
||||
| |-- iqn.2006-10.net.vlnb:tgt
|
||||
| | |-- DataDigest
|
||||
| | |-- FirstBurstLength
|
||||
| | |-- HeaderDigest
|
||||
| | |-- ImmediateData
|
||||
| | |-- InitialR2T
|
||||
| | |-- MaxBurstLength
|
||||
| | |-- MaxOutstandingR2T
|
||||
| | |-- MaxRecvDataSegmentLength
|
||||
| | |-- MaxXmitDataSegmentLength
|
||||
| | |-- QueuedCommands
|
||||
| | |-- enabled
|
||||
| | |-- ini_group
|
||||
| | | `-- mgmt
|
||||
| | |-- luns
|
||||
| | | |-- 0
|
||||
| | | | |-- device -> ../../../../../devices/disk1
|
||||
| | | | `-- read_only
|
||||
| | | |-- 1
|
||||
| | | | |-- device -> ../../../../../devices/cdrom
|
||||
| | | | `-- read_only
|
||||
| | | `-- mgmt
|
||||
| | |-- sessions
|
||||
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
|
||||
| | | |-- 10.170.75.2
|
||||
| | | | |-- cid
|
||||
| | | | |-- ip
|
||||
| | | | `-- state
|
||||
| | | |-- DataDigest
|
||||
| | | |-- FirstBurstLength
|
||||
| | | |-- HeaderDigest
|
||||
| | | |-- ImmediateData
|
||||
| | | |-- InitialR2T
|
||||
| | | |-- MaxBurstLength
|
||||
| | | |-- MaxOutstandingR2T
|
||||
| | | |-- MaxRecvDataSegmentLength
|
||||
| | | |-- MaxXmitDataSegmentLength
|
||||
| | | |-- active_commands
|
||||
| | | |-- commands
|
||||
| | | |-- force_close
|
||||
| | | |-- initiator_name
|
||||
| | | |-- reinstating
|
||||
| | | `-- sid
|
||||
| | `-- tid
|
||||
| |-- iqn.2006-10.net.vlnb:tgt1
|
||||
| | |-- DataDigest
|
||||
| | |-- FirstBurstLength
|
||||
| | |-- HeaderDigest
|
||||
| | |-- ImmediateData
|
||||
| | |-- IncomingUser
|
||||
| | |-- IncomingUser1
|
||||
| | |-- InitialR2T
|
||||
| | |-- MaxBurstLength
|
||||
| | |-- MaxOutstandingR2T
|
||||
| | |-- MaxRecvDataSegmentLength
|
||||
| | |-- MaxXmitDataSegmentLength
|
||||
| | |-- OutgoingUser
|
||||
| | |-- QueuedCommands
|
||||
| | |-- enabled
|
||||
| | |-- ini_group
|
||||
| | | |-- mgmt
|
||||
| | | `-- special_ini
|
||||
| | | |-- initiators
|
||||
| | | | |-- iqn.2005-03.org.open-iscsi:cacdcd2520
|
||||
| | | | `-- mgmt
|
||||
| | | `-- luns
|
||||
| | | |-- 0
|
||||
| | | | |-- device -> ../../../../../../../devices/blockio
|
||||
| | | | `-- read_only
|
||||
| | | `-- mgmt
|
||||
| | |-- luns
|
||||
| | | |-- 0
|
||||
| | | | |-- device -> ../../../../../devices/disk2
|
||||
| | | | `-- read_only
|
||||
| | | |-- 26
|
||||
| | | | |-- device -> ../../../../../devices/nullio
|
||||
| | | | `-- read_only
|
||||
| | | `-- mgmt
|
||||
| | |-- sessions
|
||||
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
|
||||
| | | |-- 10.170.75.2
|
||||
| | | | |-- cid
|
||||
| | | | |-- ip
|
||||
| | | | `-- state
|
||||
| | | |-- DataDigest
|
||||
| | | |-- FirstBurstLength
|
||||
| | | |-- HeaderDigest
|
||||
| | | |-- ImmediateData
|
||||
| | | |-- InitialR2T
|
||||
| | | |-- MaxBurstLength
|
||||
| | | |-- MaxOutstandingR2T
|
||||
| | | |-- MaxRecvDataSegmentLength
|
||||
| | | |-- MaxXmitDataSegmentLength
|
||||
| | | |-- active_commands
|
||||
| | | |-- commands
|
||||
| | | |-- force_close
|
||||
| | | |-- initiator_name
|
||||
| | | |-- reinstating
|
||||
| | | `-- sid
|
||||
| | `-- tid
|
||||
| |-- mgmt
|
||||
| |-- open_state
|
||||
| |-- trace_level
|
||||
| `-- version
|
||||
|-- threads
|
||||
|-- trace_level
|
||||
`-- version
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
@@ -103,9 +455,8 @@ abort or reset messages. It can happen under high I/O load, when your
|
||||
target's backstorage gets overloaded, or working over a slow link, when
|
||||
the link can't serve all the queued commands on time,
|
||||
|
||||
To workaround it you can reduce QueuedCommands parameter in
|
||||
iscsi-scstd.conf file for the corresponding target to some lower value,
|
||||
like 8 (default is 32).
|
||||
To workaround it you can reduce QueuedCommands parameter for the
|
||||
corresponding target to some lower value, like 8 (default is 32).
|
||||
|
||||
Also see SCST README file for more details about that issue and ways to
|
||||
prevent it.
|
||||
@@ -152,8 +503,6 @@ Credits
|
||||
|
||||
Thanks to:
|
||||
|
||||
* IET developers for IET
|
||||
|
||||
* Ming Zhang <blackmagic02881@gmail.com> for fixes
|
||||
|
||||
* Krzysztof Blaszkowski <kb@sysmikro.com.pl> for many fixes
|
||||
|
||||
+18
-1
@@ -1,3 +1,20 @@
|
||||
- Fix support of ranges in parameters negotiation.
|
||||
- __cmnd_abort() must be called by SCST core through new callback
|
||||
instead of the driver itself.
|
||||
|
||||
- Remove the "poor man solution" suspending. Instead, immediate/unsolicited
|
||||
data for suspended commands should be received in the dummy_page and
|
||||
then, when they are resumed, aborted with BUSY status. All other
|
||||
commands should proceed normally.
|
||||
|
||||
- Separate iSCSI request and response structures. Currently they share the
|
||||
same structure. This architecture decision derived from IET and makes
|
||||
the code a lot less readable, maintainable and effective as well as more
|
||||
errors prone, so it must be corrected.
|
||||
|
||||
- Code beautifying, i.e. make it be written in the same nice looking style.
|
||||
Particularly, all functions and variables names should share the same style.
|
||||
|
||||
- Fix support of ranges in parameters negotiation. Are there any initiators who
|
||||
use ranges and, hence, can be used for testing?
|
||||
|
||||
- Minor "ToDo"'s spread in the code.
|
||||
|
||||
@@ -34,33 +34,8 @@
|
||||
#define aligned_u64 uint64_t __attribute__((aligned(8)))
|
||||
#endif
|
||||
|
||||
struct iscsi_kern_target_info {
|
||||
u32 tid;
|
||||
char name[ISCSI_NAME_LEN];
|
||||
};
|
||||
|
||||
struct iscsi_kern_session_info {
|
||||
u32 tid;
|
||||
|
||||
aligned_u64 sid;
|
||||
char initiator_name[ISCSI_NAME_LEN];
|
||||
char user_name[ISCSI_NAME_LEN];
|
||||
u32 exp_cmd_sn;
|
||||
};
|
||||
|
||||
#define DIGEST_ALL (DIGEST_NONE | DIGEST_CRC32C)
|
||||
#define DIGEST_NONE (1 << 0)
|
||||
#define DIGEST_CRC32C (1 << 1)
|
||||
|
||||
struct iscsi_kern_conn_info {
|
||||
u32 tid;
|
||||
aligned_u64 sid;
|
||||
|
||||
u32 cid;
|
||||
u32 stat_sn;
|
||||
u32 exp_stat_sn;
|
||||
int fd;
|
||||
};
|
||||
#define ISCSI_MAX_ATTR_NAME_LEN 50
|
||||
#define ISCSI_MAX_ATTR_VALUE_LEN 512
|
||||
|
||||
enum {
|
||||
key_initial_r2t,
|
||||
@@ -95,20 +70,74 @@ enum {
|
||||
key_target,
|
||||
};
|
||||
|
||||
struct iscsi_kern_param_info {
|
||||
struct iscsi_kern_target_info {
|
||||
u32 tid;
|
||||
u32 cookie;
|
||||
char name[ISCSI_NAME_LEN];
|
||||
u32 attrs_num;
|
||||
aligned_u64 attrs_ptr;
|
||||
};
|
||||
|
||||
struct iscsi_kern_session_info {
|
||||
u32 tid;
|
||||
aligned_u64 sid;
|
||||
char initiator_name[ISCSI_NAME_LEN];
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
char user_name[ISCSI_NAME_LEN];
|
||||
#endif
|
||||
u32 exp_cmd_sn;
|
||||
s32 session_params[session_key_last];
|
||||
s32 target_params[target_key_last];
|
||||
};
|
||||
|
||||
#define DIGEST_ALL (DIGEST_NONE | DIGEST_CRC32C)
|
||||
#define DIGEST_NONE (1 << 0)
|
||||
#define DIGEST_CRC32C (1 << 1)
|
||||
|
||||
struct iscsi_kern_conn_info {
|
||||
u32 tid;
|
||||
aligned_u64 sid;
|
||||
|
||||
u32 param_type;
|
||||
u32 cid;
|
||||
u32 stat_sn;
|
||||
u32 exp_stat_sn;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct iscsi_kern_attr {
|
||||
u32 mode;
|
||||
char name[ISCSI_MAX_ATTR_NAME_LEN];
|
||||
};
|
||||
|
||||
struct iscsi_kern_mgmt_cmd_res_info {
|
||||
u32 tid;
|
||||
u32 cookie;
|
||||
u32 req_cmd;
|
||||
u32 result;
|
||||
char value[ISCSI_MAX_ATTR_VALUE_LEN];
|
||||
};
|
||||
|
||||
struct iscsi_kern_params_info {
|
||||
u32 tid;
|
||||
aligned_u64 sid;
|
||||
|
||||
u32 params_type;
|
||||
u32 partial;
|
||||
|
||||
s32 session_param[session_key_last];
|
||||
s32 target_param[target_key_last];
|
||||
s32 session_params[session_key_last];
|
||||
s32 target_params[target_key_last];
|
||||
};
|
||||
|
||||
enum iscsi_kern_event_code {
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
E_ADD_TARGET,
|
||||
E_DEL_TARGET,
|
||||
E_MGMT_CMD,
|
||||
E_ENABLE_TARGET,
|
||||
E_DISABLE_TARGET,
|
||||
E_GET_ATTR_VALUE,
|
||||
E_SET_ATTR_VALUE,
|
||||
#endif
|
||||
E_CONN_CLOSE,
|
||||
};
|
||||
|
||||
@@ -117,10 +146,26 @@ struct iscsi_kern_event {
|
||||
aligned_u64 sid;
|
||||
u32 cid;
|
||||
u32 code;
|
||||
u32 cookie;
|
||||
char target_name[ISCSI_NAME_LEN];
|
||||
u32 param1_size;
|
||||
u32 param2_size;
|
||||
};
|
||||
|
||||
struct iscsi_kern_register_info {
|
||||
aligned_u64 version;
|
||||
union {
|
||||
aligned_u64 version;
|
||||
struct {
|
||||
int max_data_seg_len;
|
||||
int max_queued_cmds;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct iscsi_kern_attr_info {
|
||||
u32 tid;
|
||||
u32 cookie;
|
||||
struct iscsi_kern_attr attr;
|
||||
};
|
||||
|
||||
#define DEFAULT_NR_QUEUED_CMNDS 32
|
||||
@@ -129,19 +174,21 @@ struct iscsi_kern_register_info {
|
||||
|
||||
#define NETLINK_ISCSI_SCST 25
|
||||
|
||||
/* On success returns MAX_DATA_SEG_LEN */
|
||||
#define REGISTER_USERD _IOW('s', 0, struct iscsi_kern_register_info)
|
||||
|
||||
#define REGISTER_USERD _IOWR('s', 0, struct iscsi_kern_register_info)
|
||||
#define ADD_TARGET _IOW('s', 1, struct iscsi_kern_target_info)
|
||||
#define DEL_TARGET _IOW('s', 2, struct iscsi_kern_target_info)
|
||||
#define ENABLE_TARGET _IOW('s', 3, struct iscsi_kern_target_info)
|
||||
#define DISABLE_TARGET _IOW('s', 4, struct iscsi_kern_target_info)
|
||||
#define ADD_SESSION _IOW('s', 5, struct iscsi_kern_session_info)
|
||||
#define DEL_SESSION _IOW('s', 6, struct iscsi_kern_session_info)
|
||||
#define ADD_CONN _IOW('s', 7, struct iscsi_kern_conn_info)
|
||||
#define DEL_CONN _IOW('s', 8, struct iscsi_kern_conn_info)
|
||||
#define ISCSI_PARAM_SET _IOW('s', 9, struct iscsi_kern_param_info)
|
||||
#define ISCSI_PARAM_GET _IOWR('s', 10, struct iscsi_kern_param_info)
|
||||
#define ADD_SESSION _IOW('s', 3, struct iscsi_kern_session_info)
|
||||
#define DEL_SESSION _IOW('s', 4, struct iscsi_kern_session_info)
|
||||
#define ADD_CONN _IOW('s', 5, struct iscsi_kern_conn_info)
|
||||
#define DEL_CONN _IOW('s', 6, struct iscsi_kern_conn_info)
|
||||
#define ISCSI_PARAM_SET _IOW('s', 7, struct iscsi_kern_params_info)
|
||||
#define ISCSI_PARAM_GET _IOWR('s', 8, struct iscsi_kern_params_info)
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
#define ISCSI_ATTR_ADD _IOW('s', 9, struct iscsi_kern_attr_info)
|
||||
#define ISCSI_ATTR_DEL _IOW('s', 10, struct iscsi_kern_attr_info)
|
||||
#define MGMT_CMD_CALLBACK _IOW('s', 11, struct iscsi_kern_mgmt_cmd_res_info)
|
||||
#endif
|
||||
|
||||
static inline int iscsi_is_key_internal(int key)
|
||||
{
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
#define ISCSI_VERSION_STRING_SUFFIX
|
||||
#endif
|
||||
|
||||
#define ISCSI_VERSION_STRING "1.0.2/0.4.17r214" ISCSI_VERSION_STRING_SUFFIX
|
||||
#define ISCSI_VERSION_STRING "2.0.0/0.4.17r214" ISCSI_VERSION_STRING_SUFFIX
|
||||
|
||||
+752
-184
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,20 @@ out:
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
|
||||
static int print_digest_state(char *p, size_t size, unsigned long flags)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (DIGEST_NONE & flags)
|
||||
pos = scnprintf(p, size, "%s", "none");
|
||||
else if (DIGEST_CRC32C & flags)
|
||||
pos = scnprintf(p, size, "%s", "crc32c");
|
||||
else
|
||||
pos = scnprintf(p, size, "%s", "unknown");
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
void conn_info_show(struct seq_file *seq, struct iscsi_session *session)
|
||||
{
|
||||
@@ -666,8 +680,8 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
conn->rd_state = ISCSI_CONN_RD_STATE_IDLE;
|
||||
conn->wr_state = ISCSI_CONN_WR_STATE_IDLE;
|
||||
|
||||
conn->hdigest_type = session->sess_param.header_digest;
|
||||
conn->ddigest_type = session->sess_param.data_digest;
|
||||
conn->hdigest_type = session->sess_params.header_digest;
|
||||
conn->ddigest_type = session->sess_params.data_digest;
|
||||
res = digest_init(conn);
|
||||
if (res != 0)
|
||||
goto out_err_free1;
|
||||
@@ -770,7 +784,7 @@ out_err:
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
{
|
||||
struct iscsi_conn *conn, *new_conn = NULL;
|
||||
int err;
|
||||
@@ -805,7 +819,7 @@ out:
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
int conn_del(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
int __del_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
{
|
||||
struct iscsi_conn *conn;
|
||||
int err = -EEXIST;
|
||||
|
||||
@@ -86,36 +86,88 @@ static void event_recv(struct sock *sk, int length)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int notify(void *data, int len)
|
||||
/* event_mutex supposed to be held */
|
||||
static int __event_send(const void *buf, int buf_len)
|
||||
{
|
||||
int res = 0, len;
|
||||
struct sk_buff *skb;
|
||||
struct nlmsghdr *nlh;
|
||||
static u32 seq;
|
||||
static u32 seq; /* protected by event_mutex */
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (ctr_open_state != ISCSI_CTR_OPEN_STATE_OPEN)
|
||||
goto out;
|
||||
|
||||
len = NLMSG_SPACE(buf_len);
|
||||
|
||||
skb = alloc_skb(NLMSG_SPACE(len), GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
if (skb == NULL) {
|
||||
PRINT_ERROR("alloc_skb() failed (len %d)", len);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nlh = __nlmsg_put(skb, iscsid_pid, seq++, NLMSG_DONE,
|
||||
len - sizeof(*nlh), 0);
|
||||
|
||||
memcpy(NLMSG_DATA(nlh), data, len);
|
||||
memcpy(NLMSG_DATA(nlh), buf, buf_len);
|
||||
res = netlink_unicast(nl, skb, iscsid_pid, 0);
|
||||
if (res <= 0) {
|
||||
if (res != -ECONNREFUSED)
|
||||
PRINT_ERROR("netlink_unicast() failed: %d", res);
|
||||
else
|
||||
TRACE(TRACE_MINOR, "netlink_unicast() failed: %s. "
|
||||
"Not functioning user space?",
|
||||
"Connection refused");
|
||||
goto out;
|
||||
}
|
||||
|
||||
return netlink_unicast(nl, skb, iscsid_pid, 0);
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int event_send(u32 tid, u64 sid, u32 cid, enum iscsi_kern_event_code code)
|
||||
int event_send(u32 tid, u64 sid, u32 cid, u32 cookie,
|
||||
enum iscsi_kern_event_code code,
|
||||
const char *param1, const char *param2)
|
||||
{
|
||||
int err;
|
||||
static DEFINE_MUTEX(event_mutex);
|
||||
struct iscsi_kern_event event;
|
||||
int param1_size, param2_size;
|
||||
|
||||
param1_size = (param1 != NULL) ? strlen(param1) : 0;
|
||||
param2_size = (param2 != NULL) ? strlen(param2) : 0;
|
||||
|
||||
event.tid = tid;
|
||||
event.sid = sid;
|
||||
event.cid = cid;
|
||||
event.code = code;
|
||||
event.cookie = cookie;
|
||||
event.param1_size = param1_size;
|
||||
event.param2_size = param2_size;
|
||||
|
||||
err = notify(&event, NLMSG_SPACE(sizeof(struct iscsi_kern_event)));
|
||||
mutex_lock(&event_mutex);
|
||||
|
||||
err = __event_send(&event, sizeof(event));
|
||||
if (err <= 0)
|
||||
goto out_unlock;
|
||||
|
||||
if (param1_size > 0) {
|
||||
err = __event_send(param1, param1_size);
|
||||
if (err <= 0)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (param2_size > 0) {
|
||||
err = __event_send(param2, param2_size);
|
||||
if (err <= 0)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&event_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
+29
-18
@@ -37,7 +37,6 @@
|
||||
|
||||
static int ctr_major;
|
||||
static char ctr_name[] = "iscsi-scst-ctl";
|
||||
static int iscsi_template_registered;
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
unsigned long iscsi_trace_flag = ISCSI_DEFAULT_LOG_FLAGS;
|
||||
@@ -725,7 +724,7 @@ static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
|
||||
|
||||
TRACE_DBG("req %p", req);
|
||||
|
||||
pdusize = req->conn->session->sess_param.max_xmit_data_length;
|
||||
pdusize = req->conn->session->sess_params.max_xmit_data_length;
|
||||
expsize = req->read_size;
|
||||
size = min(expsize, (u32)req->bufflen);
|
||||
offset = 0;
|
||||
@@ -1007,7 +1006,7 @@ out:
|
||||
|
||||
static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess)
|
||||
{
|
||||
int res = max(-1, (int)sess->max_queued_cmnds -
|
||||
int res = max(-1, (int)sess->tgt_params.queued_cmnds -
|
||||
atomic_read(&sess->active_cmds)-1);
|
||||
TRACE_DBG("allowed cmds %d (sess %p, active_cmds %d)", res,
|
||||
sess, atomic_read(&sess->active_cmds));
|
||||
@@ -1461,12 +1460,12 @@ static void send_r2t(struct iscsi_cmnd *req)
|
||||
*/
|
||||
|
||||
EXTRACHECKS_BUG_ON(req->outstanding_r2t >
|
||||
sess->sess_param.max_outstanding_r2t);
|
||||
sess->sess_params.max_outstanding_r2t);
|
||||
|
||||
if (req->outstanding_r2t == sess->sess_param.max_outstanding_r2t)
|
||||
if (req->outstanding_r2t == sess->sess_params.max_outstanding_r2t)
|
||||
goto out;
|
||||
|
||||
burst = sess->sess_param.max_burst_length;
|
||||
burst = sess->sess_params.max_burst_length;
|
||||
offset = be32_to_cpu(cmnd_hdr(req)->data_length) -
|
||||
req->r2t_len_to_send;
|
||||
|
||||
@@ -1498,7 +1497,7 @@ static void send_r2t(struct iscsi_cmnd *req)
|
||||
list_add_tail(&rsp->write_list_entry, &send);
|
||||
req->outstanding_r2t++;
|
||||
|
||||
} while ((req->outstanding_r2t < sess->sess_param.max_outstanding_r2t) &&
|
||||
} while ((req->outstanding_r2t < sess->sess_params.max_outstanding_r2t) &&
|
||||
(req->r2t_len_to_send != 0));
|
||||
|
||||
iscsi_cmnds_init_write(&send, ISCSI_INIT_WRITE_WAKE);
|
||||
@@ -1679,7 +1678,7 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
if (dir & SCST_DATA_WRITE) {
|
||||
unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL);
|
||||
|
||||
if (unlikely(session->sess_param.initial_r2t &&
|
||||
if (unlikely(session->sess_params.initial_r2t &&
|
||||
unsolicited_data_expected)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: initial R2T is required (ITT %x, "
|
||||
@@ -1688,7 +1687,7 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (unlikely(!session->sess_param.immediate_data &&
|
||||
if (unlikely(!session->sess_params.immediate_data &&
|
||||
req->pdu.datasize)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: forbidden immediate data sent "
|
||||
@@ -1697,13 +1696,13 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (unlikely(session->sess_param.first_burst_length < req->pdu.datasize)) {
|
||||
if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated "
|
||||
"parameters: immediate data len (%d) > "
|
||||
"first_burst_length (%d) (ITT %x, op %x)",
|
||||
session->initiator_name,
|
||||
req->pdu.datasize,
|
||||
session->sess_param.first_burst_length,
|
||||
session->sess_params.first_burst_length,
|
||||
cmnd_itt(req), req_hdr->scb[0]);
|
||||
goto out_close;
|
||||
}
|
||||
@@ -1732,7 +1731,7 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
|
||||
req->outstanding_r2t = 1;
|
||||
req->r2t_len_to_send = req->r2t_len_to_receive -
|
||||
min_t(unsigned int,
|
||||
session->sess_param.first_burst_length -
|
||||
session->sess_params.first_burst_length -
|
||||
req->pdu.datasize,
|
||||
req->r2t_len_to_receive);
|
||||
} else
|
||||
@@ -2853,12 +2852,12 @@ static int check_segment_length(struct iscsi_cmnd *cmnd)
|
||||
struct iscsi_conn *conn = cmnd->conn;
|
||||
struct iscsi_session *session = conn->session;
|
||||
|
||||
if (unlikely(cmnd->pdu.datasize > session->sess_param.max_recv_data_length)) {
|
||||
if (unlikely(cmnd->pdu.datasize > session->sess_params.max_recv_data_length)) {
|
||||
PRINT_ERROR("Initiator %s violated negotiated parameters: "
|
||||
"data too long (ITT %x, datasize %u, "
|
||||
"max_recv_data_length %u", session->initiator_name,
|
||||
cmnd_itt(cmnd), cmnd->pdu.datasize,
|
||||
session->sess_param.max_recv_data_length);
|
||||
session->sess_params.max_recv_data_length);
|
||||
mark_conn_closed(conn);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -3463,6 +3462,16 @@ static struct scst_trace_log iscsi_local_trace_tbl[] = {
|
||||
#define ISCSI_TRACE_TLB_HELP ", d_read, d_write, conn, conn_dbg, iov, pdu, net_page"
|
||||
#endif
|
||||
|
||||
#define ISCSI_MGMT_CMD_HELP \
|
||||
" echo \"add_attribute IncomingUser name password\" >mgmt\n" \
|
||||
" echo \"del_attribute IncomingUser name\" >mgmt\n" \
|
||||
" echo \"add_attribute OutgoingUser name password\" >mgmt\n" \
|
||||
" echo \"del_attribute OutgoingUser name\" >mgmt\n" \
|
||||
" echo \"add_target_attribute target_name IncomingUser name password\" >mgmt\n" \
|
||||
" echo \"del_target_attribute target_name IncomingUser name\" >mgmt\n" \
|
||||
" echo \"add_target_attribute target_name OutgoingUser name password\" >mgmt\n" \
|
||||
" echo \"del_target_attribute target_name OutgoingUser name\" >mgmt\n"
|
||||
|
||||
struct scst_tgt_template iscsi_template = {
|
||||
.name = "iscsi",
|
||||
.sg_tablesize = 0xFFFF /* no limit */,
|
||||
@@ -3473,8 +3482,12 @@ struct scst_tgt_template iscsi_template = {
|
||||
.tgtt_attrs = iscsi_attrs,
|
||||
.tgt_attrs = iscsi_tgt_attrs,
|
||||
.sess_attrs = iscsi_sess_attrs,
|
||||
.enable_tgt = iscsi_enable_target,
|
||||
.is_tgt_enabled = iscsi_is_target_enabled,
|
||||
.enable_target = iscsi_enable_target,
|
||||
.is_target_enabled = iscsi_is_target_enabled,
|
||||
.add_target = iscsi_sysfs_add_target,
|
||||
.del_target = iscsi_sysfs_del_target,
|
||||
.mgmt_cmd = iscsi_sysfs_mgmt_cmd,
|
||||
.mgmt_cmd_help = ISCSI_MGMT_CMD_HELP,
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = ISCSI_DEFAULT_LOG_FLAGS,
|
||||
@@ -3594,8 +3607,6 @@ static int __init iscsi_init(void)
|
||||
if (err < 0)
|
||||
goto out_kmem;
|
||||
|
||||
iscsi_template_registered = 1;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
err = iscsi_procfs_init();
|
||||
if (err < 0)
|
||||
|
||||
+62
-35
@@ -33,7 +33,11 @@
|
||||
#define iscsi_sense_unexpected_unsolicited_data ABORTED_COMMAND, 0x0C, 0x0C
|
||||
#define iscsi_sense_incorrect_amount_of_data ABORTED_COMMAND, 0x0C, 0x0D
|
||||
|
||||
struct iscsi_sess_param {
|
||||
/*
|
||||
* All members must have int type to match expectations of iscsi_tgt_store_*()
|
||||
* functions!
|
||||
*/
|
||||
struct iscsi_sess_params {
|
||||
int initial_r2t;
|
||||
int immediate_data;
|
||||
int max_connections;
|
||||
@@ -55,7 +59,11 @@ struct iscsi_sess_param {
|
||||
int ifmarkint;
|
||||
};
|
||||
|
||||
struct iscsi_trgt_param {
|
||||
/*
|
||||
* All members must have int type to match expectations of iscsi_tgt_store_*()
|
||||
* functions!
|
||||
*/
|
||||
struct iscsi_tgt_params {
|
||||
int queued_cmnds;
|
||||
};
|
||||
|
||||
@@ -64,8 +72,18 @@ struct network_thread_info {
|
||||
unsigned int ready;
|
||||
};
|
||||
|
||||
struct iscsi_target;
|
||||
struct iscsi_cmnd;
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
struct iscsi_attr {
|
||||
struct list_head attrs_list_entry;
|
||||
struct kobj_attribute attr;
|
||||
struct iscsi_target *target;
|
||||
const char *name;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct iscsi_target {
|
||||
struct scst_tgt *scst_tgt;
|
||||
|
||||
@@ -73,24 +91,16 @@ struct iscsi_target {
|
||||
|
||||
struct list_head session_list; /* protected by target_mutex */
|
||||
|
||||
/* Both protected by target_mgmt_mutex */
|
||||
struct iscsi_trgt_param trgt_param;
|
||||
/*
|
||||
* Put here to have uniform parameters checking and assigning
|
||||
* from various places, including iscsi-scst-adm.
|
||||
*/
|
||||
struct iscsi_sess_param trgt_sess_param;
|
||||
|
||||
struct list_head target_list_entry;
|
||||
u32 tid;
|
||||
|
||||
/* All protected by target_sysfs_mutex */
|
||||
/* Protected by iscsi_sysfs_mutex */
|
||||
unsigned int tgt_enabled:1;
|
||||
unsigned int expected_ioctl;
|
||||
int ioctl_res;
|
||||
struct completion *target_enabling_cmpl;
|
||||
|
||||
struct mutex target_sysfs_mutex;
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
/* Protected by target_mutex */
|
||||
struct list_head attrs_list;
|
||||
#endif
|
||||
|
||||
char name[ISCSI_NAME_LEN];
|
||||
};
|
||||
@@ -107,7 +117,8 @@ struct iscsi_session {
|
||||
/* Unprotected, since accessed only from a single read thread */
|
||||
u32 next_ttt;
|
||||
|
||||
u32 max_queued_cmnds; /* unprotected, since read-only */
|
||||
/* Read only, if there are connection(s) */
|
||||
struct iscsi_tgt_params tgt_params;
|
||||
atomic_t active_cmds;
|
||||
|
||||
spinlock_t sn_lock;
|
||||
@@ -119,7 +130,7 @@ struct iscsi_session {
|
||||
struct iscsi_cmnd *tm_rsp;
|
||||
|
||||
/* Read only, if there are connection(s) */
|
||||
struct iscsi_sess_param sess_param;
|
||||
struct iscsi_sess_params sess_params;
|
||||
|
||||
/*
|
||||
* In some corner cases commands can be deleted from the hash
|
||||
@@ -440,8 +451,13 @@ struct iscsi_cmnd {
|
||||
#define ISCSI_TM_DATA_WAIT_TIMEOUT (10 * HZ)
|
||||
#define ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT (ISCSI_TM_DATA_WAIT_TIMEOUT + HZ)
|
||||
|
||||
#define ISCSI_CTR_OPEN_STATE_CLOSED 0
|
||||
#define ISCSI_CTR_OPEN_STATE_OPEN 1
|
||||
#define ISCSI_CTR_OPEN_STATE_CLOSING 2
|
||||
|
||||
extern struct mutex target_mgmt_mutex;
|
||||
|
||||
extern int ctr_open_state;
|
||||
extern const struct file_operations ctr_fops;
|
||||
|
||||
extern spinlock_t iscsi_rd_lock;
|
||||
@@ -470,8 +486,8 @@ extern void iscsi_fail_data_waiting_cmnd(struct iscsi_cmnd *cmnd);
|
||||
/* conn.c */
|
||||
extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
|
||||
extern void conn_reinst_finished(struct iscsi_conn *);
|
||||
extern int conn_add(struct iscsi_session *, struct iscsi_kern_conn_info *);
|
||||
extern int conn_del(struct iscsi_session *, struct iscsi_kern_conn_info *);
|
||||
extern int __add_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
|
||||
extern int __del_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
extern int conn_free(struct iscsi_conn *);
|
||||
#endif
|
||||
@@ -499,51 +515,62 @@ extern void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd);
|
||||
extern void req_add_to_write_timeout_list(struct iscsi_cmnd *req);
|
||||
|
||||
/* target.c */
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
extern const struct seq_operations iscsi_seq_op;
|
||||
#else
|
||||
extern const struct attribute *iscsi_tgt_attrs[];
|
||||
extern ssize_t iscsi_enable_target(struct scst_tgt *scst_tgt, const char *buf,
|
||||
size_t size);
|
||||
extern bool iscsi_is_target_enabled(struct scst_tgt *scst_tgt);
|
||||
extern ssize_t iscsi_sysfs_send_event(uint32_t tid,
|
||||
enum iscsi_kern_event_code code,
|
||||
const char *param1, const char *param2, void **data);
|
||||
#endif
|
||||
struct iscsi_target *target_lookup_by_id(u32);
|
||||
extern int target_add(struct iscsi_kern_target_info *);
|
||||
extern int target_enable(struct iscsi_kern_target_info *);
|
||||
extern int target_disable(struct iscsi_kern_target_info *);
|
||||
extern int target_del(u32 id);
|
||||
extern struct iscsi_target *target_lookup_by_id(u32);
|
||||
extern int __add_target(struct iscsi_kern_target_info *);
|
||||
extern int __del_target(u32 id);
|
||||
extern ssize_t iscsi_sysfs_add_target(const char *target_name,
|
||||
const char *params);
|
||||
extern ssize_t iscsi_sysfs_del_target(const char *target_name);
|
||||
extern ssize_t iscsi_sysfs_mgmt_cmd(const char *cmd);
|
||||
extern void target_del_session(struct iscsi_target *target,
|
||||
struct iscsi_session *session, int flags);
|
||||
extern void target_del_all_sess(struct iscsi_target *target, int flags);
|
||||
extern void target_del_all(void);
|
||||
|
||||
extern const struct seq_operations iscsi_seq_op;
|
||||
|
||||
/* config.c */
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
extern int iscsi_procfs_init(void);
|
||||
extern void iscsi_procfs_exit(void);
|
||||
#else
|
||||
extern const struct attribute *iscsi_attrs[];
|
||||
extern int iscsi_add_attr(struct iscsi_target *target,
|
||||
const struct iscsi_kern_attr *user_info);
|
||||
extern void __iscsi_del_attr(struct iscsi_target *target,
|
||||
struct iscsi_attr *tgt_attr);
|
||||
#endif
|
||||
|
||||
/* session.c */
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
int print_digest_state(char *p, size_t size, unsigned long flags);
|
||||
#else
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
extern const struct attribute *iscsi_sess_attrs[];
|
||||
#endif
|
||||
extern const struct file_operations session_seq_fops;
|
||||
extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
|
||||
extern void sess_reinst_finished(struct iscsi_session *);
|
||||
extern int session_add(struct iscsi_target *, struct iscsi_kern_session_info *);
|
||||
extern int session_del(struct iscsi_target *, u64);
|
||||
extern int __add_session(struct iscsi_target *,
|
||||
struct iscsi_kern_session_info *);
|
||||
extern int __del_session(struct iscsi_target *, u64);
|
||||
extern int session_free(struct iscsi_session *session, bool del);
|
||||
|
||||
/* params.c */
|
||||
extern int iscsi_param_set(struct iscsi_target *,
|
||||
struct iscsi_kern_param_info *, int);
|
||||
extern const char *iscsi_get_digest_name(int val, char *res);
|
||||
extern const char *iscsi_get_bool_value(int val);
|
||||
extern int iscsi_params_set(struct iscsi_target *,
|
||||
struct iscsi_kern_params_info *, int);
|
||||
|
||||
/* event.c */
|
||||
extern int event_send(u32, u64, u32, enum iscsi_kern_event_code);
|
||||
extern int event_send(u32, u64, u32, u32, enum iscsi_kern_event_code,
|
||||
const char *param1, const char *param2);
|
||||
extern int event_init(void);
|
||||
extern void event_exit(void);
|
||||
|
||||
|
||||
@@ -382,7 +382,7 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_CONN_CLOSE("Closing connection %p (conn_ref_cnt=%d)", conn,
|
||||
TRACE_MGMT_DBG("Closing connection %p (conn_ref_cnt=%d)", conn,
|
||||
atomic_read(&conn->conn_ref_cnt));
|
||||
|
||||
iscsi_extracheck_is_rd_thread(conn);
|
||||
@@ -550,7 +550,8 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
TRACE_CONN_CLOSE("Notifying user space about closing connection %p",
|
||||
conn);
|
||||
event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE);
|
||||
event_send(target->tid, session->sid, conn->cid, 0, E_CONN_CLOSE,
|
||||
NULL, NULL);
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
mutex_lock(&target->target_mutex);
|
||||
|
||||
+184
-157
@@ -16,37 +16,40 @@
|
||||
#include "iscsi.h"
|
||||
#include "digest.h"
|
||||
|
||||
#define CHECK_PARAM(info, iparam, word, min, max) \
|
||||
do { \
|
||||
if (!(info)->partial || ((info)->partial & 1 << key_##word)) \
|
||||
if ((iparam)[key_##word] < (min) || \
|
||||
(iparam)[key_##word] > (max)) { \
|
||||
PRINT_ERROR("%s: %u is out of range (%u %u)", \
|
||||
#word, (iparam)[key_##word], (min), (max)); \
|
||||
if ((iparam)[key_##word] < (min)) \
|
||||
(iparam)[key_##word] = (min); \
|
||||
else \
|
||||
(iparam)[key_##word] = (max); \
|
||||
} \
|
||||
#define CHECK_PARAM(info, iparams, word, min, max) \
|
||||
do { \
|
||||
if (!(info)->partial || ((info)->partial & 1 << key_##word)) { \
|
||||
TRACE_DBG("%s: %u", #word, (iparams)[key_##word]); \
|
||||
if ((iparams)[key_##word] < (min) || \
|
||||
(iparams)[key_##word] > (max)) { \
|
||||
PRINT_ERROR("%s: %u is out of range (%u %u)", \
|
||||
#word, (iparams)[key_##word], (min), (max)); \
|
||||
if ((iparams)[key_##word] < (min)) \
|
||||
(iparams)[key_##word] = (min); \
|
||||
else \
|
||||
(iparams)[key_##word] = (max); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SET_PARAM(param, info, iparam, word) \
|
||||
({ \
|
||||
int changed = 0; \
|
||||
if (!(info)->partial || ((info)->partial & 1 << key_##word)) { \
|
||||
if ((param)->word != (iparam)[key_##word]) \
|
||||
changed = 1; \
|
||||
(param)->word = (iparam)[key_##word]; \
|
||||
} \
|
||||
changed; \
|
||||
#define SET_PARAM(params, info, iparams, word) \
|
||||
({ \
|
||||
int changed = 0; \
|
||||
if (!(info)->partial || ((info)->partial & 1 << key_##word)) { \
|
||||
if ((params)->word != (iparams)[key_##word]) \
|
||||
changed = 1; \
|
||||
(params)->word = (iparams)[key_##word]; \
|
||||
TRACE_DBG("%s set to %u", #word, (iparams)[key_##word]); \
|
||||
} \
|
||||
changed; \
|
||||
})
|
||||
|
||||
#define GET_PARAM(param, info, iparam, word) \
|
||||
do { \
|
||||
(iparam)[key_##word] = (param)->word; \
|
||||
#define GET_PARAM(params, info, iparams, word) \
|
||||
do { \
|
||||
(iparams)[key_##word] = (params)->word; \
|
||||
} while (0)
|
||||
|
||||
static const char *get_bool_name(int val)
|
||||
const char *iscsi_get_bool_value(int val)
|
||||
{
|
||||
if (val)
|
||||
return "Yes";
|
||||
@@ -54,210 +57,234 @@ static const char *get_bool_name(int val)
|
||||
return "No";
|
||||
}
|
||||
|
||||
static const char *get_digest_name(int val)
|
||||
const char *iscsi_get_digest_name(int val, char *res)
|
||||
{
|
||||
if (val == DIGEST_NONE)
|
||||
return "None";
|
||||
else if (val == DIGEST_CRC32C)
|
||||
return "CRC32C";
|
||||
else
|
||||
return "Unknown";
|
||||
int pos = 0;
|
||||
|
||||
if (val & DIGEST_NONE)
|
||||
pos = sprintf(&res[pos], "%s", "None");
|
||||
|
||||
if (val & DIGEST_CRC32C)
|
||||
pos += sprintf(&res[pos], "%s%s", (pos != 0) ? ", " : "",
|
||||
"CRC32C");
|
||||
|
||||
if (pos == 0)
|
||||
sprintf(&res[pos], "%s", "Unknown");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void log_params(struct iscsi_sess_param *param)
|
||||
static void log_params(struct iscsi_sess_params *params)
|
||||
{
|
||||
char digest_name[64];
|
||||
|
||||
PRINT_INFO("Negotiated parameters: InitialR2T %s, ImmediateData %s, "
|
||||
"MaxConnections %d, MaxRecvDataSegmentLength %d, "
|
||||
"MaxXmitDataSegmentLength %d, ",
|
||||
get_bool_name(param->initial_r2t),
|
||||
get_bool_name(param->immediate_data), param->max_connections,
|
||||
param->max_recv_data_length, param->max_xmit_data_length);
|
||||
iscsi_get_bool_value(params->initial_r2t),
|
||||
iscsi_get_bool_value(params->immediate_data), params->max_connections,
|
||||
params->max_recv_data_length, params->max_xmit_data_length);
|
||||
PRINT_INFO(" MaxBurstLength %d, FirstBurstLength %d, "
|
||||
"DefaultTime2Wait %d, DefaultTime2Retain %d, ",
|
||||
param->max_burst_length, param->first_burst_length,
|
||||
param->default_wait_time, param->default_retain_time);
|
||||
params->max_burst_length, params->first_burst_length,
|
||||
params->default_wait_time, params->default_retain_time);
|
||||
PRINT_INFO(" MaxOutstandingR2T %d, DataPDUInOrder %s, "
|
||||
"DataSequenceInOrder %s, ErrorRecoveryLevel %d, ",
|
||||
param->max_outstanding_r2t,
|
||||
get_bool_name(param->data_pdu_inorder),
|
||||
get_bool_name(param->data_sequence_inorder),
|
||||
param->error_recovery_level);
|
||||
params->max_outstanding_r2t,
|
||||
iscsi_get_bool_value(params->data_pdu_inorder),
|
||||
iscsi_get_bool_value(params->data_sequence_inorder),
|
||||
params->error_recovery_level);
|
||||
PRINT_INFO(" HeaderDigest %s, DataDigest %s, OFMarker %s, "
|
||||
"IFMarker %s, OFMarkInt %d, IFMarkInt %d",
|
||||
get_digest_name(param->header_digest),
|
||||
get_digest_name(param->data_digest),
|
||||
get_bool_name(param->ofmarker),
|
||||
get_bool_name(param->ifmarker),
|
||||
param->ofmarkint, param->ifmarkint);
|
||||
iscsi_get_digest_name(params->header_digest, digest_name),
|
||||
iscsi_get_digest_name(params->data_digest, digest_name),
|
||||
iscsi_get_bool_value(params->ofmarker),
|
||||
iscsi_get_bool_value(params->ifmarker),
|
||||
params->ofmarkint, params->ifmarkint);
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static void sess_param_check(struct iscsi_kern_param_info *info)
|
||||
static void sess_params_check(struct iscsi_kern_params_info *info)
|
||||
{
|
||||
int32_t *iparam = info->session_param;
|
||||
int32_t *iparams = info->session_params;
|
||||
const int max_len = ISCSI_CONN_IOV_MAX * PAGE_SIZE;
|
||||
|
||||
CHECK_PARAM(info, iparam, max_connections, 1, 1);
|
||||
CHECK_PARAM(info, iparam, max_recv_data_length, 512,
|
||||
(int32_t) (ISCSI_CONN_IOV_MAX * PAGE_SIZE));
|
||||
CHECK_PARAM(info, iparam, max_xmit_data_length, 512,
|
||||
(int32_t) (ISCSI_CONN_IOV_MAX * PAGE_SIZE));
|
||||
CHECK_PARAM(info, iparam, error_recovery_level, 0, 0);
|
||||
CHECK_PARAM(info, iparam, data_pdu_inorder, 0, 1);
|
||||
CHECK_PARAM(info, iparam, data_sequence_inorder, 0, 1);
|
||||
CHECK_PARAM(info, iparams, initial_r2t, 0, 1);
|
||||
CHECK_PARAM(info, iparams, immediate_data, 0, 1);
|
||||
CHECK_PARAM(info, iparams, max_connections, 1, 1);
|
||||
CHECK_PARAM(info, iparams, max_recv_data_length, 512, max_len);
|
||||
CHECK_PARAM(info, iparams, max_xmit_data_length, 512, max_len);
|
||||
CHECK_PARAM(info, iparams, max_burst_length, 512, max_len);
|
||||
CHECK_PARAM(info, iparams, first_burst_length, 512, max_len);
|
||||
CHECK_PARAM(info, iparams, max_outstanding_r2t, 1, 65535);
|
||||
CHECK_PARAM(info, iparams, error_recovery_level, 0, 0);
|
||||
CHECK_PARAM(info, iparams, data_pdu_inorder, 0, 1);
|
||||
CHECK_PARAM(info, iparams, data_sequence_inorder, 0, 1);
|
||||
|
||||
digest_alg_available(&iparam[key_header_digest]);
|
||||
digest_alg_available(&iparam[key_data_digest]);
|
||||
digest_alg_available(&iparams[key_header_digest]);
|
||||
digest_alg_available(&iparams[key_data_digest]);
|
||||
|
||||
CHECK_PARAM(info, iparam, ofmarker, 0, 0);
|
||||
CHECK_PARAM(info, iparam, ifmarker, 0, 0);
|
||||
CHECK_PARAM(info, iparams, ofmarker, 0, 0);
|
||||
CHECK_PARAM(info, iparams, ifmarker, 0, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static void sess_param_set(struct iscsi_sess_param *param,
|
||||
struct iscsi_kern_param_info *info)
|
||||
static void sess_params_set(struct iscsi_sess_params *params,
|
||||
struct iscsi_kern_params_info *info)
|
||||
{
|
||||
int32_t *iparam = info->session_param;
|
||||
int32_t *iparams = info->session_params;
|
||||
|
||||
SET_PARAM(param, info, iparam, initial_r2t);
|
||||
SET_PARAM(param, info, iparam, immediate_data);
|
||||
SET_PARAM(param, info, iparam, max_connections);
|
||||
SET_PARAM(param, info, iparam, max_recv_data_length);
|
||||
SET_PARAM(param, info, iparam, max_xmit_data_length);
|
||||
SET_PARAM(param, info, iparam, max_burst_length);
|
||||
SET_PARAM(param, info, iparam, first_burst_length);
|
||||
SET_PARAM(param, info, iparam, default_wait_time);
|
||||
SET_PARAM(param, info, iparam, default_retain_time);
|
||||
SET_PARAM(param, info, iparam, max_outstanding_r2t);
|
||||
SET_PARAM(param, info, iparam, data_pdu_inorder);
|
||||
SET_PARAM(param, info, iparam, data_sequence_inorder);
|
||||
SET_PARAM(param, info, iparam, error_recovery_level);
|
||||
SET_PARAM(param, info, iparam, header_digest);
|
||||
SET_PARAM(param, info, iparam, data_digest);
|
||||
SET_PARAM(param, info, iparam, ofmarker);
|
||||
SET_PARAM(param, info, iparam, ifmarker);
|
||||
SET_PARAM(param, info, iparam, ofmarkint);
|
||||
SET_PARAM(param, info, iparam, ifmarkint);
|
||||
SET_PARAM(params, info, iparams, initial_r2t);
|
||||
SET_PARAM(params, info, iparams, immediate_data);
|
||||
SET_PARAM(params, info, iparams, max_connections);
|
||||
SET_PARAM(params, info, iparams, max_recv_data_length);
|
||||
SET_PARAM(params, info, iparams, max_xmit_data_length);
|
||||
SET_PARAM(params, info, iparams, max_burst_length);
|
||||
SET_PARAM(params, info, iparams, first_burst_length);
|
||||
SET_PARAM(params, info, iparams, default_wait_time);
|
||||
SET_PARAM(params, info, iparams, default_retain_time);
|
||||
SET_PARAM(params, info, iparams, max_outstanding_r2t);
|
||||
SET_PARAM(params, info, iparams, data_pdu_inorder);
|
||||
SET_PARAM(params, info, iparams, data_sequence_inorder);
|
||||
SET_PARAM(params, info, iparams, error_recovery_level);
|
||||
SET_PARAM(params, info, iparams, header_digest);
|
||||
SET_PARAM(params, info, iparams, data_digest);
|
||||
SET_PARAM(params, info, iparams, ofmarker);
|
||||
SET_PARAM(params, info, iparams, ifmarker);
|
||||
SET_PARAM(params, info, iparams, ofmarkint);
|
||||
SET_PARAM(params, info, iparams, ifmarkint);
|
||||
return;
|
||||
}
|
||||
|
||||
static void sess_param_get(struct iscsi_sess_param *param,
|
||||
struct iscsi_kern_param_info *info)
|
||||
static void sess_params_get(struct iscsi_sess_params *params,
|
||||
struct iscsi_kern_params_info *info)
|
||||
{
|
||||
int32_t *iparam = info->session_param;
|
||||
int32_t *iparams = info->session_params;
|
||||
|
||||
GET_PARAM(param, info, iparam, initial_r2t);
|
||||
GET_PARAM(param, info, iparam, immediate_data);
|
||||
GET_PARAM(param, info, iparam, max_connections);
|
||||
GET_PARAM(param, info, iparam, max_recv_data_length);
|
||||
GET_PARAM(param, info, iparam, max_xmit_data_length);
|
||||
GET_PARAM(param, info, iparam, max_burst_length);
|
||||
GET_PARAM(param, info, iparam, first_burst_length);
|
||||
GET_PARAM(param, info, iparam, default_wait_time);
|
||||
GET_PARAM(param, info, iparam, default_retain_time);
|
||||
GET_PARAM(param, info, iparam, max_outstanding_r2t);
|
||||
GET_PARAM(param, info, iparam, data_pdu_inorder);
|
||||
GET_PARAM(param, info, iparam, data_sequence_inorder);
|
||||
GET_PARAM(param, info, iparam, error_recovery_level);
|
||||
GET_PARAM(param, info, iparam, header_digest);
|
||||
GET_PARAM(param, info, iparam, data_digest);
|
||||
GET_PARAM(param, info, iparam, ofmarker);
|
||||
GET_PARAM(param, info, iparam, ifmarker);
|
||||
GET_PARAM(param, info, iparam, ofmarkint);
|
||||
GET_PARAM(param, info, iparam, ifmarkint);
|
||||
GET_PARAM(params, info, iparams, initial_r2t);
|
||||
GET_PARAM(params, info, iparams, immediate_data);
|
||||
GET_PARAM(params, info, iparams, max_connections);
|
||||
GET_PARAM(params, info, iparams, max_recv_data_length);
|
||||
GET_PARAM(params, info, iparams, max_xmit_data_length);
|
||||
GET_PARAM(params, info, iparams, max_burst_length);
|
||||
GET_PARAM(params, info, iparams, first_burst_length);
|
||||
GET_PARAM(params, info, iparams, default_wait_time);
|
||||
GET_PARAM(params, info, iparams, default_retain_time);
|
||||
GET_PARAM(params, info, iparams, max_outstanding_r2t);
|
||||
GET_PARAM(params, info, iparams, data_pdu_inorder);
|
||||
GET_PARAM(params, info, iparams, data_sequence_inorder);
|
||||
GET_PARAM(params, info, iparams, error_recovery_level);
|
||||
GET_PARAM(params, info, iparams, header_digest);
|
||||
GET_PARAM(params, info, iparams, data_digest);
|
||||
GET_PARAM(params, info, iparams, ofmarker);
|
||||
GET_PARAM(params, info, iparams, ifmarker);
|
||||
GET_PARAM(params, info, iparams, ofmarkint);
|
||||
GET_PARAM(params, info, iparams, ifmarkint);
|
||||
return;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static void trgt_param_check(struct iscsi_kern_param_info *info)
|
||||
static void tgt_params_check(struct iscsi_kern_params_info *info)
|
||||
{
|
||||
int32_t *iparam = info->target_param;
|
||||
int32_t *iparams = info->target_params;
|
||||
|
||||
CHECK_PARAM(info, iparam, queued_cmnds, MIN_NR_QUEUED_CMNDS,
|
||||
CHECK_PARAM(info, iparams, queued_cmnds, MIN_NR_QUEUED_CMNDS,
|
||||
MAX_NR_QUEUED_CMNDS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static void trgt_param_set(struct iscsi_target *target,
|
||||
struct iscsi_kern_param_info *info)
|
||||
static void tgt_params_set(struct iscsi_tgt_params *params,
|
||||
struct iscsi_kern_params_info *info)
|
||||
{
|
||||
struct iscsi_trgt_param *param = &target->trgt_param;
|
||||
int32_t *iparam = info->target_param;
|
||||
int32_t *iparams = info->target_params;
|
||||
|
||||
SET_PARAM(param, info, iparam, queued_cmnds);
|
||||
SET_PARAM(params, info, iparams, queued_cmnds);
|
||||
return;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static void trgt_param_get(struct iscsi_trgt_param *param,
|
||||
struct iscsi_kern_param_info *info)
|
||||
static void tgt_params_get(struct iscsi_tgt_params *params,
|
||||
struct iscsi_kern_params_info *info)
|
||||
{
|
||||
int32_t *iparam = info->target_param;
|
||||
int32_t *iparams = info->target_params;
|
||||
|
||||
GET_PARAM(param, info, iparam, queued_cmnds);
|
||||
GET_PARAM(params, info, iparams, queued_cmnds);
|
||||
return;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static int trgt_param(struct iscsi_target *target,
|
||||
struct iscsi_kern_param_info *info, int set)
|
||||
static int iscsi_tgt_params_set(struct iscsi_session *session,
|
||||
struct iscsi_kern_params_info *info, int set)
|
||||
{
|
||||
struct iscsi_tgt_params *params = &session->tgt_params;
|
||||
|
||||
if (set) {
|
||||
struct iscsi_trgt_param *prm;
|
||||
trgt_param_check(info);
|
||||
trgt_param_set(target, info);
|
||||
|
||||
prm = &target->trgt_param;
|
||||
PRINT_INFO("Target parameter changed: QueuedCommands %d",
|
||||
prm->queued_cmnds);
|
||||
tgt_params_check(info);
|
||||
tgt_params_set(params, info);
|
||||
PRINT_INFO("Target parameters set for session %llx: "
|
||||
"QueuedCommands %d", session->sid,
|
||||
params->queued_cmnds);
|
||||
} else
|
||||
trgt_param_get(&target->trgt_param, info);
|
||||
tgt_params_get(params, info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static int sess_param(struct iscsi_target *target,
|
||||
struct iscsi_kern_param_info *info, int set)
|
||||
static int iscsi_sess_params_set(struct iscsi_session *session,
|
||||
struct iscsi_kern_params_info *info, int set)
|
||||
{
|
||||
struct iscsi_session *session = NULL;
|
||||
struct iscsi_sess_param *param;
|
||||
int err = -ENOENT;
|
||||
struct iscsi_sess_params *params;
|
||||
|
||||
if (set)
|
||||
sess_param_check(info);
|
||||
sess_params_check(info);
|
||||
|
||||
if (info->sid) {
|
||||
session = session_lookup(target, info->sid);
|
||||
if (!session)
|
||||
goto out;
|
||||
if (set && !list_empty(&session->conn_list)) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
param = &session->sess_param;
|
||||
} else
|
||||
param = &target->trgt_sess_param;
|
||||
params = &session->sess_params;
|
||||
|
||||
if (set) {
|
||||
sess_param_set(param, info);
|
||||
if (session != NULL)
|
||||
log_params(param);
|
||||
sess_params_set(params, info);
|
||||
log_params(params);
|
||||
} else
|
||||
sess_param_get(param, info);
|
||||
sess_params_get(params, info);
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
int iscsi_param_set(struct iscsi_target *target,
|
||||
struct iscsi_kern_param_info *info, int set)
|
||||
int iscsi_params_set(struct iscsi_target *target,
|
||||
struct iscsi_kern_params_info *info, int set)
|
||||
{
|
||||
int err;
|
||||
struct iscsi_session *session;
|
||||
|
||||
if (info->param_type == key_session)
|
||||
err = sess_param(target, info, set);
|
||||
else if (info->param_type == key_target)
|
||||
err = trgt_param(target, info, set);
|
||||
if (info->sid == 0) {
|
||||
PRINT_ERROR("sid must not be %d", 0);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
session = session_lookup(target, info->sid);
|
||||
if (session == NULL) {
|
||||
PRINT_ERROR("Session for sid %llx not found", info->sid);
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (set && !list_empty(&session->conn_list)) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info->params_type == key_session)
|
||||
err = iscsi_sess_params_set(session, info, set);
|
||||
else if (info->params_type == key_target)
|
||||
err = iscsi_tgt_params_set(session, info, set);
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
+158
-61
@@ -16,24 +16,6 @@
|
||||
|
||||
#include "iscsi.h"
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
int print_digest_state(char *p, size_t size, unsigned long flags)
|
||||
#else
|
||||
static int print_digest_state(char *p, size_t size, unsigned long flags)
|
||||
#endif
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (DIGEST_NONE & flags)
|
||||
pos = scnprintf(p, size, "%s", "none");
|
||||
else if (DIGEST_CRC32C & flags)
|
||||
pos = scnprintf(p, size, "%s", "crc32c");
|
||||
else
|
||||
pos = scnprintf(p, size, "%s", "unknown");
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
|
||||
{
|
||||
@@ -62,10 +44,7 @@ static int iscsi_session_alloc(struct iscsi_target *target,
|
||||
|
||||
session->target = target;
|
||||
session->sid = info->sid;
|
||||
session->sess_param = target->trgt_sess_param;
|
||||
session->max_queued_cmnds = target->trgt_param.queued_cmnds;
|
||||
atomic_set(&session->active_cmds, 0);
|
||||
|
||||
session->exp_cmd_sn = info->exp_cmd_sn;
|
||||
|
||||
session->initiator_name = kstrdup(info->initiator_name, GFP_KERNEL);
|
||||
@@ -74,6 +53,7 @@ static int iscsi_session_alloc(struct iscsi_target *target,
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
name = kmalloc(strlen(info->user_name) + strlen(info->initiator_name) +
|
||||
1, GFP_KERNEL);
|
||||
if (name == NULL) {
|
||||
@@ -85,6 +65,9 @@ static int iscsi_session_alloc(struct iscsi_target *target,
|
||||
sprintf(name, "%s@%s", info->user_name, info->initiator_name);
|
||||
else
|
||||
sprintf(name, "%s", info->initiator_name);
|
||||
#else
|
||||
name = info->initiator_name;
|
||||
#endif
|
||||
|
||||
INIT_LIST_HEAD(&session->conn_list);
|
||||
INIT_LIST_HEAD(&session->pending_list);
|
||||
@@ -105,7 +88,9 @@ static int iscsi_session_alloc(struct iscsi_target *target,
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
kfree(name);
|
||||
#endif
|
||||
|
||||
scst_sess_set_tgt_priv(session->scst_sess, session);
|
||||
|
||||
@@ -119,7 +104,9 @@ err:
|
||||
if (session) {
|
||||
kfree(session->initiator_name);
|
||||
kfree(session);
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
kfree(name);
|
||||
#endif
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -145,13 +132,14 @@ void sess_reinst_finished(struct iscsi_session *sess)
|
||||
}
|
||||
|
||||
/* target_mgmt_mutex supposed to be locked */
|
||||
int session_add(struct iscsi_target *target,
|
||||
int __add_session(struct iscsi_target *target,
|
||||
struct iscsi_kern_session_info *info)
|
||||
{
|
||||
struct iscsi_session *new_sess = NULL, *sess, *old_sess;
|
||||
int err = 0;
|
||||
int err = 0, i;
|
||||
union iscsi_sid sid;
|
||||
bool reinstatement = false;
|
||||
struct iscsi_kern_params_info *params_info;
|
||||
|
||||
TRACE_MGMT_DBG("Adding session SID %llx", info->sid);
|
||||
|
||||
@@ -169,6 +157,14 @@ int session_add(struct iscsi_target *target,
|
||||
goto out_err_unlock;
|
||||
}
|
||||
|
||||
params_info = kmalloc(sizeof(*params_info), GFP_KERNEL);
|
||||
if (params_info == NULL) {
|
||||
PRINT_ERROR("Unable to allocate params info (size %d)",
|
||||
sizeof(*params_info));
|
||||
err = -ENOMEM;
|
||||
goto out_err_unlock;
|
||||
}
|
||||
|
||||
sid = *(union iscsi_sid *)&info->sid;
|
||||
sid.id.tsih = 0;
|
||||
old_sess = NULL;
|
||||
@@ -194,6 +190,31 @@ int session_add(struct iscsi_target *target,
|
||||
|
||||
list_add_tail(&new_sess->session_list_entry, &target->session_list);
|
||||
|
||||
memset(params_info, 0, sizeof(*params_info));
|
||||
params_info->tid = target->tid;
|
||||
params_info->sid = info->sid;
|
||||
params_info->params_type = key_session;
|
||||
for (i = 0; i < session_key_last; i++)
|
||||
params_info->session_params[i] = info->session_params[i];
|
||||
|
||||
err = iscsi_params_set(target, params_info, 1);
|
||||
if (err != 0)
|
||||
goto out_del;
|
||||
|
||||
memset(params_info, 0, sizeof(*params_info));
|
||||
params_info->tid = target->tid;
|
||||
params_info->sid = info->sid;
|
||||
params_info->params_type = key_target;
|
||||
for (i = 0; i < target_key_last; i++)
|
||||
params_info->target_params[i] = info->target_params[i];
|
||||
|
||||
err = iscsi_params_set(target, params_info, 1);
|
||||
if (err != 0)
|
||||
goto out_del;
|
||||
|
||||
kfree(params_info);
|
||||
params_info = NULL;
|
||||
|
||||
if (old_sess != NULL) {
|
||||
reinstatement = true;
|
||||
|
||||
@@ -226,6 +247,10 @@ int session_add(struct iscsi_target *target,
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_del:
|
||||
list_del(&new_sess->session_list_entry);
|
||||
kfree(params_info);
|
||||
|
||||
out_err_unlock:
|
||||
mutex_unlock(&target->target_mutex);
|
||||
|
||||
@@ -312,7 +337,7 @@ int session_free(struct iscsi_session *session, bool del)
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
int session_del(struct iscsi_target *target, u64 sid)
|
||||
int __del_session(struct iscsi_target *target, u64 sid)
|
||||
{
|
||||
struct iscsi_session *session;
|
||||
|
||||
@@ -368,6 +393,76 @@ const struct file_operations session_seq_fops = {
|
||||
|
||||
#else /* CONFIG_SCST_PROC */
|
||||
|
||||
#define ISCSI_SESS_BOOL_PARAM_ATTR(name, exported_name) \
|
||||
static ssize_t iscsi_sess_show_##name(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, char *buf) \
|
||||
{ \
|
||||
int pos; \
|
||||
struct scst_session *scst_sess; \
|
||||
struct iscsi_session *sess; \
|
||||
\
|
||||
scst_sess = container_of(kobj, struct scst_session, sess_kobj); \
|
||||
sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess); \
|
||||
\
|
||||
pos = sprintf(buf, "%s\n", \
|
||||
iscsi_get_bool_value(sess->sess_params.name)); \
|
||||
\
|
||||
return pos; \
|
||||
} \
|
||||
\
|
||||
static struct kobj_attribute iscsi_sess_attr_##name = \
|
||||
__ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
|
||||
|
||||
#define ISCSI_SESS_INT_PARAM_ATTR(name, exported_name) \
|
||||
static ssize_t iscsi_sess_show_##name(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, char *buf) \
|
||||
{ \
|
||||
int pos; \
|
||||
struct scst_session *scst_sess; \
|
||||
struct iscsi_session *sess; \
|
||||
\
|
||||
scst_sess = container_of(kobj, struct scst_session, sess_kobj); \
|
||||
sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess); \
|
||||
\
|
||||
pos = sprintf(buf, "%d\n", sess->sess_params.name); \
|
||||
\
|
||||
return pos; \
|
||||
} \
|
||||
\
|
||||
static struct kobj_attribute iscsi_sess_attr_##name = \
|
||||
__ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
|
||||
|
||||
#define ISCSI_SESS_DIGEST_PARAM_ATTR(name, exported_name) \
|
||||
static ssize_t iscsi_sess_show_##name(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, char *buf) \
|
||||
{ \
|
||||
int pos; \
|
||||
struct scst_session *scst_sess; \
|
||||
struct iscsi_session *sess; \
|
||||
char digest_name[64]; \
|
||||
\
|
||||
scst_sess = container_of(kobj, struct scst_session, sess_kobj); \
|
||||
sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess); \
|
||||
\
|
||||
pos = sprintf(buf, "%s\n", iscsi_get_digest_name( \
|
||||
sess->sess_params.name, digest_name)); \
|
||||
\
|
||||
return pos; \
|
||||
} \
|
||||
\
|
||||
static struct kobj_attribute iscsi_sess_attr_##name = \
|
||||
__ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
|
||||
|
||||
ISCSI_SESS_BOOL_PARAM_ATTR(initial_r2t, InitialR2T);
|
||||
ISCSI_SESS_BOOL_PARAM_ATTR(immediate_data, ImmediateData);
|
||||
ISCSI_SESS_INT_PARAM_ATTR(max_recv_data_length, MaxRecvDataSegmentLength);
|
||||
ISCSI_SESS_INT_PARAM_ATTR(max_xmit_data_length, MaxXmitDataSegmentLength);
|
||||
ISCSI_SESS_INT_PARAM_ATTR(max_burst_length, MaxBurstLength);
|
||||
ISCSI_SESS_INT_PARAM_ATTR(first_burst_length, FirstBurstLength);
|
||||
ISCSI_SESS_INT_PARAM_ATTR(max_outstanding_r2t, MaxOutstandingR2T);
|
||||
ISCSI_SESS_DIGEST_PARAM_ATTR(header_digest, HeaderDigest);
|
||||
ISCSI_SESS_DIGEST_PARAM_ATTR(data_digest, DataDigest);
|
||||
|
||||
static ssize_t iscsi_sess_sid_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -386,7 +481,7 @@ static ssize_t iscsi_sess_sid_show(struct kobject *kobj,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute iscsi_sess_sid_attr =
|
||||
static struct kobj_attribute iscsi_attr_sess_sid =
|
||||
__ATTR(sid, S_IRUGO, iscsi_sess_sid_show, NULL);
|
||||
|
||||
static ssize_t iscsi_sess_reinstating_show(struct kobject *kobj,
|
||||
@@ -407,58 +502,60 @@ static ssize_t iscsi_sess_reinstating_show(struct kobject *kobj,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute iscsi_sess_reinstating_attr =
|
||||
static struct kobj_attribute iscsi_sess_attr_reinstating =
|
||||
__ATTR(reinstating, S_IRUGO, iscsi_sess_reinstating_show, NULL);
|
||||
|
||||
static ssize_t iscsi_sess_hdigest_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
static ssize_t iscsi_sess_force_close_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int pos;
|
||||
int res;
|
||||
struct scst_session *scst_sess;
|
||||
struct iscsi_session *sess;
|
||||
struct iscsi_conn *conn;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_sess = container_of(kobj, struct scst_session, sess_kobj);
|
||||
sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
|
||||
|
||||
pos = print_digest_state(buf, SCST_SYSFS_BLOCK_SIZE,
|
||||
sess->sess_param.header_digest);
|
||||
if (mutex_lock_interruptible(&sess->target->target_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
PRINT_INFO("Deleting session %llu with initiator %s (%p)",
|
||||
(long long unsigned int)sess->sid, sess->initiator_name, sess);
|
||||
|
||||
list_for_each_entry(conn, &sess->conn_list, conn_list_entry) {
|
||||
TRACE_MGMT_DBG("Deleting connection with initiator %p", conn);
|
||||
__mark_conn_closed(conn, ISCSI_CONN_ACTIVE_CLOSE|ISCSI_CONN_DELETING);
|
||||
}
|
||||
|
||||
mutex_unlock(&sess->target->target_mutex);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct kobj_attribute iscsi_sess_hdigest_attr =
|
||||
__ATTR(hdigest, S_IRUGO, iscsi_sess_hdigest_show, NULL);
|
||||
|
||||
static ssize_t iscsi_sess_ddigest_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos;
|
||||
struct scst_session *scst_sess;
|
||||
struct iscsi_session *sess;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
scst_sess = container_of(kobj, struct scst_session, sess_kobj);
|
||||
sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
|
||||
|
||||
pos = print_digest_state(buf, SCST_SYSFS_BLOCK_SIZE,
|
||||
sess->sess_param.data_digest);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute iscsi_sess_ddigest_attr =
|
||||
__ATTR(ddigest, S_IRUGO, iscsi_sess_ddigest_show, NULL);
|
||||
static struct kobj_attribute iscsi_sess_attr_force_close =
|
||||
__ATTR(force_close, S_IWUSR, NULL, iscsi_sess_force_close_store);
|
||||
|
||||
const struct attribute *iscsi_sess_attrs[] = {
|
||||
&iscsi_sess_sid_attr.attr,
|
||||
&iscsi_sess_reinstating_attr.attr,
|
||||
&iscsi_sess_hdigest_attr.attr,
|
||||
&iscsi_sess_ddigest_attr.attr,
|
||||
&iscsi_sess_attr_initial_r2t.attr,
|
||||
&iscsi_sess_attr_immediate_data.attr,
|
||||
&iscsi_sess_attr_max_recv_data_length.attr,
|
||||
&iscsi_sess_attr_max_xmit_data_length.attr,
|
||||
&iscsi_sess_attr_max_burst_length.attr,
|
||||
&iscsi_sess_attr_first_burst_length.attr,
|
||||
&iscsi_sess_attr_max_outstanding_r2t.attr,
|
||||
&iscsi_sess_attr_header_digest.attr,
|
||||
&iscsi_sess_attr_data_digest.attr,
|
||||
&iscsi_attr_sess_sid.attr,
|
||||
&iscsi_sess_attr_reinstating.attr,
|
||||
&iscsi_sess_attr_force_close.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
+219
-178
@@ -20,7 +20,6 @@
|
||||
#include "digest.h"
|
||||
|
||||
#define MAX_NR_TARGETS (1UL << 30)
|
||||
#define SYSFS_WAIT_TIMEOUT (15 * HZ)
|
||||
|
||||
DEFINE_MUTEX(target_mgmt_mutex);
|
||||
|
||||
@@ -42,7 +41,7 @@ struct iscsi_target *target_lookup_by_id(u32 id)
|
||||
}
|
||||
|
||||
/* target_mgmt_mutex supposed to be locked */
|
||||
static struct iscsi_target *target_lookup_by_name(char *name)
|
||||
static struct iscsi_target *target_lookup_by_name(const char *name)
|
||||
{
|
||||
struct iscsi_target *target;
|
||||
|
||||
@@ -54,7 +53,8 @@ static struct iscsi_target *target_lookup_by_name(char *name)
|
||||
}
|
||||
|
||||
/* target_mgmt_mutex supposed to be locked */
|
||||
static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid)
|
||||
static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid,
|
||||
struct iscsi_target **out_target)
|
||||
{
|
||||
int err = -EINVAL, len;
|
||||
char *name = info->name;
|
||||
@@ -81,11 +81,13 @@ static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid)
|
||||
|
||||
target->tid = info->tid = tid;
|
||||
|
||||
strncpy(target->name, name, sizeof(target->name) - 1);
|
||||
strlcpy(target->name, name, sizeof(target->name));
|
||||
|
||||
mutex_init(&target->target_mutex);
|
||||
mutex_init(&target->target_sysfs_mutex);
|
||||
INIT_LIST_HEAD(&target->session_list);
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
INIT_LIST_HEAD(&target->attrs_list);
|
||||
#endif
|
||||
|
||||
target->scst_tgt = scst_register(&iscsi_template, target->name);
|
||||
if (!target->scst_tgt) {
|
||||
@@ -98,6 +100,8 @@ static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid)
|
||||
|
||||
list_add_tail(&target->target_list_entry, &target_list);
|
||||
|
||||
*out_target = target;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
@@ -111,23 +115,51 @@ out:
|
||||
}
|
||||
|
||||
/* target_mgmt_mutex supposed to be locked */
|
||||
int target_add(struct iscsi_kern_target_info *info)
|
||||
int __add_target(struct iscsi_kern_target_info *info)
|
||||
{
|
||||
int err = -EEXIST;
|
||||
int err;
|
||||
u32 tid = info->tid;
|
||||
struct iscsi_target *target;
|
||||
struct iscsi_kern_params_info *params_info;
|
||||
struct iscsi_kern_attr *attr_info;
|
||||
union add_info_union {
|
||||
struct iscsi_kern_params_info params_info;
|
||||
struct iscsi_kern_attr attr_info;
|
||||
} *add_info;
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
int i, rc;
|
||||
unsigned long attrs_ptr_long;
|
||||
struct iscsi_kern_attr __user *attrs_ptr;
|
||||
#endif
|
||||
|
||||
if (nr_targets > MAX_NR_TARGETS) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (target_lookup_by_name(info->name))
|
||||
if (target_lookup_by_name(info->name)) {
|
||||
PRINT_ERROR("Target %s already exist!", info->name);
|
||||
err = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tid && target_lookup_by_id(tid))
|
||||
if (tid && target_lookup_by_id(tid)) {
|
||||
PRINT_ERROR("Target %u already exist!", tid);
|
||||
err = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!tid) {
|
||||
add_info = kmalloc(sizeof(*add_info), GFP_KERNEL);
|
||||
if (add_info == NULL) {
|
||||
PRINT_ERROR("Unable to allocate additional info (size %d)",
|
||||
sizeof(*add_info));
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
params_info = (struct iscsi_kern_params_info *)add_info;
|
||||
attr_info = (struct iscsi_kern_attr *)add_info;
|
||||
|
||||
if (tid == 0) {
|
||||
do {
|
||||
if (!++next_target_id)
|
||||
++next_target_id;
|
||||
@@ -136,116 +168,81 @@ int target_add(struct iscsi_kern_target_info *info)
|
||||
tid = next_target_id;
|
||||
}
|
||||
|
||||
err = iscsi_target_create(info, tid);
|
||||
if (!err)
|
||||
nr_targets++;
|
||||
err = iscsi_target_create(info, tid, &target);
|
||||
if (err != 0)
|
||||
goto out_free;
|
||||
|
||||
nr_targets++;
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
mutex_lock(&target->target_mutex);
|
||||
|
||||
attrs_ptr_long = info->attrs_ptr;
|
||||
attrs_ptr = (struct iscsi_kern_attr __user *)attrs_ptr_long;
|
||||
for (i = 0; i < info->attrs_num; i++) {
|
||||
memset(attr_info, 0, sizeof(*attr_info));
|
||||
|
||||
rc = copy_from_user(attr_info, attrs_ptr, sizeof(*attr_info));
|
||||
if (rc != 0) {
|
||||
PRINT_ERROR("copy_from_user() of users of target %s "
|
||||
"failed", info->name);
|
||||
err = -EFAULT;
|
||||
goto out_del_unlock;
|
||||
}
|
||||
|
||||
attr_info->name[sizeof(attr_info->name)-1] = '\0';
|
||||
|
||||
err = iscsi_add_attr(target, attr_info);
|
||||
if (err != 0)
|
||||
goto out_del_unlock;
|
||||
|
||||
attrs_ptr++;
|
||||
}
|
||||
|
||||
mutex_unlock(&target->target_mutex);
|
||||
#endif
|
||||
|
||||
err = tid;
|
||||
|
||||
out_free:
|
||||
kfree(add_info);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
out_del_unlock:
|
||||
mutex_unlock(&target->target_mutex);
|
||||
__del_target(tid);
|
||||
goto out_free;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void target_destroy(struct iscsi_target *target)
|
||||
{
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
struct iscsi_attr *attr, *t;
|
||||
#endif
|
||||
|
||||
TRACE_MGMT_DBG("Destroying target tid %u", target->tid);
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
list_for_each_entry_safe(attr, t, &target->attrs_list,
|
||||
attrs_list_entry) {
|
||||
__iscsi_del_attr(target, attr);
|
||||
}
|
||||
#endif
|
||||
|
||||
scst_unregister(target->scst_tgt);
|
||||
|
||||
kfree(target);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* target_mgmt_mutex supposed to be locked */
|
||||
int target_enable(struct iscsi_kern_target_info *info)
|
||||
{
|
||||
int res = 0;
|
||||
struct iscsi_target *tgt;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tgt = target_lookup_by_id(info->tid);
|
||||
if (tgt == NULL) {
|
||||
PRINT_ERROR("Target %d not found", info->tid);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&tgt->target_sysfs_mutex);
|
||||
|
||||
if (tgt->expected_ioctl != ENABLE_TARGET) {
|
||||
PRINT_ERROR("Unexpected ENABLE_TARGET IOCTL for target %d",
|
||||
tgt->tid);
|
||||
res = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
tgt->expected_ioctl = 0;
|
||||
|
||||
WARN_ON(tgt->tgt_enabled);
|
||||
tgt->tgt_enabled = 1;
|
||||
|
||||
tgt->ioctl_res = 0;
|
||||
|
||||
complete_all(tgt->target_enabling_cmpl);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&tgt->target_sysfs_mutex);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* target_mgmt_mutex supposed to be locked */
|
||||
int target_disable(struct iscsi_kern_target_info *info)
|
||||
{
|
||||
int res = 0;
|
||||
struct iscsi_target *tgt;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tgt = target_lookup_by_id(info->tid);
|
||||
if (tgt == NULL) {
|
||||
PRINT_ERROR("Target %d not found", info->tid);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&tgt->target_sysfs_mutex);
|
||||
|
||||
if (tgt->expected_ioctl != DISABLE_TARGET) {
|
||||
PRINT_ERROR("Unexpected DISABLE_TARGET IOCTL for target %d",
|
||||
tgt->tid);
|
||||
res = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
mutex_unlock(&tgt->target_sysfs_mutex);
|
||||
|
||||
mutex_lock(&tgt->target_mutex);
|
||||
target_del_all_sess(tgt, ISCSI_CONN_ACTIVE_CLOSE | ISCSI_CONN_DELETING);
|
||||
mutex_unlock(&tgt->target_mutex);
|
||||
|
||||
mutex_lock(&tgt->target_sysfs_mutex);
|
||||
|
||||
tgt->expected_ioctl = 0;
|
||||
|
||||
WARN_ON(!tgt->tgt_enabled);
|
||||
tgt->tgt_enabled = 0;
|
||||
|
||||
tgt->ioctl_res = 0;
|
||||
|
||||
complete_all(tgt->target_enabling_cmpl);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&tgt->target_sysfs_mutex);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* target_mgmt_mutex supposed to be locked */
|
||||
int target_del(u32 id)
|
||||
int __del_target(u32 id)
|
||||
{
|
||||
struct iscsi_target *target;
|
||||
int err;
|
||||
@@ -296,7 +293,7 @@ void target_del_session(struct iscsi_target *target,
|
||||
} else {
|
||||
TRACE_MGMT_DBG("Freeing session %p without connections",
|
||||
session);
|
||||
session_del(target, session->sid);
|
||||
__del_session(target, session->sid);
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
@@ -454,107 +451,90 @@ static ssize_t iscsi_tgt_tid_show(struct kobject *kobj,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute iscsi_tgt_tid_attr =
|
||||
static struct kobj_attribute iscsi_tgt_attr_tid =
|
||||
__ATTR(tid, S_IRUGO, iscsi_tgt_tid_show, NULL);
|
||||
|
||||
const struct attribute *iscsi_tgt_attrs[] = {
|
||||
&iscsi_tgt_tid_attr.attr,
|
||||
&iscsi_tgt_attr_tid.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ssize_t iscsi_sysfs_send_event(uint32_t tid, enum iscsi_kern_event_code code,
|
||||
const char *param1, const char *param2, void **data)
|
||||
{
|
||||
int res;
|
||||
struct scst_sysfs_user_info *info;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (ctr_open_state != ISCSI_CTR_OPEN_STATE_OPEN) {
|
||||
PRINT_ERROR("%s", "User space process not connected");
|
||||
res = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = scst_sysfs_user_add_info(&info);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
TRACE_DBG("Sending event %d (tid %d, param1 %s, param2 %s, cookie %d, "
|
||||
"info %p)", tid, code, param1, param2, info->info_cookie, info);
|
||||
|
||||
res = event_send(tid, 0, 0, info->info_cookie, code, param1, param2);
|
||||
if (res <= 0) {
|
||||
PRINT_ERROR("event_send() failed: %d", res);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* It may wait 30 secs in blocking connect to an unreacheable
|
||||
* iSNS server. It must be fixed, but not now. ToDo.
|
||||
*/
|
||||
res = scst_wait_info_completion(info, 31 * HZ);
|
||||
|
||||
if (data != NULL)
|
||||
*data = info->data;
|
||||
|
||||
out_free:
|
||||
scst_sysfs_user_del_info(info);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t iscsi_enable_target(struct scst_tgt *scst_tgt, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct iscsi_target *tgt =
|
||||
(struct iscsi_target *)scst_tgt_get_tgt_priv(scst_tgt);
|
||||
DECLARE_COMPLETION_ONSTACK(enabling_cmpl);
|
||||
int res = 0, rc, ioctl_res = 0;
|
||||
int res;
|
||||
bool enable;
|
||||
uint32_t type;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&tgt->target_sysfs_mutex);
|
||||
|
||||
if (tgt->target_enabling_cmpl != NULL) {
|
||||
TRACE_DBG("A sysfs command is being processed for target %d",
|
||||
tgt->tid);
|
||||
res = -ETXTBSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
tgt->target_enabling_cmpl = &enabling_cmpl;
|
||||
|
||||
switch (buf[0]) {
|
||||
case '0':
|
||||
if (!tgt->tgt_enabled) {
|
||||
TRACE_DBG("Target %d already disabled", tgt->tid);
|
||||
goto out_null_unlock;
|
||||
}
|
||||
enable = true;
|
||||
tgt->expected_ioctl = DISABLE_TARGET;
|
||||
res = event_send(tgt->tid, 0, 0, E_DISABLE_TARGET);
|
||||
if (res <= 0) {
|
||||
PRINT_ERROR("event_send() failed: %d", res);
|
||||
goto out_null_unlock;
|
||||
}
|
||||
type = E_DISABLE_TARGET;
|
||||
enable = false;
|
||||
break;
|
||||
case '1':
|
||||
if (tgt->tgt_enabled) {
|
||||
TRACE_DBG("Target %d already enabled", tgt->tid);
|
||||
goto out_null_unlock;
|
||||
}
|
||||
enable = false;
|
||||
tgt->expected_ioctl = ENABLE_TARGET;
|
||||
res = event_send(tgt->tid, 0, 0, E_ENABLE_TARGET);
|
||||
if (res <= 0) {
|
||||
PRINT_ERROR("event_send() failed: %d", res);
|
||||
goto out_null_unlock;
|
||||
}
|
||||
type = E_ENABLE_TARGET;
|
||||
enable = true;
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR("%s: Requested action not understood: %s",
|
||||
__func__, buf);
|
||||
res = -EINVAL;
|
||||
goto out_null_unlock;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_unlock(&tgt->target_sysfs_mutex);
|
||||
TRACE_DBG("%s target %d", enable ? "Enabling" : "Disabling", tgt->tid);
|
||||
|
||||
TRACE_DBG("Waiting for completion of enable/disable (%d) "
|
||||
"target %d", enable, tgt->tid);
|
||||
|
||||
rc = wait_for_completion_interruptible_timeout(&enabling_cmpl,
|
||||
SYSFS_WAIT_TIMEOUT);
|
||||
if (res == 0) {
|
||||
PRINT_ERROR("Timeout attempting to %s target %d",
|
||||
enable ? "enable" : "disable", tgt->tid);
|
||||
res = -EBUSY;
|
||||
/* go through */
|
||||
} else if (res < 0) {
|
||||
if (res != -ERESTARTSYS)
|
||||
PRINT_ERROR("wait_for_completion() failed: %d", res);
|
||||
/* go through */
|
||||
}
|
||||
|
||||
TRACE_DBG("Waiting for completion of enable/disable (%d) "
|
||||
"target %d finished with res %d", enable, tgt->tid, res);
|
||||
|
||||
mutex_lock(&tgt->target_sysfs_mutex);
|
||||
|
||||
ioctl_res = tgt->ioctl_res;
|
||||
|
||||
out_null_unlock:
|
||||
tgt->target_enabling_cmpl = NULL;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&tgt->target_sysfs_mutex);
|
||||
|
||||
if (res == 0) {
|
||||
res = ioctl_res;
|
||||
if (res == 0)
|
||||
res = size;
|
||||
}
|
||||
res = iscsi_sysfs_send_event(tgt->tid, type, NULL, NULL, NULL);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
@@ -567,4 +547,65 @@ bool iscsi_is_target_enabled(struct scst_tgt *scst_tgt)
|
||||
return tgt->tgt_enabled;
|
||||
}
|
||||
|
||||
ssize_t iscsi_sysfs_add_target(const char *target_name, const char *params)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = iscsi_sysfs_send_event(0, E_ADD_TARGET, target_name,
|
||||
params, NULL);
|
||||
if (res > 0) {
|
||||
/* It's tid */
|
||||
res = 0;
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t iscsi_sysfs_del_target(const char *target_name)
|
||||
{
|
||||
int res = 0, tid;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
/* We don't want to have tgt visible after the mutex unlock */
|
||||
{
|
||||
struct iscsi_target *tgt;
|
||||
mutex_lock(&target_mgmt_mutex);
|
||||
tgt = target_lookup_by_name(target_name);
|
||||
if (tgt == NULL) {
|
||||
PRINT_ERROR("Target %s not found", target_name);
|
||||
mutex_unlock(&target_mgmt_mutex);
|
||||
res = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
tid = tgt->tid;
|
||||
mutex_unlock(&target_mgmt_mutex);
|
||||
}
|
||||
|
||||
TRACE_DBG("Deleting target %s (tid %d)", target_name, tid);
|
||||
|
||||
res = iscsi_sysfs_send_event(tid, E_DEL_TARGET, NULL, NULL, NULL);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t iscsi_sysfs_mgmt_cmd(const char *cmd)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("Sending mgmt cmd %s", cmd);
|
||||
|
||||
res = iscsi_sysfs_send_event(0, E_MGMT_CMD, cmd, NULL, NULL);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
@@ -21,9 +21,12 @@ OBJS_D = $(SRCS_D:.c=.o)
|
||||
SRCS_ADM = iscsi_adm.c param.c
|
||||
OBJS_ADM = $(SRCS_ADM:.c=.o)
|
||||
|
||||
SCST_INC_DIR := ../../scst/include
|
||||
#SCST_INC_DIR := /usr/local/include/scst
|
||||
|
||||
CFLAGS += -O2 -fno-inline -Wall -Wextra -Wstrict-prototypes -Wno-sign-compare \
|
||||
-Wimplicit-function-declaration -Wno-unused-parameter \
|
||||
-Wno-missing-field-initializers -g -I../include
|
||||
-Wno-missing-field-initializers -g -I../include -I$(SCST_INC_DIR)
|
||||
CFLAGS += -D_GNU_SOURCE # required for glibc >= 2.8
|
||||
|
||||
PROGRAMS = iscsi-scstd iscsi-scst-adm
|
||||
|
||||
+13
-13
@@ -307,7 +307,8 @@ static inline void chap_encode_string(u8 *intnum, int buf_len, char *encode_buf,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void chap_calc_digest_md5(char chap_id, char *secret, int secret_len, u8 *challenge, int challenge_len, u8 *digest)
|
||||
static inline void chap_calc_digest_md5(char chap_id, const char *secret, int secret_len,
|
||||
const u8 *challenge, int challenge_len, u8 *digest)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
|
||||
@@ -318,7 +319,8 @@ static inline void chap_calc_digest_md5(char chap_id, char *secret, int secret_l
|
||||
MD5_Final(digest, &ctx);
|
||||
}
|
||||
|
||||
static inline void chap_calc_digest_sha1(char chap_id, char *secret, int secret_len, u8 *challenge, int challenge_len, u8 *digest)
|
||||
static inline void chap_calc_digest_sha1(char chap_id, const char *secret, int secret_len,
|
||||
const u8 *challenge, int challenge_len, u8 *digest)
|
||||
{
|
||||
SHA_CTX ctx;
|
||||
|
||||
@@ -389,8 +391,7 @@ static int chap_initiator_auth_check_response(struct connection *conn)
|
||||
int digest_len = 0, retval = 0, encoding_format;
|
||||
char pass[ISCSI_NAME_LEN];
|
||||
|
||||
memset(pass, 0, sizeof(pass));
|
||||
if (config_account_query(conn->tid, AUTH_DIR_INCOMING, pass, pass) < 0) {
|
||||
if (accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING)) {
|
||||
log_warning("CHAP initiator auth.: "
|
||||
"No CHAP credentials configured");
|
||||
retval = CHAP_TARGET_ERROR;
|
||||
@@ -408,7 +409,7 @@ static int chap_initiator_auth_check_response(struct connection *conn)
|
||||
}
|
||||
|
||||
memset(pass, 0, sizeof(pass));
|
||||
if (config_account_query(conn->tid, AUTH_DIR_INCOMING, value, pass) < 0) {
|
||||
if (config_account_query(conn->tid, ISCSI_USER_DIR_INCOMING, value, pass) < 0) {
|
||||
log_warning("CHAP initiator auth.: "
|
||||
"No valid user/pass combination for initiator %s "
|
||||
"found", conn->initiator);
|
||||
@@ -493,19 +494,18 @@ static int chap_target_auth_create_response(struct connection *conn)
|
||||
u8 *challenge = NULL, *digest = NULL;
|
||||
int encoding_format, response_len;
|
||||
int challenge_len = 0, digest_len = 0, retval = 0;
|
||||
char pass[ISCSI_NAME_LEN], name[ISCSI_NAME_LEN];
|
||||
struct iscsi_user *user;
|
||||
|
||||
if (!(value = text_key_find(conn, "CHAP_I"))) {
|
||||
/* initiator doesn't want target auth!? */
|
||||
/* Initiator doesn't want target auth!? */
|
||||
conn->state = STATE_SECURITY_DONE;
|
||||
retval = 0;
|
||||
goto out;
|
||||
}
|
||||
chap_id = strtol(value, &value, 10);
|
||||
|
||||
memset(pass, 0, sizeof(pass));
|
||||
memset(name, 0, sizeof(name));
|
||||
if (config_account_query(conn->tid, AUTH_DIR_OUTGOING, name, pass) < 0) {
|
||||
user = account_get_first(conn->tid, ISCSI_USER_DIR_OUTGOING);
|
||||
if (user == NULL) {
|
||||
log_warning("CHAP target auth.: "
|
||||
"no outgoing credentials configured%s",
|
||||
conn->tid ? "." : " for discovery.");
|
||||
@@ -588,11 +588,11 @@ static int chap_target_auth_create_response(struct connection *conn)
|
||||
|
||||
switch (conn->auth.chap.digest_alg) {
|
||||
case CHAP_DIGEST_ALG_MD5:
|
||||
chap_calc_digest_md5(chap_id, pass, strlen(pass),
|
||||
chap_calc_digest_md5(chap_id, user->password, strlen(user->password),
|
||||
challenge, challenge_len, digest);
|
||||
break;
|
||||
case CHAP_DIGEST_ALG_SHA1:
|
||||
chap_calc_digest_sha1(chap_id, pass, strlen(pass),
|
||||
chap_calc_digest_sha1(chap_id, user->password, strlen(user->password),
|
||||
challenge, challenge_len, digest);
|
||||
break;
|
||||
default:
|
||||
@@ -602,7 +602,7 @@ static int chap_target_auth_create_response(struct connection *conn)
|
||||
|
||||
memset(response, 0x0, response_len);
|
||||
chap_encode_string(digest, digest_len, response, encoding_format);
|
||||
text_key_add(conn, "CHAP_N", name);
|
||||
text_key_add(conn, "CHAP_N", user->name);
|
||||
text_key_add(conn, "CHAP_R", response);
|
||||
|
||||
conn->state = STATE_SECURITY_DONE;
|
||||
|
||||
+670
-242
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,8 @@
|
||||
struct connection *conn_alloc(void)
|
||||
{
|
||||
struct connection *conn;
|
||||
unsigned int session_params[session_key_last];
|
||||
int i;
|
||||
|
||||
conn = malloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
@@ -37,16 +39,20 @@ struct connection *conn_alloc(void)
|
||||
|
||||
memset(conn, 0, sizeof(*conn));
|
||||
conn->state = STATE_FREE;
|
||||
param_set_defaults(conn->session_param, session_keys);
|
||||
INIT_LIST_HEAD(&conn->rsp_buf_list);
|
||||
|
||||
params_set_defaults(session_params, session_keys);
|
||||
|
||||
for (i = 0; i < session_key_last; i++)
|
||||
conn->session_params[i].val = session_params[i];
|
||||
|
||||
out:
|
||||
return conn;
|
||||
}
|
||||
|
||||
void conn_free(struct connection *conn)
|
||||
{
|
||||
remque(&conn->clist);
|
||||
list_del(&conn->clist);
|
||||
free(conn->initiator);
|
||||
free(conn->user);
|
||||
free(conn);
|
||||
|
||||
+219
-34
@@ -17,6 +17,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -36,7 +37,7 @@ int kernel_open(int *max_data_seg_len)
|
||||
int devn;
|
||||
int ctlfd = -1;
|
||||
int err;
|
||||
struct iscsi_kern_register_info reg = { 0 };
|
||||
struct iscsi_kern_register_info reg;
|
||||
|
||||
if (!(f = fopen("/proc/devices", "r"))) {
|
||||
err = -errno;
|
||||
@@ -80,17 +81,18 @@ int kernel_open(int *max_data_seg_len)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
memset(®, 0, sizeof(reg));
|
||||
reg.version = (uintptr_t)ISCSI_SCST_INTERFACE_VERSION;
|
||||
|
||||
err = ioctl(ctlfd, REGISTER_USERD, ®);
|
||||
if (err < 0) {
|
||||
if (err != 0) {
|
||||
err = -errno;
|
||||
log_error("Unable to register: %s. Incompatible version of the "
|
||||
"kernel module?\n", strerror(errno));
|
||||
goto out_close;
|
||||
} else {
|
||||
log_debug(0, "MAX_DATA_SEG_LEN %d", err);
|
||||
*max_data_seg_len = err;
|
||||
*max_data_seg_len = reg.max_data_seg_len;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -104,32 +106,98 @@ out_err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
int kernel_target_create(u32 *tid, char *name)
|
||||
int kernel_target_create(struct target *target, u32 *tid, u32 cookie)
|
||||
{
|
||||
int err;
|
||||
int err, i, j;
|
||||
struct iscsi_kern_target_info info;
|
||||
struct iscsi_user *user;
|
||||
struct iscsi_kern_attr *kern_attrs;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
strlcpy(info.name, target->name, sizeof(info.name));
|
||||
info.tid = (tid != NULL) ? *tid : 0;
|
||||
info.cookie = cookie;
|
||||
|
||||
for (j = 0; j < session_key_last; j++) {
|
||||
if (session_keys[j].show_in_sysfs)
|
||||
info.attrs_num++;;
|
||||
}
|
||||
for (j = 0; j < target_key_last; j++) {
|
||||
if (target_keys[j].show_in_sysfs)
|
||||
info.attrs_num++;;
|
||||
}
|
||||
list_for_each_entry(user, &target->target_in_accounts, ulist) {
|
||||
info.attrs_num++;
|
||||
}
|
||||
list_for_each_entry(user, &target->target_out_accounts, ulist) {
|
||||
info.attrs_num++;
|
||||
}
|
||||
|
||||
kern_attrs = calloc(info.attrs_num, sizeof(*kern_attrs));
|
||||
if (kern_attrs == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
info.attrs_ptr = (unsigned long)kern_attrs;
|
||||
|
||||
i = 0;
|
||||
for (j = 0; j < session_key_last; j++) {
|
||||
if (!session_keys[j].show_in_sysfs)
|
||||
continue;
|
||||
kern_attrs[i].mode = 0644;
|
||||
strlcpy(kern_attrs[i].name, session_keys[j].name,
|
||||
sizeof(kern_attrs[i].name));
|
||||
i++;
|
||||
}
|
||||
for (j = 0; j < target_key_last; j++) {
|
||||
if (!target_keys[j].show_in_sysfs)
|
||||
continue;
|
||||
kern_attrs[i].mode = 0644;
|
||||
strlcpy(kern_attrs[i].name, target_keys[j].name,
|
||||
sizeof(kern_attrs[i].name));
|
||||
i++;
|
||||
}
|
||||
list_for_each_entry(user, &target->target_in_accounts, ulist) {
|
||||
kern_attrs[i].mode = 0600;
|
||||
strlcpy(kern_attrs[i].name, user->sysfs_name,
|
||||
sizeof(kern_attrs[i].name));
|
||||
i++;
|
||||
}
|
||||
list_for_each_entry(user, &target->target_out_accounts, ulist) {
|
||||
kern_attrs[i].mode = 0600;
|
||||
strlcpy(kern_attrs[i].name, user->sysfs_name,
|
||||
sizeof(kern_attrs[i].name));
|
||||
i++;
|
||||
}
|
||||
|
||||
log_debug(1, "Adding target %s (attrs_num %d)", target->name,
|
||||
info.attrs_num);
|
||||
|
||||
memcpy(info.name, name, sizeof(info.name) - 1);
|
||||
info.tid = *tid;
|
||||
if ((err = ioctl(ctrl_fd, ADD_TARGET, &info)) < 0) {
|
||||
err = -errno;
|
||||
log_error("Can't create target %u: %s\n", *tid,
|
||||
log_error("Can't create target %s: %s\n", target->name,
|
||||
strerror(errno));
|
||||
} else
|
||||
*tid = info.tid;
|
||||
} else {
|
||||
target->tid = err;
|
||||
if (tid != NULL)
|
||||
*tid = err;
|
||||
err = 0;
|
||||
}
|
||||
|
||||
free(kern_attrs);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int kernel_target_destroy(u32 tid)
|
||||
int kernel_target_destroy(u32 tid, u32 cookie)
|
||||
{
|
||||
struct iscsi_kern_target_info info;
|
||||
int res;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.tid = tid;
|
||||
info.cookie = cookie;
|
||||
|
||||
res = ioctl(ctrl_fd, DEL_TARGET, &info);
|
||||
if (res < 0) {
|
||||
@@ -140,6 +208,88 @@ int kernel_target_destroy(u32 tid)
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
|
||||
int kernel_attr_add(struct target *target, const char *name, u32 mode,
|
||||
u32 cookie)
|
||||
{
|
||||
struct iscsi_kern_attr_info info;
|
||||
int res;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (target != NULL)
|
||||
info.tid = target->tid;
|
||||
info.cookie = cookie;
|
||||
|
||||
info.attr.mode = mode;
|
||||
strlcpy(info.attr.name, name, sizeof(info.attr.name));
|
||||
|
||||
res = ioctl(ctrl_fd, ISCSI_ATTR_ADD, &info);
|
||||
if (res < 0)
|
||||
res = -errno;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int kernel_attr_del(struct target *target, const char *name, u32 cookie)
|
||||
{
|
||||
struct iscsi_kern_attr_info info;
|
||||
int res;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (target != NULL)
|
||||
info.tid = target->tid;
|
||||
info.cookie = cookie;
|
||||
|
||||
strlcpy(info.attr.name, name, sizeof(info.attr.name));
|
||||
|
||||
res = ioctl(ctrl_fd, ISCSI_ATTR_DEL, &info);
|
||||
if (res < 0)
|
||||
res = -errno;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int __kernel_user_cmd(struct iscsi_user *user, u32 cookie, unsigned int cmd)
|
||||
{
|
||||
struct iscsi_kern_attr_info info;
|
||||
int res;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (user->target != NULL)
|
||||
info.tid = user->target->tid;
|
||||
info.cookie = cookie;
|
||||
|
||||
info.attr.mode = 0600;
|
||||
strlcpy(info.attr.name, user->sysfs_name, sizeof(info.attr.name));
|
||||
|
||||
res = ioctl(ctrl_fd, cmd, &info);
|
||||
if (res < 0)
|
||||
res = -errno;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int kernel_user_add(struct iscsi_user *user, u32 cookie)
|
||||
{
|
||||
int res;
|
||||
res = __kernel_user_cmd(user, cookie, ISCSI_ATTR_ADD);
|
||||
if (res != 0)
|
||||
log_error("Can't add user %s (%d)\n", user->name, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int kernel_user_del(struct iscsi_user *user, u32 cookie)
|
||||
{
|
||||
int res;
|
||||
res = __kernel_user_cmd(user, cookie, ISCSI_ATTR_DEL);
|
||||
if (res != 0)
|
||||
log_error("Can't del user %s (%d)\n", user->name, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
int kernel_conn_destroy(u32 tid, u64 sid, u32 cid)
|
||||
{
|
||||
int err;
|
||||
@@ -158,82 +308,117 @@ int kernel_conn_destroy(u32 tid, u64 sid, u32 cid)
|
||||
return err;
|
||||
}
|
||||
|
||||
int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param)
|
||||
int kernel_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params)
|
||||
{
|
||||
int err, i;
|
||||
struct iscsi_kern_param_info info;
|
||||
struct iscsi_kern_params_info info;
|
||||
|
||||
if (sid == 0) {
|
||||
log_error("kernel_params_get(): sid must be not %d", 0);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.tid = tid;
|
||||
info.sid = sid;
|
||||
info.param_type = type;
|
||||
info.params_type = type;
|
||||
|
||||
if ((err = ioctl(ctrl_fd, ISCSI_PARAM_GET, &info)) < 0) {
|
||||
err = -errno;
|
||||
log_debug(1, "Can't get session param for session 0x%" PRIu64
|
||||
log_debug(1, "Can't get session params for session 0x%" PRIu64
|
||||
" (tid %u, err %d): %s\n", sid, tid, err, strerror(errno));
|
||||
}
|
||||
|
||||
if (type == key_session)
|
||||
for (i = 0; i < session_key_last; i++)
|
||||
param[i].val = info.session_param[i];
|
||||
params[i].val = info.session_params[i];
|
||||
else
|
||||
for (i = 0; i < target_key_last; i++)
|
||||
param[i].val = info.target_param[i];
|
||||
params[i].val = info.target_params[i];
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
|
||||
struct iscsi_param *param)
|
||||
int kernel_params_set(u32 tid, u64 sid, int type, u32 partial,
|
||||
const struct iscsi_param *params)
|
||||
{
|
||||
int i, err;
|
||||
struct iscsi_kern_param_info info;
|
||||
struct iscsi_kern_params_info info;
|
||||
|
||||
if (sid == 0) {
|
||||
log_error("kernel_params_set(): sid must be not %d", 0);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.tid = tid;
|
||||
info.sid = sid;
|
||||
info.param_type = type;
|
||||
info.params_type = type;
|
||||
info.partial = partial;
|
||||
|
||||
if (info.param_type == key_session)
|
||||
if (info.params_type == key_session)
|
||||
for (i = 0; i < session_key_last; i++)
|
||||
info.session_param[i] = param[i].val;
|
||||
info.session_params[i] = params[i].val;
|
||||
else
|
||||
for (i = 0; i < target_key_last; i++)
|
||||
info.target_param[i] = param[i].val;
|
||||
info.target_params[i] = params[i].val;
|
||||
|
||||
if ((err = ioctl(ctrl_fd, ISCSI_PARAM_SET, &info)) < 0) {
|
||||
err = -errno;
|
||||
log_error("Can't set session param for session 0x%" PRIu64
|
||||
log_error("Can't set session params for session 0x%" PRIu64
|
||||
" (tid %u, type %d, partial %d, err %d): %s\n", sid,
|
||||
tid, type, partial, err, strerror(errno));
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
|
||||
char *name, char *user)
|
||||
int kernel_session_create(struct connection *conn)
|
||||
{
|
||||
struct iscsi_kern_session_info info;
|
||||
int res;
|
||||
int res, i;
|
||||
struct target *target;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
info.tid = tid;
|
||||
info.sid = sid;
|
||||
info.exp_cmd_sn = exp_cmd_sn;
|
||||
strncpy(info.initiator_name, name, sizeof(info.initiator_name) - 1);
|
||||
strncpy(info.user_name, user, sizeof(info.user_name) - 1);
|
||||
info.tid = conn->tid;
|
||||
info.sid = conn->sess->sid.id64;
|
||||
info.exp_cmd_sn = conn->exp_cmd_sn;
|
||||
strlcpy(info.initiator_name, conn->sess->initiator, sizeof(info.initiator_name));
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
if (conn->user != NULL)
|
||||
strlcpy(info.user_name, conn->user, sizeof(info.user_name));
|
||||
else
|
||||
info.user_name[0] = '\0';
|
||||
#endif
|
||||
|
||||
target = target_find_by_id(conn->tid);
|
||||
if (target == NULL) {
|
||||
log_error("Target %d not found", conn->tid);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < session_key_last; i++)
|
||||
info.session_params[i] = conn->session_params[i].val;
|
||||
|
||||
for (i = 0; i < target_key_last; i++)
|
||||
info.target_params[i] = target->target_params[i];
|
||||
|
||||
res = ioctl(ctrl_fd, ADD_SESSION, &info);
|
||||
if (res < 0) {
|
||||
res = -errno;
|
||||
log_error("Can't create sess 0x%" PRIu64 " (tid %d, "
|
||||
"initiator %s): %s\n", sid, tid, name, strerror(errno));
|
||||
"initiator %s): %s\n", conn->sess->sid.id64, conn->tid,
|
||||
conn->sess->initiator, strerror(errno));
|
||||
}
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
+691
-43
@@ -24,13 +24,18 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <scst_const.h>
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
#define ISCSI_ISNS_SYSFS_ACCESS_CONTROL_ENABLED "AccessControl"
|
||||
|
||||
static struct sockaddr_nl src_addr, dest_addr;
|
||||
|
||||
static int nl_write(int fd, void *data, int len)
|
||||
@@ -63,6 +68,7 @@ static int nl_read(int fd, void *data, int len)
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct nlmsghdr nlh;
|
||||
int res;
|
||||
|
||||
iov[0].iov_base = &nlh;
|
||||
iov[0].iov_len = sizeof(nlh);
|
||||
@@ -75,14 +81,643 @@ static int nl_read(int fd, void *data, int len)
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 2;
|
||||
|
||||
return recvmsg(fd, &msg, MSG_DONTWAIT);
|
||||
res = recvmsg(fd, &msg, iscsi_enabled ? MSG_DONTWAIT : 0);
|
||||
if (res > 0) {
|
||||
res -= sizeof(nlh);
|
||||
if (res < 0)
|
||||
res = -EPIPE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
|
||||
static int send_mgmt_cmd_res(u32 tid, u32 cookie, u32 req_cmd, int result,
|
||||
const char *res_str)
|
||||
{
|
||||
struct iscsi_kern_mgmt_cmd_res_info cinfo;
|
||||
int res;
|
||||
|
||||
memset(&cinfo, 0, sizeof(cinfo));
|
||||
cinfo.tid = tid;
|
||||
cinfo.cookie = cookie;
|
||||
cinfo.req_cmd = req_cmd;
|
||||
cinfo.result = result;
|
||||
|
||||
if (res_str != NULL)
|
||||
strlcpy(cinfo.value, res_str, sizeof(cinfo.value));
|
||||
|
||||
log_debug(1, "Sending result %d (cookie %d)", result, cookie);
|
||||
|
||||
res = ioctl(ctrl_fd, MGMT_CMD_CALLBACK, &cinfo);
|
||||
if (res != 0) {
|
||||
log_error("Can't send mgmt reply (cookie %d, result %d, "
|
||||
"res %d): %s\n", cookie, result, res, strerror(errno));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_e_add_target(int fd, const struct iscsi_kern_event *event)
|
||||
{
|
||||
int res, rc;
|
||||
char *buf;
|
||||
int size, offs;
|
||||
|
||||
if (event->param1_size == 0) {
|
||||
log_error("Incorrect E_ADD_TARGET: %s", "Target name expected");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Params are not 0-terminated */
|
||||
|
||||
size = strlen("Target ") + event->param1_size + 2 + event->param2_size + 1;
|
||||
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
log_error("Unable to allocate tmp buffer (size %d)", size);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
offs = sprintf(buf, "Target ");
|
||||
|
||||
while (1) {
|
||||
if ((rc = nl_read(fd, &buf[offs], event->param1_size)) < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("read netlink fd (%d) failed: %s", fd,
|
||||
strerror(errno));
|
||||
send_mgmt_cmd_res(0, event->cookie, E_ADD_TARGET, -errno, NULL);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
offs += rc;
|
||||
offs += sprintf(&buf[offs], "; ");
|
||||
|
||||
if (event->param2_size > 0) {
|
||||
while (1) {
|
||||
if ((rc = nl_read(fd, &buf[offs], event->param2_size)) < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("read netlink fd (%d) failed: %s", fd,
|
||||
strerror(errno));
|
||||
send_mgmt_cmd_res(0, event->cookie, E_ADD_TARGET, -errno, NULL);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
offs += rc;
|
||||
}
|
||||
|
||||
buf[offs] = '\0';
|
||||
|
||||
log_debug(1, "Going to parse %s", buf);
|
||||
|
||||
res = config_parse_main(buf, event->cookie);
|
||||
if (res != 0)
|
||||
goto out_free;
|
||||
|
||||
out_free:
|
||||
free(buf);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_e_del_target(int fd, const struct iscsi_kern_event *event)
|
||||
{
|
||||
int res;
|
||||
|
||||
log_debug(2, "Going to delete target %d", event->tid);
|
||||
|
||||
res = target_del(event->tid, event->cookie);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_add_user(struct target *target, int dir, char *sysfs_name,
|
||||
char *p, u32 cookie)
|
||||
{
|
||||
int res;
|
||||
char *name, *pass;
|
||||
|
||||
name = config_sep_string(&p);
|
||||
pass = config_sep_string(&p);
|
||||
|
||||
res = __config_account_add(target, dir, name, pass, sysfs_name, 1, cookie);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_add_param(struct target *target, char *p, u32 cookie)
|
||||
{
|
||||
int res, dir;
|
||||
char *pp;
|
||||
|
||||
pp = config_sep_string(&p);
|
||||
dir = params_index_by_name_numwild(pp, user_keys);
|
||||
if (dir >= 0)
|
||||
res = handle_add_user(target, dir, pp, p, cookie);
|
||||
else {
|
||||
log_error("Syntax error at %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_del_user(struct target *target, int dir, char *p, u32 cookie)
|
||||
{
|
||||
int res;
|
||||
char *name;
|
||||
|
||||
name = config_sep_string(&p);
|
||||
|
||||
res = config_account_del((target != NULL) ? target->tid : 0, dir,
|
||||
name, cookie);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_del_param(struct target *target, char *p, u32 cookie)
|
||||
{
|
||||
int res, dir;
|
||||
char *pp;
|
||||
|
||||
pp = config_sep_string(&p);
|
||||
dir = params_index_by_name_numwild(pp, user_keys);
|
||||
if (dir >= 0)
|
||||
res = handle_del_user(target, dir, p, cookie);
|
||||
else {
|
||||
log_error("Syntax error at %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_e_mgmt_cmd(int fd, const struct iscsi_kern_event *event)
|
||||
{
|
||||
int res, rc;
|
||||
char *buf, *p, *pp;
|
||||
int size;
|
||||
|
||||
if (event->param1_size == 0) {
|
||||
log_error("Incorrect E_MGMT_CMD: %s", "command expected");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Params are not 0-terminated */
|
||||
|
||||
size = event->param1_size + 1;
|
||||
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
log_error("Unable to allocate tmp buffer (size %d)", size);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if ((rc = nl_read(fd, buf, event->param1_size)) < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("read netlink fd (%d) failed: %s", fd,
|
||||
strerror(errno));
|
||||
send_mgmt_cmd_res(0, event->cookie, E_MGMT_CMD, -errno, NULL);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
buf[rc] = '\0';
|
||||
|
||||
log_debug(1, "Going to parse %s", buf);
|
||||
|
||||
p = buf;
|
||||
pp = config_sep_string(&p);
|
||||
if (strcasecmp("add_attribute", pp) == 0) {
|
||||
res = handle_add_param(NULL, p, event->cookie);
|
||||
} else if (strcasecmp("add_target_attribute", pp) == 0) {
|
||||
struct target *target;
|
||||
pp = config_sep_string(&p);
|
||||
target = target_find_by_name(pp);
|
||||
if (target == NULL) {
|
||||
log_error("Target %s not found", pp);
|
||||
res = -ENOENT;
|
||||
goto out_free;
|
||||
}
|
||||
res = handle_add_param(target, p, event->cookie);
|
||||
} else if (strcasecmp("del_attribute", pp) == 0) {
|
||||
res = handle_del_param(NULL, p, event->cookie);
|
||||
} else if (strcasecmp("del_target_parameter", pp) == 0) {
|
||||
struct target *target;
|
||||
pp = config_sep_string(&p);
|
||||
target = target_find_by_name(pp);
|
||||
if (target == NULL) {
|
||||
log_error("Target %s not found", pp);
|
||||
res = -ENOENT;
|
||||
goto out_free;
|
||||
}
|
||||
res = handle_del_param(target, p, event->cookie);
|
||||
} else {
|
||||
log_error("Syntax error at %s", p);
|
||||
res = -EINVAL;
|
||||
}
|
||||
|
||||
out_free:
|
||||
free(buf);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void add_key_mark(char *res_str, int res_str_len, int new_line)
|
||||
{
|
||||
int offs = strlen(res_str);
|
||||
snprintf(&res_str[offs], res_str_len - offs, "%s%s\n",
|
||||
new_line ? "\n" : "", SCST_SYSFS_KEY_MARK);
|
||||
return;
|
||||
}
|
||||
|
||||
static int handle_e_get_attr_value(int fd, const struct iscsi_kern_event *event)
|
||||
{
|
||||
int res = 0, rc, idx;
|
||||
char *buf, *p, *pp;
|
||||
int size;
|
||||
struct target *target;
|
||||
char res_str[ISCSI_MAX_ATTR_VALUE_LEN];
|
||||
|
||||
memset(res_str, 0, sizeof(res_str));
|
||||
|
||||
if (event->param1_size == 0) {
|
||||
log_error("Incorrect E_GET_ATTR_VALUE: %s", "attr name expected");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Params are not 0-terminated */
|
||||
|
||||
size = event->param1_size + 1;
|
||||
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
log_error("Unable to allocate tmp buffer (size %d)", size);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if ((rc = nl_read(fd, buf, event->param1_size)) < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("read netlink fd (%d) failed: %s", fd,
|
||||
strerror(errno));
|
||||
send_mgmt_cmd_res(0, event->cookie, E_GET_ATTR_VALUE, -errno, NULL);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
buf[rc] = '\0';
|
||||
|
||||
log_debug(1, "Going to parse name %s", buf);
|
||||
|
||||
target = target_find_by_id(event->tid);
|
||||
|
||||
p = buf;
|
||||
pp = config_sep_string(&p);
|
||||
if (!((idx = params_index_by_name(pp, target_keys)) < 0)) {
|
||||
if (target == NULL) {
|
||||
log_error("Target expected for attr %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
params_val_to_str(target_keys, idx, target->target_params[idx],
|
||||
res_str, sizeof(res_str));
|
||||
|
||||
if (target->target_params[idx] != target_keys[idx].local_def)
|
||||
add_key_mark(res_str, sizeof(res_str), 1);
|
||||
} else if (!((idx = params_index_by_name(pp, session_keys)) < 0)) {
|
||||
if (target == NULL) {
|
||||
log_error("Target expected for attr %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
params_val_to_str(session_keys, idx, target->session_params[idx],
|
||||
res_str, sizeof(res_str));
|
||||
|
||||
if (target->session_params[idx] != session_keys[idx].local_def)
|
||||
add_key_mark(res_str, sizeof(res_str), 1);
|
||||
} else if (!((idx = params_index_by_name_numwild(pp, user_keys)) < 0)) {
|
||||
struct iscsi_user *user;
|
||||
|
||||
user = account_lookup_by_sysfs_name(target, idx, pp);
|
||||
if (user == NULL) {
|
||||
log_error("Unknown user attribute %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
snprintf(res_str, sizeof(res_str), "%s %s\n", user->name,
|
||||
user->password);
|
||||
add_key_mark(res_str, sizeof(res_str), 0);
|
||||
} else if (strcasecmp(ISCSI_ENABLED_ATTR_NAME, pp) == 0) {
|
||||
if (target != NULL) {
|
||||
log_error("Not NULL target %s for global attribute %s",
|
||||
target->name, pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
snprintf(res_str, sizeof(res_str), "%d\n", iscsi_enabled);
|
||||
} else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
|
||||
if (target != NULL) {
|
||||
log_error("Not NULL target %s for global attribute %s",
|
||||
target->name, pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (isns_server != NULL) {
|
||||
snprintf(res_str, sizeof(res_str), "%s %s\n", isns_server,
|
||||
isns_access_control ? ISCSI_ISNS_SYSFS_ACCESS_CONTROL_ENABLED : "");
|
||||
add_key_mark(res_str, sizeof(res_str), 0);
|
||||
} else
|
||||
snprintf(res_str, sizeof(res_str), "%s\n", "");
|
||||
} else {
|
||||
log_error("Unknown attribute %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
send_mgmt_cmd_res(event->tid, event->cookie, E_GET_ATTR_VALUE, 0, res_str);
|
||||
|
||||
out_free:
|
||||
free(buf);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
|
||||
{
|
||||
int res = 0, rc, idx;
|
||||
char *buf, *p, *pp, *n;
|
||||
struct target *target;
|
||||
int size, offs;
|
||||
u32 val;
|
||||
|
||||
if (event->param1_size == 0) {
|
||||
log_error("Incorrect E_SET_ATTR_VALUE: %s", "attr name expected");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (event->param2_size == 0) {
|
||||
log_error("Incorrect E_SET_ATTR_VALUE: %s", "attr value expected");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Params are not 0-terminated */
|
||||
size = event->param1_size + 1 + 1 + event->param2_size + 1;
|
||||
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
log_error("Unable to allocate tmp buffer (size %d)", size);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if ((rc = nl_read(fd, buf, event->param1_size)) < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("read netlink fd (%d) failed: %s", fd,
|
||||
strerror(errno));
|
||||
send_mgmt_cmd_res(0, event->cookie, E_SET_ATTR_VALUE, -errno, NULL);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
offs = rc;
|
||||
offs += sprintf(&buf[offs], " ");
|
||||
|
||||
while (1) {
|
||||
if ((rc = nl_read(fd, &buf[offs], event->param2_size)) < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("read netlink fd (%d) failed: %s", fd,
|
||||
strerror(errno));
|
||||
send_mgmt_cmd_res(0, event->cookie, E_SET_ATTR_VALUE, -errno, NULL);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
offs += rc;
|
||||
buf[offs] = '\0';
|
||||
|
||||
log_debug(1, "Going to parse %s", buf);
|
||||
|
||||
target = target_find_by_id(event->tid);
|
||||
|
||||
p = buf;
|
||||
pp = config_sep_string(&p);
|
||||
if (!((idx = params_index_by_name(pp, target_keys)) < 0)) {
|
||||
if (target == NULL) {
|
||||
log_error("Target expected for attr %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
pp = config_sep_string(&p);
|
||||
|
||||
n = config_sep_string(&p);
|
||||
if (*n != '\0') {
|
||||
log_error("Unexpected parameter value %s\n", n);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
res = params_str_to_val(target_keys, idx, pp, &val);
|
||||
if (res < 0) {
|
||||
log_error("Wrong value %s for parameter %s\n",
|
||||
pp, target_keys[idx].name);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
res = params_check_val(target_keys, idx, &val);
|
||||
if (res < 0) {
|
||||
log_error("Wrong value %u for parameter %s\n",
|
||||
val, target_keys[idx].name);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
target->target_params[idx] = val;
|
||||
} else if (!((idx = params_index_by_name(pp, session_keys)) < 0)) {
|
||||
if (target == NULL) {
|
||||
log_error("Target expected for attr %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
pp = config_sep_string(&p);
|
||||
|
||||
n = config_sep_string(&p);
|
||||
if (*n != '\0') {
|
||||
log_error("Unexpected parameter value %s\n", n);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
res = params_str_to_val(session_keys, idx, pp, &val);
|
||||
if (res < 0) {
|
||||
log_error("Wrong value %s for parameter %s\n",
|
||||
pp, session_keys[idx].name);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
res = params_check_val(session_keys, idx, &val);
|
||||
if (res < 0) {
|
||||
log_error("Wrong value %u for parameter %s\n",
|
||||
val, session_keys[idx].name);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
target->session_params[idx] = val;
|
||||
} else if (!((idx = params_index_by_name_numwild(pp, user_keys)) < 0)) {
|
||||
struct iscsi_user *user;
|
||||
|
||||
user = account_lookup_by_sysfs_name(target, idx, pp);
|
||||
if (user == NULL) {
|
||||
log_error("Unknown user attribute %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
res = account_replace(target, idx, pp, p);
|
||||
if (res != 0)
|
||||
goto out_free;
|
||||
} else if (strcasecmp(ISCSI_ENABLED_ATTR_NAME, pp) == 0) {
|
||||
if (target != NULL) {
|
||||
log_error("Not NULL target %s for global attribute %s",
|
||||
target->name, pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
pp = config_sep_string(&p);
|
||||
if (strcmp(pp, "1") == 0)
|
||||
iscsi_enabled = 1;
|
||||
else if (strcmp(pp, "0") == 0)
|
||||
iscsi_enabled = 0;
|
||||
else {
|
||||
log_error("Unknown value %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
} else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
|
||||
if (target != NULL) {
|
||||
log_error("Not NULL target %s for global attribute %s",
|
||||
target->name, pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (isns_server != NULL)
|
||||
isns_exit();
|
||||
|
||||
pp = config_sep_string(&p);
|
||||
if (*pp == '\0') {
|
||||
goto done;
|
||||
}
|
||||
|
||||
isns_access_control = 0;
|
||||
isns_server = strdup(pp);
|
||||
if (isns_server == NULL) {
|
||||
log_error("Unable to dublicate iSNS server name %s", pp);
|
||||
res = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
pp = config_sep_string(&p);
|
||||
if (strcasecmp(ISCSI_ISNS_SYSFS_ACCESS_CONTROL_ENABLED, pp) == 0) {
|
||||
pp = config_sep_string(&p);
|
||||
if (strcasecmp(pp, "No") == 0)
|
||||
isns_access_control = 0;
|
||||
else
|
||||
isns_access_control = 1;
|
||||
} else if (*pp != '\0') {
|
||||
log_error("Unknown parameter %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free_server;
|
||||
}
|
||||
|
||||
res = isns_init();
|
||||
if (res == 0) {
|
||||
struct target *t;
|
||||
int rc;
|
||||
|
||||
list_for_each_entry(t, &targets_list, tlist) {
|
||||
rc = isns_target_register(t->name);
|
||||
if (rc < 0) {
|
||||
/*
|
||||
* iSNS server can be temporary not
|
||||
* available.
|
||||
*/
|
||||
goto out_free_isns_exit;
|
||||
}
|
||||
}
|
||||
} else
|
||||
goto out_free_server;
|
||||
} else {
|
||||
log_error("Unknown attribute %s", pp);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
done:
|
||||
send_mgmt_cmd_res(event->tid, event->cookie, E_SET_ATTR_VALUE, 0, NULL);
|
||||
|
||||
out_free:
|
||||
free(buf);
|
||||
|
||||
out:
|
||||
return res;
|
||||
|
||||
out_free_isns_exit:
|
||||
isns_exit();
|
||||
|
||||
out_free_server:
|
||||
free(isns_server);
|
||||
isns_server = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
void handle_iscsi_events(int fd)
|
||||
{
|
||||
struct session *session;
|
||||
struct connection *conn;
|
||||
struct iscsi_kern_event event;
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
struct target *target;
|
||||
#endif
|
||||
int rc;
|
||||
|
||||
retry:
|
||||
@@ -91,63 +726,77 @@ retry:
|
||||
return;
|
||||
if (errno == EINTR)
|
||||
goto retry;
|
||||
log_error("read netlink fd (%d)", errno);
|
||||
log_error("read netlink fd (%d) failed: %s", fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
log_debug(1, "conn %u session %#" PRIx64 " target %u, code %u",
|
||||
event.cid, event.sid, event.tid, event.code);
|
||||
log_debug(1, "target %u, session %#" PRIx64 ", conn %u, code %u, cookie %d",
|
||||
event.tid, event.sid, event.cid, event.code, event.cookie);
|
||||
|
||||
/*
|
||||
* Let's always report errors through send_mgmt_cmd_res(). If the error
|
||||
* was returned by the corresponding ioctl(), it will lead to blank
|
||||
* MGMT_CMD_CALLBACK ioctl()'s, but that's OK, because kernel will
|
||||
* not reuse the cookie. Better to have extra return call, than no call
|
||||
* at all.
|
||||
*/
|
||||
|
||||
switch (event.code) {
|
||||
case E_ENABLE_TARGET:
|
||||
{
|
||||
struct target *target;
|
||||
struct iscsi_kern_target_info info;
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
case E_ADD_TARGET:
|
||||
rc = handle_e_add_target(fd, &event);
|
||||
if (rc != 0)
|
||||
send_mgmt_cmd_res(event.tid, event.cookie, E_ADD_TARGET, rc, NULL);
|
||||
break;
|
||||
|
||||
case E_DEL_TARGET:
|
||||
rc = handle_e_del_target(fd, &event);
|
||||
if (rc != 0)
|
||||
send_mgmt_cmd_res(event.tid, event.cookie, E_DEL_TARGET, rc, NULL);
|
||||
break;
|
||||
|
||||
case E_MGMT_CMD:
|
||||
rc = handle_e_mgmt_cmd(fd, &event);
|
||||
if (rc != 0)
|
||||
send_mgmt_cmd_res(event.tid, event.cookie, E_MGMT_CMD, rc, NULL);
|
||||
break;
|
||||
|
||||
case E_ENABLE_TARGET:
|
||||
target = target_find_by_id(event.tid);
|
||||
if (target == NULL) {
|
||||
log_error("Target %d not found", event.tid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
target->tgt_enabled = 1;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
info.tid = event.tid;
|
||||
rc = ioctl(ctrl_fd, ENABLE_TARGET, &info);
|
||||
if (rc < 0) {
|
||||
log_error("Can't enable target %u: %s\n", event.tid,
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
rc = -ENOENT;
|
||||
} else
|
||||
rc = 0;
|
||||
rc |= send_mgmt_cmd_res(event.tid, event.cookie, E_ENABLE_TARGET, rc, NULL);
|
||||
if (rc == 0)
|
||||
target->tgt_enabled = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case E_DISABLE_TARGET:
|
||||
{
|
||||
struct target *target;
|
||||
struct iscsi_kern_target_info info;
|
||||
|
||||
target = target_find_by_id(event.tid);
|
||||
if (target == NULL) {
|
||||
log_error("Target %d not found", event.tid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
target->tgt_enabled = 0;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
info.tid = event.tid;
|
||||
rc = ioctl(ctrl_fd, DISABLE_TARGET, &info);
|
||||
if (rc < 0) {
|
||||
log_error("Can't disable target %u: %s\n", event.tid,
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
rc = -ENOENT;
|
||||
} else
|
||||
rc = 0;
|
||||
rc |= send_mgmt_cmd_res(event.tid, event.cookie, E_DISABLE_TARGET, rc, NULL);
|
||||
if (rc == 0)
|
||||
target->tgt_enabled = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case E_GET_ATTR_VALUE:
|
||||
rc = handle_e_get_attr_value(fd, &event);
|
||||
if (rc != 0)
|
||||
send_mgmt_cmd_res(event.tid, event.cookie, E_GET_ATTR_VALUE, rc, NULL);
|
||||
break;
|
||||
|
||||
case E_SET_ATTR_VALUE:
|
||||
rc = handle_e_set_attr_value(fd, &event);
|
||||
if (rc != 0)
|
||||
send_mgmt_cmd_res(event.tid, event.cookie, E_SET_ATTR_VALUE, rc, NULL);
|
||||
break;
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
case E_CONN_CLOSE:
|
||||
session = session_find_id(event.tid, event.sid);
|
||||
@@ -175,7 +824,6 @@ retry:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+27
-30
@@ -245,9 +245,9 @@ out_close:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void show_iscsi_param(int type, struct iscsi_param *param)
|
||||
static void show_iscsi_params(int type, struct iscsi_param *param)
|
||||
{
|
||||
int i, nr;
|
||||
int i, nr, len;
|
||||
char buf[1024], *p;
|
||||
struct iscsi_key *keys;
|
||||
|
||||
@@ -261,10 +261,11 @@ static void show_iscsi_param(int type, struct iscsi_param *param)
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
strcpy(buf, keys[i].name);
|
||||
p = buf + strlen(buf);
|
||||
strlcpy(buf, keys[i].name, sizeof(buf));
|
||||
len = strlen(buf);
|
||||
p = buf + len;
|
||||
*p++ = '=';
|
||||
param_val_to_str(keys, i, param[i].val, p);
|
||||
params_val_to_str(keys, i, param[i].val, p, sizeof(buf) - (len + 1));
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
}
|
||||
@@ -282,31 +283,31 @@ static int parse_trgt_params(struct msg_trgt *msg, char *params)
|
||||
continue;
|
||||
*q++ = '\0';
|
||||
|
||||
if (!((idx = param_index_by_name(p, target_keys)) < 0)) {
|
||||
if (param_str_to_val(target_keys, idx, q, &val)) {
|
||||
if (!((idx = params_index_by_name(p, target_keys)) < 0)) {
|
||||
if (params_str_to_val(target_keys, idx, q, &val)) {
|
||||
fprintf(stderr,
|
||||
"Invalid %s value \"%s\".\n",
|
||||
target_keys[idx].name, q);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!param_check_val(target_keys, idx, &val))
|
||||
if (!params_check_val(target_keys, idx, &val))
|
||||
msg->target_partial |= (1 << idx);
|
||||
msg->target_param[idx].val = val;
|
||||
msg->target_params[idx].val = val;
|
||||
msg->type |= 1 << key_target;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!((idx = param_index_by_name(p, session_keys)) < 0)) {
|
||||
if (param_str_to_val(session_keys, idx, q, &val)) {
|
||||
if (!((idx = params_index_by_name(p, session_keys)) < 0)) {
|
||||
if (params_str_to_val(session_keys, idx, q, &val)) {
|
||||
fprintf(stderr,
|
||||
"Invalid %s value \"%s\".\n",
|
||||
session_keys[idx].name, q);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!param_check_val(session_keys, idx, &val))
|
||||
if (!params_check_val(session_keys, idx, &val))
|
||||
msg->session_partial |= (1 << idx);
|
||||
msg->session_param[idx].val = val;
|
||||
msg->session_params[idx].val = val;
|
||||
msg->type |= 1 << key_session;
|
||||
|
||||
continue;
|
||||
@@ -346,7 +347,7 @@ static int trgt_handle(int op, u32 set, u32 tid, char *params)
|
||||
goto out;
|
||||
}
|
||||
req.rcmnd = C_TRGT_NEW;
|
||||
strncpy(req.u.trgt.name, p, sizeof(req.u.trgt.name) - 1);
|
||||
strlcpy(req.u.trgt.name, p, sizeof(req.u.trgt.name));
|
||||
break;
|
||||
}
|
||||
case OP_DELETE:
|
||||
@@ -364,7 +365,7 @@ static int trgt_handle(int op, u32 set, u32 tid, char *params)
|
||||
|
||||
err = iscsid_request(&req, NULL, 0);
|
||||
if (!err && req.rcmnd == C_TRGT_SHOW)
|
||||
show_iscsi_param(key_target, req.u.trgt.target_param);
|
||||
show_iscsi_params(key_target, req.u.trgt.target_params);
|
||||
|
||||
out:
|
||||
return err;
|
||||
@@ -395,7 +396,7 @@ static int sess_handle(int op, u32 set, u32 tid, u64 sid, char *params)
|
||||
req.rcmnd = C_SESS_SHOW;
|
||||
err = iscsid_request(&req, NULL, 0);
|
||||
if (!err)
|
||||
show_iscsi_param(key_session, req.u.trgt.session_param);
|
||||
show_iscsi_params(key_session, req.u.trgt.session_params);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -424,14 +425,14 @@ static int parse_user_params(char *params, u32 *auth_dir, char **user,
|
||||
"Already specified IncomingUser %s\n",
|
||||
q);
|
||||
*user = q;
|
||||
*auth_dir = AUTH_DIR_INCOMING;
|
||||
*auth_dir = ISCSI_USER_DIR_INCOMING;
|
||||
} else if (!strcasecmp(p, "OutgoingUser")) {
|
||||
if (*user)
|
||||
fprintf(stderr,
|
||||
"Already specified OutgoingUser %s\n",
|
||||
q);
|
||||
*user = q;
|
||||
*auth_dir = AUTH_DIR_OUTGOING;
|
||||
*auth_dir = ISCSI_USER_DIR_OUTGOING;
|
||||
} else if (!strcasecmp(p, "Password")) {
|
||||
if (*pass)
|
||||
fprintf(stderr,
|
||||
@@ -453,7 +454,7 @@ static void show_account(int auth_dir, char *user, char *pass)
|
||||
if (pass)
|
||||
snprintf(buf + strlen(buf), ISCSI_NAME_LEN, " %s", pass);
|
||||
|
||||
printf("%sUser %s\n", (auth_dir == AUTH_DIR_INCOMING) ?
|
||||
printf("%sUser %s\n", (auth_dir == ISCSI_USER_DIR_INCOMING) ?
|
||||
"Incoming" : "Outgoing", buf);
|
||||
}
|
||||
|
||||
@@ -462,8 +463,7 @@ static int user_handle_show_user(struct iscsi_adm_req *req, char *user)
|
||||
int err;
|
||||
|
||||
req->rcmnd = C_ACCT_SHOW;
|
||||
strncpy(req->u.acnt.u.user.name, user,
|
||||
sizeof(req->u.acnt.u.user.name) - 1);
|
||||
strlcpy(req->u.acnt.u.user.name, user, sizeof(req->u.acnt.u.user.name));
|
||||
|
||||
err = iscsid_request(req, NULL, 0);
|
||||
if (!err)
|
||||
@@ -479,7 +479,7 @@ static int user_handle_show_list(struct iscsi_adm_req *req)
|
||||
size_t buf_sz = 0;
|
||||
char *buf;
|
||||
|
||||
req->u.acnt.auth_dir = AUTH_DIR_INCOMING;
|
||||
req->u.acnt.auth_dir = ISCSI_USER_DIR_INCOMING;
|
||||
req->rcmnd = C_ACCT_LIST;
|
||||
|
||||
do {
|
||||
@@ -513,8 +513,8 @@ static int user_handle_show_list(struct iscsi_adm_req *req)
|
||||
show_account(req->u.acnt.auth_dir,
|
||||
&buf[i * ISCSI_NAME_LEN], NULL);
|
||||
|
||||
if (req->u.acnt.auth_dir == AUTH_DIR_INCOMING) {
|
||||
req->u.acnt.auth_dir = AUTH_DIR_OUTGOING;
|
||||
if (req->u.acnt.auth_dir == ISCSI_USER_DIR_INCOMING) {
|
||||
req->u.acnt.auth_dir = ISCSI_USER_DIR_OUTGOING;
|
||||
buf_sz = 0;
|
||||
retry = 1;
|
||||
}
|
||||
@@ -546,10 +546,8 @@ static int user_handle_new(struct iscsi_adm_req *req, char *user, char *pass)
|
||||
|
||||
req->rcmnd = C_ACCT_NEW;
|
||||
|
||||
strncpy(req->u.acnt.u.user.name, user,
|
||||
sizeof(req->u.acnt.u.user.name) - 1);
|
||||
strncpy(req->u.acnt.u.user.pass, pass,
|
||||
sizeof(req->u.acnt.u.user.pass) - 1);
|
||||
strlcpy(req->u.acnt.u.user.name, user, sizeof(req->u.acnt.u.user.name));
|
||||
strlcpy(req->u.acnt.u.user.pass, pass, sizeof(req->u.acnt.u.user.pass));
|
||||
|
||||
return iscsid_request(req, NULL, 0);
|
||||
}
|
||||
@@ -566,8 +564,7 @@ static int user_handle_del(struct iscsi_adm_req *req, char *user, char *pass)
|
||||
|
||||
req->rcmnd = C_ACCT_DEL;
|
||||
|
||||
strncpy(req->u.acnt.u.user.name, user,
|
||||
sizeof(req->u.acnt.u.user.name) - 1);
|
||||
strlcpy(req->u.acnt.u.user.name, user, sizeof(req->u.acnt.u.user.name));
|
||||
|
||||
return iscsid_request(req, NULL, 0);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ struct msg_trgt {
|
||||
u32 type;
|
||||
u32 session_partial;
|
||||
u32 target_partial;
|
||||
struct iscsi_param session_param[session_key_last];
|
||||
struct iscsi_param target_param[target_key_last];
|
||||
struct iscsi_param session_params[session_key_last];
|
||||
struct iscsi_param target_params[target_key_last];
|
||||
};
|
||||
|
||||
struct msg_acnt {
|
||||
|
||||
@@ -465,7 +465,7 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void event_loop(int timeout)
|
||||
static void event_loop(void)
|
||||
{
|
||||
int res, i;
|
||||
|
||||
@@ -491,9 +491,13 @@ static void event_loop(int timeout)
|
||||
close(init_report_pipe[1]);
|
||||
|
||||
while (1) {
|
||||
res = poll(poll_array, POLL_MAX, timeout);
|
||||
if (!iscsi_enabled) {
|
||||
handle_iscsi_events(nl_fd);
|
||||
continue;
|
||||
}
|
||||
res = poll(poll_array, POLL_MAX, isns_timeout);
|
||||
if (res == 0) {
|
||||
isns_handle(1, &timeout);
|
||||
isns_handle(1);
|
||||
continue;
|
||||
} else if (res < 0) {
|
||||
if (errno == EINTR)
|
||||
@@ -531,7 +535,7 @@ static void event_loop(int timeout)
|
||||
iscsi_adm_request_handle(ipc_fd);
|
||||
|
||||
if (poll_array[POLL_ISNS].revents)
|
||||
isns_handle(0, &timeout);
|
||||
isns_handle(0);
|
||||
|
||||
if (poll_array[POLL_SCN_LISTEN].revents)
|
||||
isns_scn_handle(1);
|
||||
@@ -562,7 +566,7 @@ static void event_loop(int timeout)
|
||||
}
|
||||
}
|
||||
|
||||
void init_max_data_seg_len(int max_data_seg_len)
|
||||
static void init_max_data_seg_len(int max_data_seg_len)
|
||||
{
|
||||
if ((session_keys[key_max_recv_data_length].local_def != -1) ||
|
||||
(session_keys[key_max_recv_data_length].max != -1) ||
|
||||
@@ -597,13 +601,16 @@ void init_max_data_seg_len(int max_data_seg_len)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ch, longindex, timeout = -1;
|
||||
int ch, longindex;
|
||||
char *config = NULL;
|
||||
uid_t uid = 0;
|
||||
gid_t gid = 0;
|
||||
char *isns = NULL;
|
||||
int isns_ac = 0;
|
||||
int max_data_seg_len = -1;
|
||||
int err;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
iscsi_enabled = 1;
|
||||
#endif
|
||||
|
||||
if (pipe(init_report_pipe) == -1) {
|
||||
perror("pipe failed");
|
||||
@@ -666,6 +673,18 @@ int main(int argc, char **argv)
|
||||
|
||||
init_max_data_seg_len(max_data_seg_len);
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
err = kernel_attr_add(NULL, ISCSI_ISNS_SERVER_PARAM_NAME,
|
||||
S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR, 0);
|
||||
if (err != 0)
|
||||
exit(err);
|
||||
|
||||
err = kernel_attr_add(NULL, ISCSI_ENABLED_ATTR_NAME,
|
||||
S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR, 0);
|
||||
if (err != 0)
|
||||
exit(err);
|
||||
#endif
|
||||
|
||||
if ((ipc_fd = iscsi_adm_request_listen()) < 0) {
|
||||
perror("ipc failed\n");
|
||||
exit(-1);
|
||||
@@ -722,11 +741,8 @@ int main(int argc, char **argv)
|
||||
setsid();
|
||||
}
|
||||
|
||||
config_isns_load(config, &isns, &isns_ac);
|
||||
if (isns)
|
||||
timeout = isns_init(isns, isns_ac);
|
||||
|
||||
if (config_load(config) != 0)
|
||||
err = config_load(config);
|
||||
if (err != 0)
|
||||
exit(1);
|
||||
|
||||
if (gid && setgid(gid) < 0)
|
||||
@@ -735,7 +751,7 @@ int main(int argc, char **argv)
|
||||
if (uid && setuid(uid) < 0)
|
||||
perror("setuid failed");
|
||||
|
||||
event_loop(timeout);
|
||||
event_loop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+56
-49
@@ -26,6 +26,8 @@
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
int iscsi_enabled;
|
||||
|
||||
static u32 ttt;
|
||||
|
||||
static u32 get_next_ttt(struct connection *conn __attribute__((unused)))
|
||||
@@ -39,7 +41,7 @@ static struct iscsi_key login_keys[] = {
|
||||
{"InitiatorAlias",},
|
||||
{"SessionType",},
|
||||
{"TargetName",},
|
||||
{NULL, 0, 0, 0, 0, NULL},
|
||||
{NULL,},
|
||||
};
|
||||
|
||||
char *text_key_find(struct connection *conn, char *searchKey)
|
||||
@@ -67,7 +69,7 @@ char *text_key_find(struct connection *conn, char *searchKey)
|
||||
datasize--;
|
||||
|
||||
if (keylen == value - key - 1
|
||||
&& !strncmp(key, searchKey, keylen))
|
||||
&& !strncasecmp(key, searchKey, keylen))
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -114,7 +116,7 @@ static struct buf_segment *conn_alloc_buf_segment(struct connection *conn,
|
||||
return seg;
|
||||
}
|
||||
|
||||
void text_key_add(struct connection *conn, char *key, char *value)
|
||||
void text_key_add(struct connection *conn, char *key, const char *value)
|
||||
{
|
||||
struct buf_segment *seg;
|
||||
int keylen = strlen(key);
|
||||
@@ -126,7 +128,7 @@ void text_key_add(struct connection *conn, char *key, char *value)
|
||||
size_t data_sz;
|
||||
|
||||
data_sz = (conn->state == STATE_FULL) ?
|
||||
conn->session_param[key_max_xmit_data_length].val :
|
||||
conn->session_params[key_max_xmit_data_length].val :
|
||||
INCOMING_BUFSIZE;
|
||||
|
||||
seg = list_empty(&conn->rsp_buf_list) ? NULL :
|
||||
@@ -190,14 +192,6 @@ static void text_key_add_reject(struct connection *conn, char *key)
|
||||
text_key_add(conn, key, "Reject");
|
||||
}
|
||||
|
||||
static int account_empty(u32 tid, int dir)
|
||||
{
|
||||
char pass[ISCSI_NAME_LEN];
|
||||
|
||||
memset(pass, 0, sizeof(pass));
|
||||
return config_account_query(tid, dir, pass, pass) < 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
static void text_scan_security(struct connection *conn)
|
||||
{
|
||||
struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
|
||||
@@ -208,7 +202,7 @@ static void text_scan_security(struct connection *conn)
|
||||
datasize = conn->req.datasize;
|
||||
|
||||
while ((key = next_key(&data, &datasize, &value))) {
|
||||
if (!(param_index_by_name(key, login_keys) < 0))
|
||||
if (!(params_index_by_name(key, login_keys) < 0))
|
||||
;
|
||||
else if (!strcmp(key, "AuthMethod")) {
|
||||
do {
|
||||
@@ -217,13 +211,13 @@ static void text_scan_security(struct connection *conn)
|
||||
*nextValue++ = 0;
|
||||
|
||||
if (!strcmp(value, "None")) {
|
||||
if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
|
||||
if (!accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
|
||||
continue;
|
||||
conn->auth_method = AUTH_NONE;
|
||||
text_key_add(conn, key, "None");
|
||||
break;
|
||||
} else if (!strcmp(value, "CHAP")) {
|
||||
if (account_empty(conn->tid, AUTH_DIR_INCOMING))
|
||||
if (accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
|
||||
continue;
|
||||
conn->auth_method = AUTH_CHAP;
|
||||
text_key_add(conn, key, "CHAP");
|
||||
@@ -285,7 +279,7 @@ static int login_check_reinstatement(struct connection *conn)
|
||||
"initiator %s)", conn->cid, conn->tid,
|
||||
req->sid.id64, conn->initiator);
|
||||
conn->sess = session;
|
||||
insque(&conn->clist, &session->conn_list);
|
||||
list_add_tail(&conn->clist, &session->conn_list);
|
||||
} else {
|
||||
log_error("Only a single connection supported "
|
||||
"(initiator %s)", conn->initiator);
|
||||
@@ -329,11 +323,11 @@ static void text_scan_login(struct connection *conn)
|
||||
datasize = conn->req.datasize;
|
||||
|
||||
while ((key = next_key(&data, &datasize, &value))) {
|
||||
if (!(param_index_by_name(key, login_keys) < 0))
|
||||
if (!(params_index_by_name(key, login_keys) < 0))
|
||||
;
|
||||
else if (!strcmp(key, "AuthMethod"))
|
||||
;
|
||||
else if (!((idx = param_index_by_name(key, session_keys)) < 0)) {
|
||||
else if (!((idx = params_index_by_name(key, session_keys)) < 0)) {
|
||||
unsigned int val;
|
||||
char buf[32];
|
||||
|
||||
@@ -342,12 +336,12 @@ static void text_scan_login(struct connection *conn)
|
||||
continue;
|
||||
}
|
||||
if (idx == key_max_recv_data_length) {
|
||||
conn->session_param[idx].key_state = KEY_STATE_DONE;
|
||||
conn->session_params[idx].key_state = KEY_STATE_DONE;
|
||||
idx = key_max_xmit_data_length;
|
||||
};
|
||||
|
||||
if (param_str_to_val(session_keys, idx, value, &val) < 0) {
|
||||
if (conn->session_param[idx].key_state == KEY_STATE_START) {
|
||||
if (params_str_to_val(session_keys, idx, value, &val) < 0) {
|
||||
if (conn->session_params[idx].key_state == KEY_STATE_START) {
|
||||
text_key_add_reject(conn, key);
|
||||
continue;
|
||||
} else {
|
||||
@@ -358,30 +352,30 @@ static void text_scan_login(struct connection *conn)
|
||||
}
|
||||
}
|
||||
|
||||
param_check_val(session_keys, idx, &val);
|
||||
param_set_val(session_keys, conn->session_param, idx, &val);
|
||||
params_check_val(session_keys, idx, &val);
|
||||
params_set_val(session_keys, conn->session_params, idx, &val);
|
||||
|
||||
switch (conn->session_param[idx].key_state) {
|
||||
switch (conn->session_params[idx].key_state) {
|
||||
case KEY_STATE_START:
|
||||
if (iscsi_is_key_internal(idx)) {
|
||||
conn->session_param[idx].key_state = KEY_STATE_DONE;
|
||||
conn->session_params[idx].key_state = KEY_STATE_DONE;
|
||||
break;
|
||||
}
|
||||
memset(buf, 0, sizeof(buf));
|
||||
param_val_to_str(session_keys, idx, val, buf);
|
||||
params_val_to_str(session_keys, idx, val, buf, sizeof(buf));
|
||||
text_key_add(conn, key, buf);
|
||||
conn->session_param[idx].key_state = KEY_STATE_DONE_ADDED;
|
||||
conn->session_params[idx].key_state = KEY_STATE_DONE_ADDED;
|
||||
break;
|
||||
case KEY_STATE_REQUEST:
|
||||
if (val != conn->session_param[idx].val) {
|
||||
if (val != conn->session_params[idx].val) {
|
||||
rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
|
||||
rsp->status_detail = ISCSI_STATUS_INIT_ERR;
|
||||
conn->state = STATE_EXIT;
|
||||
log_warning("%s %u %u\n", key,
|
||||
val, conn->session_param[idx].val);
|
||||
val, conn->session_params[idx].val);
|
||||
goto out;
|
||||
}
|
||||
conn->session_param[idx].key_state = KEY_STATE_DONE;
|
||||
conn->session_params[idx].key_state = KEY_STATE_DONE;
|
||||
break;
|
||||
case KEY_STATE_DONE_ADDED:
|
||||
case KEY_STATE_DONE:
|
||||
@@ -395,9 +389,9 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
static int text_check_param(struct connection *conn)
|
||||
static int text_check_params(struct connection *conn)
|
||||
{
|
||||
struct iscsi_param *p = conn->session_param;
|
||||
struct iscsi_param *p = conn->session_params;
|
||||
char buf[32];
|
||||
int i, cnt;
|
||||
|
||||
@@ -426,7 +420,7 @@ static int text_check_param(struct connection *conn)
|
||||
if (iscsi_is_key_internal(i))
|
||||
continue;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
param_val_to_str(session_keys, i, p[i].val, buf);
|
||||
params_val_to_str(session_keys, i, p[i].val, buf, sizeof(buf));
|
||||
text_key_add(conn, session_keys[i].name, buf);
|
||||
if (i == key_max_recv_data_length) {
|
||||
p[i].key_state = KEY_STATE_DONE;
|
||||
@@ -445,6 +439,25 @@ static int text_check_param(struct connection *conn)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int init_conn_session_params(struct connection *conn)
|
||||
{
|
||||
int res = 0, i;
|
||||
struct target *target;
|
||||
|
||||
target = target_find_by_id(conn->tid);
|
||||
if (target == NULL) {
|
||||
log_error("target %d not found", conn->tid);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < session_key_last; i++)
|
||||
conn->session_params[i].val = target->session_params[i];
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void login_start(struct connection *conn)
|
||||
{
|
||||
struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
|
||||
@@ -479,9 +492,9 @@ static void login_start(struct connection *conn)
|
||||
conn->session_type = SESSION_NORMAL;
|
||||
|
||||
if (session_type) {
|
||||
if (!strcmp(session_type, "Discovery"))
|
||||
if (!strcmp(session_type, "Discovery")) {
|
||||
conn->session_type = SESSION_DISCOVERY;
|
||||
else if (strcmp(session_type, "Normal")) {
|
||||
} else if (strcmp(session_type, "Normal")) {
|
||||
rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
|
||||
rsp->status_detail = ISCSI_STATUS_INV_SESSION_TYPE;
|
||||
conn->state = STATE_EXIT;
|
||||
@@ -509,7 +522,7 @@ static void login_start(struct connection *conn)
|
||||
}
|
||||
|
||||
if (!target->tgt_enabled) {
|
||||
log_debug(1, "Connect from %s to disabled target %s",
|
||||
log_info("Connect from %s to disabled target %s refused",
|
||||
name, target_name);
|
||||
rsp->status_class = ISCSI_STATUS_TARGET_ERR;
|
||||
conn->state = STATE_CLOSE;
|
||||
@@ -527,15 +540,9 @@ static void login_start(struct connection *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
err = kernel_param_get(conn->tid, conn->sid.id64, key_session,
|
||||
conn->session_param);
|
||||
if (err == -ENOENT) {
|
||||
err = kernel_param_get(conn->tid, 0, key_session,
|
||||
conn->session_param);
|
||||
}
|
||||
|
||||
err = init_conn_session_params(conn);
|
||||
if (err != 0) {
|
||||
log_error("Can't get session param for session 0x%" PRIu64
|
||||
log_error("Can't get session params for session 0x%" PRIu64
|
||||
" (err %d): %s\n", conn->sid.id64, err,
|
||||
strerror(-err));
|
||||
rsp->status_class = ISCSI_STATUS_TARGET_ERR;
|
||||
@@ -694,20 +701,20 @@ static void cmnd_exec_login(struct connection *conn)
|
||||
conn->state = STATE_LOGIN;
|
||||
|
||||
login_start(conn);
|
||||
if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
|
||||
if (!accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
|
||||
goto auth_err;
|
||||
if (rsp->status_class)
|
||||
return;
|
||||
text_scan_login(conn);
|
||||
if (rsp->status_class)
|
||||
return;
|
||||
stay = text_check_param(conn);
|
||||
stay = text_check_params(conn);
|
||||
break;
|
||||
case STATE_LOGIN:
|
||||
text_scan_login(conn);
|
||||
if (rsp->status_class)
|
||||
return;
|
||||
stay = text_check_param(conn);
|
||||
stay = text_check_params(conn);
|
||||
break;
|
||||
default:
|
||||
goto init_err;
|
||||
@@ -737,7 +744,7 @@ static void cmnd_exec_login(struct connection *conn)
|
||||
switch (conn->state) {
|
||||
case STATE_SECURITY:
|
||||
case STATE_SECURITY_DONE:
|
||||
if ((nsg_disagree = text_check_param(conn))) {
|
||||
if ((nsg_disagree = text_check_params(conn))) {
|
||||
conn->state = STATE_LOGIN;
|
||||
nsg = ISCSI_FLG_NSG_LOGIN;
|
||||
break;
|
||||
@@ -755,7 +762,7 @@ static void cmnd_exec_login(struct connection *conn)
|
||||
}
|
||||
if (!stay && !nsg_disagree) {
|
||||
int err;
|
||||
text_check_param(conn);
|
||||
text_check_params(conn);
|
||||
err = login_finish(conn);
|
||||
if (err != 0) {
|
||||
log_debug(1, "login_finish() failed: %d", err);
|
||||
|
||||
+67
-28
@@ -68,7 +68,9 @@ struct connection {
|
||||
struct session *sess;
|
||||
|
||||
u32 tid;
|
||||
struct iscsi_param session_param[session_key_last];
|
||||
|
||||
/* Put here, because negotiations is done before session created */
|
||||
struct iscsi_param session_params[session_key_last];
|
||||
|
||||
char *initiator;
|
||||
char *user;
|
||||
@@ -128,10 +130,6 @@ struct connection {
|
||||
#define AUTH_STATE_START 0
|
||||
#define AUTH_STATE_CHALLENGE 1
|
||||
|
||||
/* don't touch these */
|
||||
#define AUTH_DIR_INCOMING 0
|
||||
#define AUTH_DIR_OUTGOING 1
|
||||
|
||||
#define SESSION_NORMAL 0
|
||||
#define SESSION_DISCOVERY 1
|
||||
#define AUTH_UNKNOWN -1
|
||||
@@ -148,6 +146,21 @@ struct connection {
|
||||
*/
|
||||
#define INCOMING_BUFSIZE 8192
|
||||
|
||||
struct iscsi_user {
|
||||
struct __qelem ulist;
|
||||
|
||||
struct target *target;
|
||||
|
||||
#define ISCSI_USER_DIR_INCOMING 0
|
||||
#define ISCSI_USER_DIR_OUTGOING 1
|
||||
int direction;
|
||||
|
||||
const char *name;
|
||||
const char *password;
|
||||
|
||||
char sysfs_name[64];
|
||||
};
|
||||
|
||||
struct target {
|
||||
struct __qelem tlist;
|
||||
|
||||
@@ -155,10 +168,16 @@ struct target {
|
||||
|
||||
unsigned int tgt_enabled:1;
|
||||
|
||||
unsigned int target_params[target_key_last];
|
||||
unsigned int session_params[session_key_last];
|
||||
|
||||
u32 tid;
|
||||
char name[ISCSI_NAME_LEN];
|
||||
char *alias;
|
||||
|
||||
struct __qelem target_in_accounts;
|
||||
struct __qelem target_out_accounts;
|
||||
|
||||
struct __qelem isns_head;
|
||||
};
|
||||
|
||||
@@ -182,12 +201,12 @@ extern uint16_t server_port;
|
||||
extern void isns_set_fd(int isns, int scn_listen, int scn);
|
||||
|
||||
/* iscsid.c */
|
||||
extern int iscsi_debug;
|
||||
extern int iscsi_enabled;
|
||||
|
||||
extern int cmnd_execute(struct connection *conn);
|
||||
extern void cmnd_finish(struct connection *conn);
|
||||
extern char *text_key_find(struct connection *conn, char *searchKey);
|
||||
extern void text_key_add(struct connection *conn, char *key, char *value);
|
||||
extern void text_key_add(struct connection *conn, char *key, const char *value);
|
||||
|
||||
/* log.c */
|
||||
extern int log_daemon;
|
||||
@@ -219,8 +238,10 @@ extern struct connection *conn_find(struct session *session, u16 cid);
|
||||
|
||||
/* target.c */
|
||||
extern struct __qelem targets_list;
|
||||
extern int target_add(u32 *, char *);
|
||||
extern int target_del(u32);
|
||||
extern int target_create(const char *name, struct target **out_target);
|
||||
extern void target_free(struct target *target);
|
||||
extern int target_add(struct target *target, u32 *tid, u32 cookie);
|
||||
extern int target_del(u32 tid, u32 cookie);
|
||||
extern u32 target_find_id_by_name(const char *name);
|
||||
extern struct target *target_find_by_name(const char *name);
|
||||
struct target *target_find_by_id(u32);
|
||||
@@ -232,13 +253,19 @@ extern int iscsi_adm_request_handle(int accept_fd);
|
||||
|
||||
/* ctldev.c */
|
||||
extern int kernel_open(int *max_data_seg_len);
|
||||
extern int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param);
|
||||
extern int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
|
||||
struct iscsi_param *param);
|
||||
extern int kernel_target_create(u32 *tid, char *name);
|
||||
extern int kernel_target_destroy(u32 tid);
|
||||
extern int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
|
||||
char *name, char *user);
|
||||
extern int kernel_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params);
|
||||
extern int kernel_params_set(u32 tid, u64 sid, int type, u32 partial,
|
||||
const struct iscsi_param *params);
|
||||
extern int kernel_target_create(struct target *target, u32 *tid, u32 cookie);
|
||||
extern int kernel_target_destroy(u32 tid, u32 cookie);
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
extern int kernel_user_add(struct iscsi_user *user, u32 cookie);
|
||||
extern int kernel_user_del(struct iscsi_user *user, u32 cookie);
|
||||
extern int kernel_attr_add(struct target *target, const char *name,
|
||||
u32 mode, u32 cookie);
|
||||
extern int kernel_attr_del(struct target *target, const char *name, u32 cookie);
|
||||
#endif
|
||||
extern int kernel_session_create(struct connection *conn);
|
||||
extern int kernel_session_destroy(u32 tid, u64 sid);
|
||||
extern int kernel_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
|
||||
int fd);
|
||||
@@ -248,26 +275,38 @@ extern int kernel_conn_destroy(u32 tid, u64 sid, u32 cid);
|
||||
extern void handle_iscsi_events(int fd);
|
||||
extern int nl_open(void);
|
||||
|
||||
/* param.c */
|
||||
extern int param_index_by_name(char *name, struct iscsi_key *keys);
|
||||
|
||||
/* config.c */
|
||||
extern int config_isns_load(char *params, char **isns, int *isns_ac);
|
||||
extern int config_load(char *params);
|
||||
extern char *config_sep_string(char **pp);
|
||||
extern int config_parse_main(const char *data, u32 cookie);
|
||||
extern int config_load(const char *config_name);
|
||||
extern int config_target_create(u32 *tid, char *name);
|
||||
extern int config_target_destroy(u32 tid);
|
||||
int config_account_add(u32 tid, int dir, char *name, char *pass);
|
||||
extern int config_account_query(u32 tid, int dir, char *name, char *pass);
|
||||
extern int config_account_add(u32 tid, int dir, char *name, char *pass,
|
||||
char *sysfs_name, u32 cookie);
|
||||
extern int __config_account_add(struct target *target, int dir, char *name,
|
||||
char *pass, char *sysfs_name, int send_to_kern, u32 cookie);
|
||||
extern int config_account_query(u32 tid, int dir, const char *name, char *pass);
|
||||
extern int config_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow,
|
||||
char *buf, size_t buf_sz);
|
||||
extern int config_account_del(u32 tid, int dir, char *name);
|
||||
extern int config_param_set(u32 tid, u64 sid, int type, u32 partial,
|
||||
struct iscsi_param *param);
|
||||
extern int config_account_del(u32 tid, int dir, char *name, u32 cookie);
|
||||
extern int config_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params);
|
||||
extern int config_params_set(u32 tid, u64 sid, int type, u32 partial,
|
||||
struct iscsi_param *params);
|
||||
extern int config_initiator_access(u32 tid, int fd);
|
||||
extern int accounts_empty(u32 tid, int dir);
|
||||
extern struct iscsi_user *account_get_first(u32 tid, int dir);
|
||||
extern struct iscsi_user *account_lookup_by_sysfs_name(struct target *target,
|
||||
int dir, const char *sysfs_name);
|
||||
extern int account_replace(struct target *target, int direction,
|
||||
const char *sysfs_name, char *value);
|
||||
extern void accounts_free(struct __qelem *accounts_list);
|
||||
|
||||
/* isns.c */
|
||||
extern int isns_init(char *addr, int isns_ac);
|
||||
extern int isns_handle(int is_timeout, int *timeout);
|
||||
extern char *isns_server;
|
||||
extern int isns_access_control;
|
||||
extern int isns_timeout;
|
||||
extern int isns_init(void);
|
||||
extern int isns_handle(int is_timeout);
|
||||
extern int isns_scn_handle(int accept);
|
||||
extern int isns_scn_access(u32 tid, int fd, char *name);
|
||||
extern int isns_target_register(char *name);
|
||||
|
||||
+86
-38
@@ -54,9 +54,13 @@ struct isns_initiator {
|
||||
struct __qelem ilist;
|
||||
};
|
||||
|
||||
char *isns_server;
|
||||
int isns_access_control;
|
||||
int isns_timeout = -1;
|
||||
|
||||
static LIST_HEAD(qry_list);
|
||||
static uint16_t scn_listen_port;
|
||||
static int use_isns, use_isns_ac, isns_fd, scn_listen_fd, scn_fd;
|
||||
static int isns_fd, scn_listen_fd, scn_fd;
|
||||
static struct isns_io isns_rx, scn_rx;
|
||||
static char *rxbuf;
|
||||
static uint16_t transaction;
|
||||
@@ -70,11 +74,11 @@ int isns_scn_access(uint32_t tid, int fd, char *name)
|
||||
struct isns_initiator *ini;
|
||||
struct target *target = target_find_by_id(tid);
|
||||
|
||||
if (!use_isns || !use_isns_ac)
|
||||
if ((isns_server == NULL) || !isns_access_control)
|
||||
return 0;
|
||||
|
||||
if (!target)
|
||||
return -EPERM;
|
||||
return -ENOENT;
|
||||
|
||||
list_for_each_entry(ini, &target->isns_head, ilist) {
|
||||
if (!strcmp(ini->name, name))
|
||||
@@ -130,19 +134,25 @@ static int isns_connect(void)
|
||||
{
|
||||
int fd, err;
|
||||
|
||||
log_debug(1, "Going to connect to iSNS server %s", isns_server);
|
||||
|
||||
fd = socket(ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (fd < 0) {
|
||||
log_error("unable to create (%s) %d!", strerror(errno),
|
||||
ss.ss_family);
|
||||
return -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* ToDo: must be made non-blocking, otherwise for an unreacheable
|
||||
* server it blocks all other events processing until timeout (30 secs).
|
||||
*/
|
||||
err = connect(fd, (struct sockaddr *) &ss, sizeof(ss));
|
||||
if (err < 0) {
|
||||
log_error("unable to connect (%s) %d!", strerror(errno),
|
||||
ss.ss_family);
|
||||
close(fd);
|
||||
return -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
log_error("%s %d: new connection %d", __func__, __LINE__, fd);
|
||||
@@ -151,7 +161,7 @@ static int isns_connect(void)
|
||||
err = isns_get_ip(fd);
|
||||
if (err) {
|
||||
close(fd);
|
||||
return -1;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +311,7 @@ static int isns_attr_query(char *name)
|
||||
mgmt = malloc(sizeof(*mgmt));
|
||||
if (!mgmt)
|
||||
return 0;
|
||||
insque(&mgmt->qlist, &qry_list);
|
||||
list_add_tail(&mgmt->qlist, &qry_list);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
tlv = (struct isns_tlv *) hdr->pdu;
|
||||
@@ -384,12 +394,14 @@ int isns_target_register(char *name)
|
||||
struct target *target;
|
||||
int err, initial = list_length_is_one(&targets_list);
|
||||
|
||||
if (!use_isns)
|
||||
if (isns_server == NULL)
|
||||
return 0;
|
||||
|
||||
if (!isns_fd)
|
||||
if (isns_connect() < 0)
|
||||
return 0;
|
||||
if (!isns_fd) {
|
||||
err = isns_connect();
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
tlv = (struct isns_tlv *) hdr->pdu;
|
||||
@@ -447,7 +459,7 @@ static void free_all_acl(struct target *target)
|
||||
|
||||
while (!list_empty(&target->isns_head)) {
|
||||
ini = list_entry(target->isns_head.q_forw, typeof(*ini), ilist);
|
||||
remque(&ini->ilist);
|
||||
list_del(&ini->ilist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +476,7 @@ int isns_target_deregister(char *name)
|
||||
if (target)
|
||||
free_all_acl(target);
|
||||
|
||||
if (!use_isns)
|
||||
if (isns_server == NULL)
|
||||
return 0;
|
||||
|
||||
if (!isns_fd)
|
||||
@@ -637,7 +649,7 @@ static void qry_rsp_handle(struct isns_hdr *hdr)
|
||||
|
||||
list_for_each_entry_safe(mgmt, n, &qry_list, qlist) {
|
||||
if (mgmt->transaction == transaction) {
|
||||
remque(&mgmt->qlist);
|
||||
list_del(&mgmt->qlist);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
@@ -690,7 +702,7 @@ found:
|
||||
goto free_qry_mgmt;
|
||||
snprintf(ini->name, sizeof(ini->name), "%s",
|
||||
name);
|
||||
insque(&ini->ilist, &target->isns_head);
|
||||
list_add_tail(&ini->ilist, &target->isns_head);
|
||||
} else
|
||||
name = NULL;
|
||||
break;
|
||||
@@ -707,7 +719,7 @@ free_qry_mgmt:
|
||||
free(mgmt);
|
||||
}
|
||||
|
||||
int isns_handle(int is_timeout, int *timeout)
|
||||
int isns_handle(int is_timeout)
|
||||
{
|
||||
int err;
|
||||
struct isns_io *rx = &isns_rx;
|
||||
@@ -716,6 +728,9 @@ int isns_handle(int is_timeout, int *timeout)
|
||||
uint16_t function, length, flags, transaction, sequence;
|
||||
char *name = NULL;
|
||||
|
||||
if (isns_server == NULL)
|
||||
return 0;
|
||||
|
||||
if (is_timeout)
|
||||
return isns_attr_query(NULL);
|
||||
|
||||
@@ -855,7 +870,7 @@ int isns_scn_handle(int is_accept)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scn_init(char *addr)
|
||||
static int scn_init(void)
|
||||
{
|
||||
int fd, opt, err;
|
||||
union {
|
||||
@@ -868,29 +883,31 @@ static int scn_init(char *addr)
|
||||
fd = socket(ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (fd < 0) {
|
||||
log_error("%s %d: %s\n", __func__, __LINE__, strerror(errno));
|
||||
return -errno;
|
||||
err = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
opt = 1;
|
||||
if (ss.ss_family == AF_INET6) {
|
||||
err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
|
||||
if (err)
|
||||
if (err) {
|
||||
log_error("%s %d: %s\n", __func__, __LINE__,
|
||||
strerror(errno));
|
||||
goto out;
|
||||
goto out_close;
|
||||
}
|
||||
}
|
||||
|
||||
err = listen(fd, 5);
|
||||
if (err) {
|
||||
log_error("%s %d: %s\n", __func__, __LINE__, strerror(errno));
|
||||
goto out;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
slen = sizeof(lss);
|
||||
err = getsockname(fd, (struct sockaddr *) &lss, &slen);
|
||||
if (err) {
|
||||
log_error("%s %d: %s\n", __func__, __LINE__, strerror(errno));
|
||||
goto out;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
/* protocol independent way ? */
|
||||
@@ -899,8 +916,9 @@ static int scn_init(char *addr)
|
||||
else
|
||||
scn_listen_port = ntohs(lss.sin.sin_port);
|
||||
|
||||
log_error("scn listen port %u %d %d\n", scn_listen_port, fd, err);
|
||||
out:
|
||||
log_info("scn listen port %u %d %d\n", scn_listen_port, fd, err);
|
||||
|
||||
out_close:
|
||||
if (err)
|
||||
close(fd);
|
||||
else {
|
||||
@@ -908,10 +926,11 @@ out:
|
||||
isns_set_fd(isns_fd, scn_listen_fd, scn_fd);
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int isns_init(char *addr, int isns_ac)
|
||||
int isns_init(void)
|
||||
{
|
||||
int err;
|
||||
char port[8];
|
||||
@@ -920,10 +939,11 @@ int isns_init(char *addr, int isns_ac)
|
||||
snprintf(port, sizeof(port), "%d", ISNS_PORT);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
err = getaddrinfo(addr, (char *) &port, &hints, &res);
|
||||
err = getaddrinfo(isns_server, (char *)&port, &hints, &res);
|
||||
if (err) {
|
||||
log_error("getaddrinfo error: %s, %s", gai_strerror(err), addr);
|
||||
return -1;
|
||||
log_error("getaddrinfo error: %s, %s", gai_strerror(err),
|
||||
isns_server);
|
||||
goto out;
|
||||
}
|
||||
memcpy(&ss, res->ai_addr, sizeof(ss));
|
||||
freeaddrinfo(res);
|
||||
@@ -931,28 +951,40 @@ int isns_init(char *addr, int isns_ac)
|
||||
rxbuf = calloc(2, BUFSIZE);
|
||||
if (!rxbuf) {
|
||||
log_error("oom!");
|
||||
return -1;
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
scn_init(addr);
|
||||
err = scn_init();
|
||||
if (err != 0)
|
||||
goto out_free;
|
||||
|
||||
isns_rx.buf = rxbuf;
|
||||
isns_rx.offset = 0;
|
||||
scn_rx.buf = rxbuf + BUFSIZE;
|
||||
scn_rx.offset = 0;
|
||||
|
||||
use_isns = 1;
|
||||
use_isns_ac = isns_ac;
|
||||
isns_timeout = current_timeout * 1000;
|
||||
|
||||
return current_timeout * 1000;
|
||||
err = isns_connect();
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_free:
|
||||
free(rxbuf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void isns_exit(void)
|
||||
{
|
||||
struct target *target;
|
||||
|
||||
if (!use_isns)
|
||||
return;
|
||||
if (isns_server == NULL)
|
||||
goto out;
|
||||
|
||||
if (!isns_fd)
|
||||
goto close;
|
||||
|
||||
list_for_each_entry(target, &targets_list, tlist)
|
||||
isns_scn_deregister(target->name);
|
||||
@@ -961,12 +993,28 @@ void isns_exit(void)
|
||||
/* we can't receive events any more. */
|
||||
isns_set_fd(0, 0, 0);
|
||||
|
||||
if (isns_fd)
|
||||
close:
|
||||
if (isns_fd) {
|
||||
close(isns_fd);
|
||||
if (scn_listen_fd)
|
||||
isns_fd = 0;
|
||||
}
|
||||
if (scn_listen_fd) {
|
||||
close(scn_listen_fd);
|
||||
if (scn_fd)
|
||||
scn_listen_fd = 0;
|
||||
}
|
||||
if (scn_fd) {
|
||||
close(scn_fd);
|
||||
scn_fd = 0;
|
||||
}
|
||||
|
||||
free(rxbuf);
|
||||
rxbuf = NULL;
|
||||
|
||||
free(isns_server);
|
||||
isns_server = NULL;
|
||||
|
||||
isns_timeout = -1;
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,9 +64,11 @@ static void dolog(int prio, const char *func, int line, const char *fmt, va_list
|
||||
int len = strlen(func) + strlen(fmt);
|
||||
char f[len+1+1];
|
||||
if (fmt[len] != '\n')
|
||||
sprintf(f, "%s:%d: %s\n", func, line, fmt);
|
||||
sprintf(f, "%s:%d: %s %s\n", func, line,
|
||||
(prio == LOG_ERR) ? "ERROR:" : "", fmt);
|
||||
else
|
||||
sprintf(f, "%s:%d: %s", func, line, fmt);
|
||||
sprintf(f, "%s:%d: %s %s", func, line,
|
||||
(prio == LOG_ERR) ? "ERROR: " : "", fmt);
|
||||
vsyslog(prio, f, ap);
|
||||
} else {
|
||||
struct timeval time;
|
||||
|
||||
+10
-10
@@ -65,22 +65,22 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r
|
||||
break;
|
||||
case C_TRGT_UPDATE:
|
||||
if (req->u.trgt.type & (1 << key_session))
|
||||
err = config_param_set(req->tid, req->sid,
|
||||
err = config_params_set(req->tid, req->sid,
|
||||
key_session,
|
||||
req->u.trgt.session_partial,
|
||||
req->u.trgt.session_param);
|
||||
req->u.trgt.session_params);
|
||||
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (req->u.trgt.type & (1 << key_target))
|
||||
err = config_param_set(req->tid, req->sid, key_target,
|
||||
err = config_params_set(req->tid, req->sid, key_target,
|
||||
req->u.trgt.target_partial,
|
||||
req->u.trgt.target_param);
|
||||
req->u.trgt.target_params);
|
||||
break;
|
||||
case C_TRGT_SHOW:
|
||||
err = kernel_param_get(req->tid, req->sid, key_target,
|
||||
req->u.trgt.target_param);
|
||||
err = config_params_get(req->tid, req->sid, key_target,
|
||||
req->u.trgt.target_params);
|
||||
break;
|
||||
|
||||
case C_SESS_NEW:
|
||||
@@ -88,8 +88,8 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r
|
||||
case C_SESS_UPDATE:
|
||||
break;
|
||||
case C_SESS_SHOW:
|
||||
err = kernel_param_get(req->tid, req->sid, key_session,
|
||||
req->u.trgt.session_param);
|
||||
err = config_params_get(req->tid, req->sid, key_session,
|
||||
req->u.trgt.session_params);
|
||||
break;
|
||||
|
||||
case C_CONN_NEW:
|
||||
@@ -105,11 +105,11 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r
|
||||
case C_ACCT_NEW:
|
||||
err = config_account_add(req->tid, req->u.acnt.auth_dir,
|
||||
req->u.acnt.u.user.name,
|
||||
req->u.acnt.u.user.pass);
|
||||
req->u.acnt.u.user.pass, NULL, 0);
|
||||
break;
|
||||
case C_ACCT_DEL:
|
||||
err = config_account_del(req->tid, req->u.acnt.auth_dir,
|
||||
req->u.acnt.u.user.name);
|
||||
req->u.acnt.u.user.name, 0);
|
||||
break;
|
||||
case C_ACCT_LIST:
|
||||
*rsp_data = malloc(req->u.acnt.u.list.alloc_len);
|
||||
|
||||
+115
-52
@@ -18,10 +18,24 @@
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
int param_index_by_name(char *name, struct iscsi_key *keys)
|
||||
/* Taken from Linux kernel sources */
|
||||
size_t strlcpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
size_t ret = strlen(src);
|
||||
|
||||
if (size) {
|
||||
size_t len = (ret >= size) ? size - 1 : ret;
|
||||
memcpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int params_index_by_name(char *name, struct iscsi_key *keys)
|
||||
{
|
||||
int i, err = -ENOENT;
|
||||
|
||||
@@ -35,19 +49,43 @@ int param_index_by_name(char *name, struct iscsi_key *keys)
|
||||
return err;
|
||||
}
|
||||
|
||||
void param_set_defaults(struct iscsi_param *params, struct iscsi_key *keys)
|
||||
int params_index_by_name_numwild(char *name, struct iscsi_key *keys)
|
||||
{
|
||||
int i, err = -ENOENT;
|
||||
|
||||
for (i = 0; keys[i].name; i++) {
|
||||
if (!strncasecmp(keys[i].name, name, strlen(keys[i].name))) {
|
||||
int j;
|
||||
if (strlen(keys[i].name) > strlen(name))
|
||||
continue;
|
||||
for (j = strlen(keys[i].name); j < strlen(name); j++) {
|
||||
if (!isdigit(name[j]))
|
||||
goto next;
|
||||
|
||||
}
|
||||
err = i;
|
||||
break;
|
||||
next:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void params_set_defaults(unsigned int *params, struct iscsi_key *keys)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; keys[i].name; i++)
|
||||
params[i].val = keys[i].local_def;
|
||||
params[i] = keys[i].local_def;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int range_val_to_str(unsigned int val, char *str)
|
||||
static int range_val_to_str(unsigned int val, char *str, int len)
|
||||
{
|
||||
sprintf(str, "%u", val);
|
||||
snprintf(str, len, "%u", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -57,16 +95,16 @@ static int range_str_to_val(char *str, unsigned int *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bool_val_to_str(unsigned int val, char *str)
|
||||
static int bool_val_to_str(unsigned int val, char *str, int len)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
strcpy(str, "No");
|
||||
strlcpy(str, "No", len);
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "Yes");
|
||||
strlcpy(str, "Yes", len);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
@@ -136,18 +174,32 @@ static int maximum_set_val(struct iscsi_param *param, int idx, unsigned int *val
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digest_val_to_str(unsigned int val, char *str)
|
||||
static int digest_val_to_str(unsigned int val, char *str, int len)
|
||||
{
|
||||
int err = 0;
|
||||
int pos = 0;
|
||||
|
||||
if (val & DIGEST_CRC32C)
|
||||
strcpy(str, "CRC32C");
|
||||
else if (val & DIGEST_NONE)
|
||||
strcpy(str, "None");
|
||||
else
|
||||
err = -EINVAL;
|
||||
if (val & DIGEST_NONE) {
|
||||
len -= pos;
|
||||
pos = snprintf(&str[pos], len, "%s", "None");
|
||||
}
|
||||
|
||||
return err;
|
||||
if (pos >= len)
|
||||
goto out;
|
||||
|
||||
if (val & DIGEST_CRC32C) {
|
||||
len -= pos;
|
||||
pos = snprintf(&str[pos], len, "%s%s",
|
||||
(pos != 0) ? "," : "", "CRC32C");
|
||||
}
|
||||
|
||||
if (pos >= len)
|
||||
goto out;
|
||||
|
||||
if (pos == 0)
|
||||
pos = snprintf(&str[0], len, "%s", "Unknown");
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digest_str_to_val(char *str, unsigned int *val)
|
||||
@@ -156,11 +208,13 @@ static int digest_str_to_val(char *str, unsigned int *val)
|
||||
char *p, *q;
|
||||
p = str;
|
||||
|
||||
*val = DIGEST_NONE;
|
||||
*val = 0;
|
||||
do {
|
||||
if (!strncmp(p, "None", strlen("None")))
|
||||
while ((*p != '\0') && isspace(*p))
|
||||
p++;
|
||||
if (!strncasecmp(p, "None", strlen("None")))
|
||||
*val |= DIGEST_NONE;
|
||||
else if (!strncmp(p, "CRC32C", strlen("CRC32C")))
|
||||
else if (!strncasecmp(p, "CRC32C", strlen("CRC32C")))
|
||||
*val |= DIGEST_CRC32C;
|
||||
else {
|
||||
err = -EINVAL;
|
||||
@@ -171,6 +225,9 @@ static int digest_str_to_val(char *str, unsigned int *val)
|
||||
p = q + 1;
|
||||
} while (q);
|
||||
|
||||
if (*val == 0)
|
||||
*val = DIGEST_NONE;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -186,38 +243,38 @@ static int digest_set_val(struct iscsi_param *param, int idx, unsigned int *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int marker_val_to_str(unsigned int val, char *str)
|
||||
static int marker_val_to_str(unsigned int val, char *str, int len)
|
||||
{
|
||||
if (val == 0)
|
||||
strcpy(str, "Irrelevant");
|
||||
strlcpy(str, "Irrelevant", len);
|
||||
else
|
||||
strcpy(str, "Reject");
|
||||
strlcpy(str, "Reject", len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int marker_set_val(struct iscsi_param *param, int idx, unsigned int *val)
|
||||
static int marker_set_val(struct iscsi_param *params, int idx, unsigned int *val)
|
||||
{
|
||||
if ((idx == key_ofmarkint && param[key_ofmarker].key_state == KEY_STATE_DONE) ||
|
||||
(idx == key_ifmarkint && param[key_ifmarker].key_state == KEY_STATE_DONE))
|
||||
if ((idx == key_ofmarkint && params[key_ofmarker].key_state == KEY_STATE_DONE) ||
|
||||
(idx == key_ifmarkint && params[key_ifmarker].key_state == KEY_STATE_DONE))
|
||||
*val = 0;
|
||||
else
|
||||
*val = 1;
|
||||
|
||||
param[idx].val = *val;
|
||||
params[idx].val = *val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int param_val_to_str(struct iscsi_key *keys, int idx, unsigned int val, char *str)
|
||||
int params_val_to_str(struct iscsi_key *keys, int idx, unsigned int val, char *str, int len)
|
||||
{
|
||||
if (keys[idx].ops->val_to_str)
|
||||
return keys[idx].ops->val_to_str(val, str);
|
||||
return keys[idx].ops->val_to_str(val, str, len);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int param_str_to_val(struct iscsi_key *keys, int idx, char *str, unsigned int *val)
|
||||
int params_str_to_val(struct iscsi_key *keys, int idx, char *str, unsigned int *val)
|
||||
{
|
||||
if (keys[idx].ops->str_to_val)
|
||||
return keys[idx].ops->str_to_val(str, val);
|
||||
@@ -225,7 +282,7 @@ int param_str_to_val(struct iscsi_key *keys, int idx, char *str, unsigned int *v
|
||||
return 0;
|
||||
}
|
||||
|
||||
int param_check_val(struct iscsi_key *keys, int idx, unsigned int *val)
|
||||
int params_check_val(struct iscsi_key *keys, int idx, unsigned int *val)
|
||||
{
|
||||
if (keys[idx].ops->check_val)
|
||||
return keys[idx].ops->check_val(&keys[idx], val);
|
||||
@@ -233,7 +290,7 @@ int param_check_val(struct iscsi_key *keys, int idx, unsigned int *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int param_set_val(struct iscsi_key *keys, struct iscsi_param *param,
|
||||
int params_set_val(struct iscsi_key *keys, struct iscsi_param *param,
|
||||
int idx, unsigned int *val)
|
||||
{
|
||||
if (keys[idx].ops->set_val)
|
||||
@@ -284,35 +341,41 @@ static struct iscsi_key_ops marker_ops = {
|
||||
/*
|
||||
* List of local target keys with initial values.
|
||||
* Must match corresponding key_* enum in iscsi_scst.h!!
|
||||
*
|
||||
* Updating this array don't forget to update tgt_params_check() in
|
||||
* the kernel as well!
|
||||
*/
|
||||
struct iscsi_key target_keys[] = {
|
||||
{"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), &minimum_ops},
|
||||
{"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), 1, &minimum_ops},
|
||||
{NULL,},
|
||||
};
|
||||
|
||||
/*
|
||||
* List of iSCSI RFC specified session keys with initial values.
|
||||
* Must match corresponding key_* enum in iscsi_scst.h!!
|
||||
*
|
||||
* Updating this array don't forget to update sess_params_check() in
|
||||
* the kernel as well!
|
||||
*/
|
||||
struct iscsi_key session_keys[] = {
|
||||
{"InitialR2T", 1, 0, 0, 1, &or_ops},
|
||||
{"ImmediateData", 1, 1, 0, 1, &and_ops},
|
||||
{"MaxConnections", 1, 1, 1, 1, &minimum_ops},
|
||||
{"MaxRecvDataSegmentLength", 8192, -1, 512, -1, &minimum_ops},
|
||||
{"MaxXmitDataSegmentLength", 8192, -1, 512, -1, &minimum_ops},
|
||||
{"MaxBurstLength", 262144, -1, 512, -1, &minimum_ops},
|
||||
{"FirstBurstLength", 65536, -1, 512, -1, &minimum_ops},
|
||||
{"DefaultTime2Wait", 2, 0, 0, 3600, &maximum_ops},
|
||||
{"DefaultTime2Retain", 20, 0, 0, 3600, &minimum_ops},
|
||||
{"MaxOutstandingR2T", 1, 32, 1, 65535, &minimum_ops},
|
||||
{"DataPDUInOrder", 1, 0, 0, 1, &or_ops},
|
||||
{"DataSequenceInOrder", 1, 0, 0, 1, &or_ops},
|
||||
{"ErrorRecoveryLevel", 0, 0, 0, 0, &minimum_ops},
|
||||
{"HeaderDigest", DIGEST_NONE, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, &digest_ops},
|
||||
{"DataDigest", DIGEST_NONE, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, &digest_ops},
|
||||
{"OFMarker", 0, 0, 0, 0, &and_ops},
|
||||
{"IFMarker", 0, 0, 0, 0, &and_ops},
|
||||
{"OFMarkInt", 2048, 2048, 1, 65535, &marker_ops},
|
||||
{"IFMarkInt", 2048, 2048, 1, 65535, &marker_ops},
|
||||
{"InitialR2T", 1, 0, 0, 1, 1, &or_ops},
|
||||
{"ImmediateData", 1, 1, 0, 1, 1, &and_ops},
|
||||
{"MaxConnections", 1, 1, 1, 1, 0, &minimum_ops},
|
||||
{"MaxRecvDataSegmentLength", 8192, -1, 512, -1, 1, &minimum_ops},
|
||||
{"MaxXmitDataSegmentLength", 8192, -1, 512, -1, 1, &minimum_ops},
|
||||
{"MaxBurstLength", 262144, -1, 512, -1, 1, &minimum_ops},
|
||||
{"FirstBurstLength", 65536, -1, 512, -1, 1, &minimum_ops},
|
||||
{"DefaultTime2Wait", 2, 0, 0, 3600, 0, &maximum_ops},
|
||||
{"DefaultTime2Retain", 20, 0, 0, 3600, 0, &minimum_ops},
|
||||
{"MaxOutstandingR2T", 1, 32, 1, 65535, 1, &minimum_ops},
|
||||
{"DataPDUInOrder", 1, 0, 0, 1, 0, &or_ops},
|
||||
{"DataSequenceInOrder", 1, 0, 0, 1, 0, &or_ops},
|
||||
{"ErrorRecoveryLevel", 0, 0, 0, 0, 0, &minimum_ops},
|
||||
{"HeaderDigest", DIGEST_NONE, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, 1, &digest_ops},
|
||||
{"DataDigest", DIGEST_NONE, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, 1, &digest_ops},
|
||||
{"OFMarker", 0, 0, 0, 0, 0, &and_ops},
|
||||
{"IFMarker", 0, 0, 0, 0, 0, &and_ops},
|
||||
{"OFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops},
|
||||
{"IFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops},
|
||||
{NULL,},
|
||||
};
|
||||
|
||||
+17
-7
@@ -16,6 +16,11 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#define ISCSI_ISNS_SERVER_PARAM_NAME "iSNSServer"
|
||||
#define ISCSI_ISNS_ACCESS_CONTROL_PARAM_NAME "iSNSAccessControl"
|
||||
|
||||
#define ISCSI_ENABLED_ATTR_NAME "enabled"
|
||||
|
||||
struct iscsi_key;
|
||||
|
||||
struct iscsi_param {
|
||||
@@ -24,7 +29,7 @@ struct iscsi_param {
|
||||
};
|
||||
|
||||
struct iscsi_key_ops {
|
||||
int (*val_to_str)(unsigned int, char *);
|
||||
int (*val_to_str)(unsigned int, char *, int);
|
||||
int (*str_to_val)(char *, unsigned int *);
|
||||
int (*check_val)(struct iscsi_key *, unsigned int *);
|
||||
int (*set_val)(struct iscsi_param *, int, unsigned int *);
|
||||
@@ -36,17 +41,22 @@ struct iscsi_key {
|
||||
unsigned int local_def;
|
||||
unsigned int min;
|
||||
unsigned int max;
|
||||
int show_in_sysfs;
|
||||
struct iscsi_key_ops *ops;
|
||||
};
|
||||
|
||||
extern struct iscsi_key session_keys[];
|
||||
extern struct iscsi_key target_keys[];
|
||||
extern struct iscsi_key user_keys[];
|
||||
|
||||
extern void param_set_defaults(struct iscsi_param *, struct iscsi_key *);
|
||||
extern int param_index_by_name(char *, struct iscsi_key *);
|
||||
extern int param_val_to_str(struct iscsi_key *, int, unsigned int, char *);
|
||||
extern int param_str_to_val(struct iscsi_key *, int, char *, unsigned int *);
|
||||
extern int param_check_val(struct iscsi_key *, int, unsigned int *);
|
||||
extern int param_set_val(struct iscsi_key *, struct iscsi_param *, int, unsigned int *);
|
||||
extern size_t strlcpy(char *dest, const char *src, size_t size);
|
||||
|
||||
extern void params_set_defaults(unsigned int *, struct iscsi_key *);
|
||||
extern int params_index_by_name(char *, struct iscsi_key *);
|
||||
extern int params_index_by_name_numwild(char *, struct iscsi_key *);
|
||||
extern int params_val_to_str(struct iscsi_key *, int, unsigned int, char *, int);
|
||||
extern int params_str_to_val(struct iscsi_key *, int, char *, unsigned int *);
|
||||
extern int params_check_val(struct iscsi_key *, int, unsigned int *);
|
||||
extern int params_set_val(struct iscsi_key *, struct iscsi_param *, int, unsigned int *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,7 @@ static int session_alloc(u32 tid, struct session **psess)
|
||||
|
||||
session->target = target;
|
||||
INIT_LIST_HEAD(&session->slist);
|
||||
insque(&session->slist, &target->sessions_list);
|
||||
list_add_tail(&session->slist, &target->sessions_list);
|
||||
|
||||
*psess = session;
|
||||
|
||||
@@ -99,7 +99,6 @@ int session_create(struct connection *conn)
|
||||
/* We are single threaded, so it doesn't need any protection */
|
||||
static u16 tsih = 1;
|
||||
struct session *session;
|
||||
char *user;
|
||||
int res = 0;
|
||||
|
||||
res = session_alloc(conn->tid, &session);
|
||||
@@ -112,7 +111,7 @@ int session_create(struct connection *conn)
|
||||
session->sid.id.tsih = tsih;
|
||||
INIT_LIST_HEAD(&session->conn_list);
|
||||
|
||||
insque(&conn->clist, &session->conn_list);
|
||||
list_add_tail(&conn->clist, &session->conn_list);
|
||||
conn->sess = session;
|
||||
|
||||
conn->sess->initiator = strdup(conn->initiator);
|
||||
@@ -136,27 +135,13 @@ int session_create(struct connection *conn)
|
||||
|
||||
log_debug(1, "sid %#" PRIx64, session->sid.id64);
|
||||
|
||||
if (conn->user != NULL)
|
||||
user = conn->user;
|
||||
else
|
||||
user = "";
|
||||
|
||||
res = kernel_session_create(conn->tid, session->sid.id64, conn->exp_cmd_sn,
|
||||
session->initiator, user);
|
||||
res = kernel_session_create(conn);
|
||||
if (res != 0)
|
||||
goto out_free;
|
||||
|
||||
res = kernel_param_set(conn->tid, session->sid.id64, key_session, 0,
|
||||
conn->session_param);
|
||||
if (res != 0)
|
||||
goto out_destroy;
|
||||
|
||||
out:
|
||||
return res;
|
||||
|
||||
out_destroy:
|
||||
kernel_session_destroy(conn->tid, session->sid.id64);
|
||||
|
||||
out_free:
|
||||
session_free(session);
|
||||
conn->sess = NULL;
|
||||
@@ -171,10 +156,11 @@ void session_free(struct session *session)
|
||||
kernel_session_destroy(session->target->tid, session->sid.id64);
|
||||
|
||||
if (session->target)
|
||||
remque(&session->slist);
|
||||
list_del(&session->slist);
|
||||
|
||||
free(session->initiator);
|
||||
free(session);
|
||||
return;
|
||||
}
|
||||
|
||||
struct connection *conn_find(struct session *session, u16 cid)
|
||||
|
||||
+57
-51
@@ -78,34 +78,25 @@ struct target *target_find_by_id(u32 tid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void all_accounts_del(u32 tid, int dir)
|
||||
int target_del(u32 tid, u32 cookie)
|
||||
{
|
||||
char name[ISCSI_NAME_LEN], pass[ISCSI_NAME_LEN];
|
||||
struct target *target;
|
||||
int err;
|
||||
|
||||
memset(name, 0, sizeof(name));
|
||||
|
||||
for (; config_account_query(tid, dir, name, pass) != -ENOENT;
|
||||
memset(name, 0, sizeof(name))) {
|
||||
config_account_del(tid, dir, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int target_del(u32 tid)
|
||||
{
|
||||
struct target *target = target_find_by_id(tid);
|
||||
int err = kernel_target_destroy(tid);
|
||||
err = kernel_target_destroy(tid, cookie);
|
||||
|
||||
if (err < 0 && err != -ENOENT)
|
||||
return err;
|
||||
else if (!err && !target)
|
||||
|
||||
target = target_find_by_id(tid);
|
||||
if (!err && !target)
|
||||
/* A leftover kernel object was cleaned up - don't complain. */
|
||||
return 0;
|
||||
|
||||
if (!target)
|
||||
return -ENOENT;
|
||||
|
||||
remque(&target->tlist);
|
||||
list_del(&target->tlist);
|
||||
|
||||
if (!list_empty(&target->sessions_list)) {
|
||||
log_error("%s: target %u still has sessions\n", __FUNCTION__,
|
||||
@@ -113,62 +104,77 @@ int target_del(u32 tid)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
all_accounts_del(tid, AUTH_DIR_INCOMING);
|
||||
all_accounts_del(tid, AUTH_DIR_OUTGOING);
|
||||
|
||||
isns_target_deregister(target->name);
|
||||
free(target);
|
||||
|
||||
target_free(target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int target_add(u32 *tid, char *name)
|
||||
void target_free(struct target *target)
|
||||
{
|
||||
accounts_free(&target->target_in_accounts);
|
||||
accounts_free(&target->target_out_accounts);
|
||||
|
||||
free(target);
|
||||
return;
|
||||
}
|
||||
|
||||
int target_create(const char *name, struct target **out_target)
|
||||
{
|
||||
int res = 0;
|
||||
struct target *target;
|
||||
int err;
|
||||
struct iscsi_param tgt_params[target_key_last];
|
||||
struct iscsi_param sess_params[session_key_last];
|
||||
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
if (name == NULL) {
|
||||
res = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(target = malloc(sizeof(*target))))
|
||||
return -ENOMEM;
|
||||
target = malloc(sizeof(*target));
|
||||
if (target == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(target, 0, sizeof(*target));
|
||||
memcpy(target->name, name, sizeof(target->name) - 1);
|
||||
|
||||
if ((err = kernel_target_create(tid, name)) < 0)
|
||||
goto out_free;
|
||||
|
||||
param_set_defaults(tgt_params, target_keys);
|
||||
err = kernel_param_set(*tid, 0, key_target, 0, tgt_params);
|
||||
if (err != 0)
|
||||
goto out_destroy;
|
||||
|
||||
param_set_defaults(sess_params, session_keys);
|
||||
err = kernel_param_set(*tid, 0, key_session, 0, sess_params);
|
||||
if (err != 0)
|
||||
goto out_destroy;
|
||||
params_set_defaults(target->target_params, target_keys);
|
||||
params_set_defaults(target->session_params, session_keys);
|
||||
|
||||
INIT_LIST_HEAD(&target->tlist);
|
||||
INIT_LIST_HEAD(&target->sessions_list);
|
||||
INIT_LIST_HEAD(&target->target_in_accounts);
|
||||
INIT_LIST_HEAD(&target->target_out_accounts);
|
||||
INIT_LIST_HEAD(&target->isns_head);
|
||||
target->tid = *tid;
|
||||
|
||||
*out_target = target;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
int target_add(struct target *target, u32 *tid, u32 cookie)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (target_find_by_name(target->name)) {
|
||||
log_error("duplicated target %s", target->name);
|
||||
err = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = kernel_target_create(target, tid, cookie);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
target->tgt_enabled = 1;
|
||||
#endif
|
||||
insque(&target->tlist, &targets_list);
|
||||
list_add_tail(&target->tlist, &targets_list);
|
||||
|
||||
isns_target_register(name);
|
||||
isns_target_register(target->name);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_destroy:
|
||||
kernel_target_destroy(*tid);
|
||||
|
||||
out_free:
|
||||
free(target);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Target driver for Qlogic 22xx/23xx/24xx/25xx Fibre Channel cards
|
||||
================================================================
|
||||
|
||||
Version 2.0.0, XX XXXXX 2009
|
||||
Version 2.0.0, XX XXXXX 2010
|
||||
----------------------------
|
||||
|
||||
This driver consists from two parts: the target mode driver itself and
|
||||
@@ -12,7 +12,7 @@ necessary callbacks, but it's still capable to work as initiator only.
|
||||
Mode, when a host acts as the initiator and the target simultaneously,
|
||||
is supported as well.
|
||||
|
||||
This version is compatible with SCST core version 1.0.2 and higher and
|
||||
This version is compatible with SCST core version 2.0.0 and higher and
|
||||
Linux kernel 2.6.26 and higher. Sorry, kernels below 2.6.26 are not
|
||||
supported, because it's too hard to backport used initiator driver to
|
||||
older kernels.
|
||||
|
||||
@@ -158,8 +158,8 @@ static struct scst_tgt_template tgt2x_template = {
|
||||
.on_free_cmd = q2t_on_free_cmd,
|
||||
.task_mgmt_fn_done = q2t_task_mgmt_fn_done,
|
||||
.on_hw_pending_cmd_timeout = q2t_on_hw_pending_cmd_timeout,
|
||||
.enable_tgt = q2t_enable_tgt,
|
||||
.is_tgt_enabled = q2t_is_tgt_enabled,
|
||||
.enable_target = q2t_enable_tgt,
|
||||
.is_target_enabled = q2t_is_tgt_enabled,
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
.tgtt_attrs = q2t_attrs,
|
||||
.tgt_attrs = q2t_tgt_attrs,
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
Generic SCSI target mid-level for Linux (SCST)
|
||||
==============================================
|
||||
|
||||
Version 1.0.2, XX XXXXX 2009
|
||||
Version 2.0.0, XX XXXXX 2010
|
||||
----------------------------
|
||||
|
||||
SCST is designed to provide unified, consistent interface between SCSI
|
||||
|
||||
+100
-2
@@ -605,6 +605,7 @@ struct scst_tgt_template {
|
||||
* queuecommand. The target should transmit the response
|
||||
* buffer and the status in the scst_cmd struct.
|
||||
* The expectation is that this executing this command is NON-BLOCKING.
|
||||
* If it is blocking, consider to set threads_num to some none 0 number.
|
||||
*
|
||||
* After the response is actually transmitted, the target
|
||||
* should call the scst_tgt_cmd_done() function of the
|
||||
@@ -631,7 +632,9 @@ struct scst_tgt_template {
|
||||
* the low-level driver needs to call scst_rx_data() in order to
|
||||
* continue processing this command.
|
||||
* Returns one of the SCST_TGT_RES_* constants.
|
||||
*
|
||||
* This command is expected to be NON-BLOCKING.
|
||||
* If it is blocking, consider to set threads_num to some none 0 number.
|
||||
*
|
||||
* Pay attention to "atomic" attribute of the cmd, which can be get
|
||||
* by scst_cmd_atomic(): it is true if the function called in the
|
||||
@@ -708,6 +711,7 @@ struct scst_tgt_template {
|
||||
* scst_restart_cmd().
|
||||
*
|
||||
* This command is expected to be NON-BLOCKING.
|
||||
* If it is blocking, consider to set threads_num to some none 0 number.
|
||||
*
|
||||
* Pay attention to "atomic" attribute of the cmd, which can be get
|
||||
* by scst_cmd_atomic(): it is true if the function called in the
|
||||
@@ -724,6 +728,7 @@ struct scst_tgt_template {
|
||||
* Returns one of the SCST_PREPROCESS_* constants.
|
||||
*
|
||||
* This command is expected to be NON-BLOCKING.
|
||||
* If it is blocking, consider to set threads_num to some none 0 number.
|
||||
*
|
||||
* Pay attention to "atomic" attribute of the cmd, which can be get
|
||||
* by scst_cmd_atomic(): it is true if the function called in the
|
||||
@@ -815,7 +820,7 @@ struct scst_tgt_template {
|
||||
* case the too early connected initiators would see not those devices,
|
||||
* which they intended to see.
|
||||
*/
|
||||
ssize_t (*enable_tgt) (struct scst_tgt *tgt, const char *buffer,
|
||||
ssize_t (*enable_target) (struct scst_tgt *tgt, const char *buffer,
|
||||
size_t size);
|
||||
|
||||
/*
|
||||
@@ -823,7 +828,44 @@ struct scst_tgt_template {
|
||||
*
|
||||
* SHOULD HAVE, see above why.
|
||||
*/
|
||||
bool (*is_tgt_enabled) (struct scst_tgt *tgt);
|
||||
bool (*is_target_enabled) (struct scst_tgt *tgt);
|
||||
|
||||
/*
|
||||
* This function adds a virtual target.
|
||||
*
|
||||
* If both add_target and del_target callbacks defined, then this
|
||||
* target driver supposed to support virtual targets. In this case
|
||||
* an "mgmt" entry will be created in the sysfs root for this driver.
|
||||
* The "mgmt" entry will support 2 commands: "add_target" and
|
||||
* "del_target", for which the corresponding callbacks will be called.
|
||||
* Also target driver can define own commands for the "mgmt" entry, see
|
||||
* mgmt_cmd and mgmt_cmd_help below.
|
||||
*
|
||||
* This approach allows uniform targets management to simplify external
|
||||
* management tools like scstadmin. See README for more details.
|
||||
*
|
||||
* Either both add_target and del_target must be defined, or none.
|
||||
*
|
||||
* MUST HAVE if virtual targets are supported.
|
||||
*/
|
||||
ssize_t (*add_target) (const char *target_name, const char *params);
|
||||
|
||||
/*
|
||||
* This function deletes a virtual target. See comment for add_target
|
||||
* above.
|
||||
*
|
||||
* MUST HAVE if virtual targets are supported.
|
||||
*/
|
||||
ssize_t (*del_target) (const char *target_name);
|
||||
|
||||
/*
|
||||
* This function called if not "add_target" or "del_target" command is
|
||||
* sent to the mgmt entry (see comment for add_target above). In this
|
||||
* case the command passed in this function as is in a string form.
|
||||
*
|
||||
* OPTIONAL.
|
||||
*/
|
||||
ssize_t (*mgmt_cmd) (const char *cmd);
|
||||
|
||||
/*
|
||||
* Name of the template. Must be unique to identify
|
||||
@@ -862,6 +904,9 @@ struct scst_tgt_template {
|
||||
const struct attribute **sess_attrs;
|
||||
#endif
|
||||
|
||||
/* Optional help string for mgmt_cmd commands */
|
||||
const char *mgmt_cmd_help;
|
||||
|
||||
/** Private, must be inited to 0 by memset() **/
|
||||
|
||||
/* List of targets per template, protected by scst_mutex */
|
||||
@@ -3544,4 +3589,57 @@ static inline void add_wait_queue_exclusive_head(wait_queue_head_t *q,
|
||||
spin_unlock_irqrestore(&q->lock, flags);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
|
||||
/**
|
||||
** Helper functionality to help target drivers and dev handlers support
|
||||
** sending events to user space and wait for their completion in a safe
|
||||
** manner. See samples how to use it in iscsi-scst or scst_user.
|
||||
**/
|
||||
|
||||
struct scst_sysfs_user_info {
|
||||
/* Unique cookie to identify request */
|
||||
uint32_t info_cookie;
|
||||
|
||||
/* Entry in the global list */
|
||||
struct list_head info_list_entry;
|
||||
|
||||
/* Set if reply from the user space is being executed */
|
||||
unsigned int info_being_executed:1;
|
||||
|
||||
/* Set if this info is in the info_list */
|
||||
unsigned int info_in_list:1;
|
||||
|
||||
/* Completion to wait on for the request completion */
|
||||
struct completion info_completion;
|
||||
|
||||
/* Request completion status and optional data */
|
||||
int info_status;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function creates an info structure and adds it in the info_list.
|
||||
* Returns 0 and out_info on success, error code otherwise.
|
||||
*/
|
||||
int scst_sysfs_user_add_info(struct scst_sysfs_user_info **out_info);
|
||||
|
||||
/* This function deletes and frees info */
|
||||
void scst_sysfs_user_del_info(struct scst_sysfs_user_info *info);
|
||||
|
||||
/*
|
||||
* This function finds the info based on cookie and set for it flag
|
||||
* info_being_executed. Returns found entry or NULL.
|
||||
*/
|
||||
struct scst_sysfs_user_info *scst_sysfs_user_get_info(uint32_t cookie);
|
||||
|
||||
/*
|
||||
* This function waits for the info request been completed by user space.
|
||||
* Returns status of the request completion.
|
||||
*/
|
||||
int scst_wait_info_completion(struct scst_sysfs_user_info *info,
|
||||
unsigned long timeout);
|
||||
|
||||
#endif /* CONFIG_SCST_PROC */
|
||||
|
||||
#endif /* __SCST_H */
|
||||
|
||||
@@ -351,6 +351,8 @@ enum scst_cdb_flags {
|
||||
/*************************************************************
|
||||
** Misc constants
|
||||
*************************************************************/
|
||||
#define SCST_SYSFS_BLOCK_SIZE PAGE_SIZE
|
||||
#define SCST_SYSFS_BLOCK_SIZE PAGE_SIZE
|
||||
|
||||
#define SCST_SYSFS_KEY_MARK "[key]"
|
||||
|
||||
#endif /* __SCST_CONST_H */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#define DEV_USER_NAME "scst_user"
|
||||
#define DEV_USER_PATH "/dev/"
|
||||
#define DEV_USER_VERSION_NAME "1.0.2"
|
||||
#define DEV_USER_VERSION_NAME "2.0.0"
|
||||
#define DEV_USER_VERSION \
|
||||
DEV_USER_VERSION_NAME "$Revision$" SCST_CONST_VERSION
|
||||
|
||||
|
||||
@@ -2532,16 +2532,12 @@ static int dev_user_attach_tgt(struct scst_tgt_dev *tgt_dev)
|
||||
ucmd->user_cmd.sess.lun = (uint64_t)tgt_dev->lun;
|
||||
ucmd->user_cmd.sess.threads_num = tgt_dev->sess->tgt->tgtt->threads_num;
|
||||
ucmd->user_cmd.sess.rd_only = tgt_dev->acg_dev->rd_only;
|
||||
strncpy(ucmd->user_cmd.sess.initiator_name,
|
||||
strlcpy(ucmd->user_cmd.sess.initiator_name,
|
||||
tgt_dev->sess->initiator_name,
|
||||
sizeof(ucmd->user_cmd.sess.initiator_name)-1);
|
||||
ucmd->user_cmd.sess.initiator_name[
|
||||
sizeof(ucmd->user_cmd.sess.initiator_name)-1] = '\0';
|
||||
strncpy(ucmd->user_cmd.sess.target_name,
|
||||
strlcpy(ucmd->user_cmd.sess.target_name,
|
||||
tgt_dev->sess->tgt->tgt_name,
|
||||
sizeof(ucmd->user_cmd.sess.target_name)-1);
|
||||
ucmd->user_cmd.sess.target_name[
|
||||
sizeof(ucmd->user_cmd.sess.target_name)-1] = '\0';
|
||||
|
||||
TRACE_MGMT_DBG("Preparing ATTACH_SESS %p (h %d, sess_h %llx, LUN %llx, "
|
||||
"threads_num %d, rd_only %d, initiator %s, target %s)",
|
||||
@@ -2757,8 +2753,7 @@ 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]);
|
||||
|
||||
strncpy(dev->name, dev_desc->name, sizeof(dev->name)-1);
|
||||
dev->name[sizeof(dev->name)-1] = '\0';
|
||||
strlcpy(dev->name, dev_desc->name, sizeof(dev->name)-1);
|
||||
|
||||
scst_init_mem_lim(&dev->udev_mem_lim);
|
||||
|
||||
|
||||
@@ -3277,7 +3277,7 @@ static int vdev_open(struct vdev_type *vdt, char *p, const char *name)
|
||||
res = -ENOMEM;
|
||||
goto out_free_vdev;
|
||||
}
|
||||
strncpy(virt_dev->file_name, file_name, len);
|
||||
strlcpy(virt_dev->file_name, file_name, len);
|
||||
}
|
||||
|
||||
if (vdt->vfns.pre_register != NULL) {
|
||||
@@ -3518,7 +3518,7 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
strncpy(fn, file_name, len);
|
||||
strlcpy(fn, file_name, len);
|
||||
virt_dev->file_name = fn;
|
||||
|
||||
res = vdisk_get_file_size(virt_dev->file_name,
|
||||
@@ -4253,7 +4253,7 @@ static int vdisk_proc_mgmt_cmd(const char *buffer, int length,
|
||||
res = -ENOMEM;
|
||||
goto out_free_vdev;
|
||||
}
|
||||
strncpy(virt_dev->file_name, file_name, len);
|
||||
strlcpy(virt_dev->file_name, file_name, len);
|
||||
|
||||
list_add_tail(&virt_dev->vdisk_dev_list_entry,
|
||||
&vdisk_dev_list);
|
||||
|
||||
+2
-2
@@ -692,7 +692,7 @@ static int scst_set_lun_not_supported_request_sense(struct scst_cmd *cmd,
|
||||
|
||||
cmd->sg = scst_alloc(cmd->bufflen, GFP_ATOMIC, &cmd->sg_cnt);
|
||||
if (cmd->sg == NULL) {
|
||||
PRINT_CRIT_ERROR("Unable to alloc sg"
|
||||
PRINT_ERROR("Unable to alloc sg for REQUEST SENSE"
|
||||
"(sense %x/%x/%x)", key, asc, ascq);
|
||||
res = 1;
|
||||
goto out;
|
||||
@@ -737,7 +737,7 @@ static int scst_set_lun_not_supported_inquiry(struct scst_cmd *cmd)
|
||||
|
||||
cmd->sg = scst_alloc(cmd->bufflen, GFP_ATOMIC, &cmd->sg_cnt);
|
||||
if (cmd->sg == NULL) {
|
||||
PRINT_CRIT_ERROR("%s", "Unable to alloc sg for INQUIRY "
|
||||
PRINT_ERROR("%s", "Unable to alloc sg for INQUIRY "
|
||||
"for not supported LUN");
|
||||
res = 1;
|
||||
goto out;
|
||||
|
||||
+14
-6
@@ -220,13 +220,21 @@ int __scst_register_target_template(struct scst_tgt_template *vtt,
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
if (!vtt->enable_tgt || !vtt->is_tgt_enabled) {
|
||||
PRINT_WARNING("Target driver %s doesn't have enable_tgt() "
|
||||
"and/or is_tgt_enabled() method(s). This is unsafe "
|
||||
if (!vtt->enable_target || !vtt->is_target_enabled) {
|
||||
PRINT_WARNING("Target driver %s doesn't have enable_target() "
|
||||
"and/or is_target_enabled() method(s). This is unsafe "
|
||||
"and can lead that initiators connected on the "
|
||||
"initialization time can see an unexpected set of "
|
||||
"devices or no devices at all!", vtt->name);
|
||||
}
|
||||
|
||||
if (((vtt->add_target != NULL) && (vtt->del_target == NULL)) ||
|
||||
((vtt->add_target == NULL) && (vtt->del_target != NULL))) {
|
||||
PRINT_ERROR("Target driver %s must either define both "
|
||||
"add_target() and del_target(), or none.", vtt->name);
|
||||
res = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
#else
|
||||
if (!vtt->no_proc_entry) {
|
||||
res = scst_build_proc_target_dir_entries(vtt);
|
||||
@@ -1298,8 +1306,8 @@ int scst_add_dev_threads(struct scst_device *dev, int num)
|
||||
PRINT_ERROR("Failed to allocate thr %d", res);
|
||||
goto out_del;
|
||||
}
|
||||
strncpy(nm, dev->handler->name, ARRAY_SIZE(nm)-1);
|
||||
nm[ARRAY_SIZE(nm)-1] = '\0';
|
||||
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 (IS_ERR(thr->cmd_thread)) {
|
||||
@@ -1801,7 +1809,7 @@ static void __init scst_print_config(void)
|
||||
j = i;
|
||||
|
||||
#ifdef CONFIG_SCST_STRICT_SERIALIZING
|
||||
i += snprintf(&buf[i], sizeof(buf) - i, "Strict serializing");
|
||||
i += snprintf(&buf[i], sizeof(buf) - i, "STRICT_SERIALIZING");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
|
||||
+1
-2
@@ -1342,8 +1342,7 @@ static int sgv_pool_init(struct sgv_pool *pool, const char *name,
|
||||
name, sizeof(struct sgv_pool_obj), clustering_type,
|
||||
single_alloc_pages, pool->max_caches, pool->max_cached_pages);
|
||||
|
||||
strncpy(pool->name, name, sizeof(pool->name)-1);
|
||||
pool->name[sizeof(pool->name)-1] = '\0';
|
||||
strlcpy(pool->name, name, sizeof(pool->name)-1);
|
||||
|
||||
pool->owner_mm = current->mm;
|
||||
|
||||
|
||||
@@ -878,7 +878,7 @@ static int scst_proc_group_add(const char *p)
|
||||
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of name failed");
|
||||
goto out_nomem;
|
||||
}
|
||||
strncpy(name, p, len);
|
||||
strlcpy(name, p, len);
|
||||
|
||||
acg = scst_alloc_add_acg(NULL, name);
|
||||
if (acg == NULL) {
|
||||
@@ -942,7 +942,7 @@ static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name)
|
||||
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of new name failed");
|
||||
goto out_nomem;
|
||||
}
|
||||
strncpy(name, new_name, len);
|
||||
strlcpy(name, new_name, len);
|
||||
|
||||
res = scst_proc_group_add_tree(acg, new_name);
|
||||
if (res != 0)
|
||||
@@ -2225,7 +2225,7 @@ static int scst_version_info_show(struct seq_file *seq, void *v)
|
||||
seq_printf(seq, "%s\n", SCST_VERSION_STRING);
|
||||
|
||||
#ifdef CONFIG_SCST_STRICT_SERIALIZING
|
||||
seq_printf(seq, "Strict serializing enabled\n");
|
||||
seq_printf(seq, "STRICT_SERIALIZING\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
|
||||
+312
-17
@@ -27,8 +27,6 @@
|
||||
#include "scst_priv.h"
|
||||
#include "scst_mem.h"
|
||||
|
||||
static DEFINE_MUTEX(scst_sysfs_mutex);
|
||||
|
||||
static DECLARE_COMPLETION(scst_sysfs_root_release_completion);
|
||||
|
||||
static struct kobject scst_sysfs_root_kobj;
|
||||
@@ -204,6 +202,125 @@ static struct kobj_attribute tgtt_trace_attr =
|
||||
|
||||
#endif /* #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
|
||||
|
||||
static ssize_t scst_tgtt_mgmt_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
char *help = "Usage: echo \"add_target target_name [parameters]\" "
|
||||
">mgmt\n"
|
||||
" echo \"del_target target_name\" >mgmt\n"
|
||||
"%s"
|
||||
"\n"
|
||||
"where parameters are one or more "
|
||||
"param_name=value pairs separated by ';'\n";
|
||||
struct scst_tgt_template *tgtt;
|
||||
|
||||
tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
|
||||
|
||||
return sprintf(buf, help, (tgtt->mgmt_cmd_help != NULL) ?
|
||||
tgtt->mgmt_cmd_help : "");
|
||||
}
|
||||
|
||||
static ssize_t scst_tgtt_mgmt_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
char *buffer, *p, *target_name;
|
||||
struct scst_tgt_template *tgtt;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
|
||||
|
||||
buffer = kzalloc(count+1, GFP_KERNEL);
|
||||
if (buffer == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(buffer, buf, count);
|
||||
buffer[count] = '\0';
|
||||
p = buffer;
|
||||
|
||||
p = buffer;
|
||||
if (p[strlen(p) - 1] == '\n')
|
||||
p[strlen(p) - 1] = '\0';
|
||||
|
||||
if (strncasecmp("add_target ", p, 11) == 0) {
|
||||
p += 11;
|
||||
|
||||
while (isspace(*p) && *p != '\0')
|
||||
p++;
|
||||
|
||||
if (p == '\0')
|
||||
goto out_syntax_err;
|
||||
|
||||
target_name = p;
|
||||
|
||||
while (!isspace(*p) && *p != '\0')
|
||||
p++;
|
||||
|
||||
if (*p != '\0') {
|
||||
*p = '\0';
|
||||
p++;
|
||||
}
|
||||
|
||||
while (isspace(*p) && *p != '\0')
|
||||
p++;
|
||||
|
||||
res = tgtt->add_target(target_name, p);
|
||||
} else if (strncasecmp("del_target ", p, 11) == 0) {
|
||||
p += 11;
|
||||
|
||||
while (isspace(*p) && *p != '\0')
|
||||
p++;
|
||||
|
||||
if (p == '\0')
|
||||
goto out_syntax_err;
|
||||
|
||||
target_name = p;
|
||||
|
||||
while (!isspace(*p) && *p != '\0')
|
||||
p++;
|
||||
|
||||
if (*p != '\0') {
|
||||
*p = '\0';
|
||||
p++;
|
||||
while (isspace(*p) && *p != '\0')
|
||||
p++;
|
||||
if (*p != '\0')
|
||||
goto out_syntax_err;
|
||||
}
|
||||
|
||||
res = tgtt->del_target(target_name);
|
||||
} else if (tgtt->mgmt_cmd != NULL)
|
||||
res = tgtt->mgmt_cmd(buffer);
|
||||
else {
|
||||
PRINT_ERROR("Unknown action \"%s\"", p);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (res == 0)
|
||||
res = count;
|
||||
|
||||
out_free:
|
||||
kfree(buffer);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_syntax_err:
|
||||
PRINT_ERROR("Syntax error on \"%s\"", p);
|
||||
res = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_tgtt_mgmt =
|
||||
__ATTR(mgmt, S_IRUGO | S_IWUSR, scst_tgtt_mgmt_show,
|
||||
scst_tgtt_mgmt_store);
|
||||
|
||||
int scst_create_tgtt_sysfs(struct scst_tgt_template *tgtt)
|
||||
{
|
||||
int retval = 0;
|
||||
@@ -227,6 +344,16 @@ int scst_create_tgtt_sysfs(struct scst_tgt_template *tgtt)
|
||||
* it will be done by the _put function() called by the caller.
|
||||
*/
|
||||
|
||||
if (tgtt->add_target != NULL) {
|
||||
retval = sysfs_create_file(&tgtt->tgtt_kobj,
|
||||
&scst_tgtt_mgmt.attr);
|
||||
if (retval != 0) {
|
||||
PRINT_ERROR("Can't add mgmt attr for target driver %s",
|
||||
tgtt->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
pattr = tgtt->tgtt_attrs;
|
||||
if (pattr != NULL) {
|
||||
while (*pattr != NULL) {
|
||||
@@ -410,7 +537,7 @@ static ssize_t scst_tgt_enable_show(struct kobject *kobj,
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
|
||||
enabled = tgt->tgtt->is_tgt_enabled(tgt);
|
||||
enabled = tgt->tgtt->is_target_enabled(tgt);
|
||||
|
||||
res = sprintf(buf, "%d\n", enabled ? 1 : 0);
|
||||
|
||||
@@ -431,7 +558,9 @@ static ssize_t scst_tgt_enable_store(struct kobject *kobj,
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
|
||||
res = tgt->tgtt->enable_tgt(tgt, buf, count);
|
||||
res = tgt->tgtt->enable_target(tgt, buf, count);
|
||||
if (res == 0)
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -470,8 +599,8 @@ int scst_create_tgt_sysfs(struct scst_tgt *tgt)
|
||||
* it will be done by the _put function() called by the caller.
|
||||
*/
|
||||
|
||||
if ((tgt->tgtt->enable_tgt != NULL) &&
|
||||
(tgt->tgtt->is_tgt_enabled != NULL)) {
|
||||
if ((tgt->tgtt->enable_target != NULL) &&
|
||||
(tgt->tgtt->is_target_enabled != NULL)) {
|
||||
retval = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&tgt_enable_attr.attr);
|
||||
if (retval != 0) {
|
||||
@@ -1618,7 +1747,7 @@ static ssize_t scst_ini_group_mgmt_store(struct kobject *kobj,
|
||||
res = -ENOMEM;
|
||||
goto out_free_up;
|
||||
}
|
||||
strncpy(name, p, len);
|
||||
strlcpy(name, p, len);
|
||||
|
||||
acg = scst_alloc_add_acg(tgt, name);
|
||||
kfree(name);
|
||||
@@ -1694,7 +1823,7 @@ int scst_create_acn_sysfs(struct scst_acg *acg, struct scst_acn *acn)
|
||||
retval = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
strncpy((char *)attr->attr.name, acn->name, len);
|
||||
strlcpy((char *)attr->attr.name, acn->name, len);
|
||||
|
||||
attr->attr.owner = THIS_MODULE;
|
||||
attr->attr.mode = S_IRUGO;
|
||||
@@ -1703,7 +1832,7 @@ int scst_create_acn_sysfs(struct scst_acg *acg, struct scst_acn *acn)
|
||||
|
||||
retval = sysfs_create_file(acg->initiators_kobj, &attr->attr);
|
||||
if (retval != 0) {
|
||||
PRINT_ERROR("Unable to allocate initiator '%s' for group '%s'",
|
||||
PRINT_ERROR("Unable to create acn '%s' for group '%s'",
|
||||
acn->name, acg->acg_name);
|
||||
kfree(attr->attr.name);
|
||||
goto out_free;
|
||||
@@ -2131,20 +2260,18 @@ static ssize_t scst_threads_store(struct kobject *kobj,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (mutex_lock_interruptible(&scst_sysfs_mutex) != 0) {
|
||||
if (mutex_lock_interruptible(&scst_global_threads_mutex) != 0) {
|
||||
res = -EINTR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&scst_global_threads_mutex);
|
||||
|
||||
oldtn = scst_nr_global_threads;
|
||||
sscanf(buf, "%du", &newtn);
|
||||
|
||||
if (newtn <= 0) {
|
||||
PRINT_ERROR("Illegal threads num value %d", newtn);
|
||||
res = -EINVAL;
|
||||
goto out_up_thr_free;
|
||||
goto out_up;
|
||||
}
|
||||
delta = newtn - oldtn;
|
||||
if (delta < 0)
|
||||
@@ -2154,11 +2281,9 @@ static ssize_t scst_threads_store(struct kobject *kobj,
|
||||
|
||||
PRINT_INFO("Changed cmd threads num: old %d, new %d", oldtn, newtn);
|
||||
|
||||
out_up_thr_free:
|
||||
out_up:
|
||||
mutex_unlock(&scst_global_threads_mutex);
|
||||
|
||||
mutex_unlock(&scst_sysfs_mutex);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
@@ -2408,7 +2533,7 @@ static ssize_t scst_version_show(struct kobject *kobj,
|
||||
sprintf(buf, "%s\n", SCST_VERSION_STRING);
|
||||
|
||||
#ifdef CONFIG_SCST_STRICT_SERIALIZING
|
||||
strcat(buf, "Strict serializing enabled\n");
|
||||
strcat(buf, "STRICT_SERIALIZING\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
@@ -2686,6 +2811,176 @@ void scst_devt_sysfs_put(struct scst_dev_type *devt)
|
||||
return;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(scst_sysfs_user_info_mutex);
|
||||
|
||||
/* All protected by scst_sysfs_user_info_mutex */
|
||||
static LIST_HEAD(scst_sysfs_user_info_list);
|
||||
static uint32_t scst_sysfs_info_cur_cookie;
|
||||
|
||||
/* scst_sysfs_user_info_mutex supposed to be held */
|
||||
static struct scst_sysfs_user_info *scst_sysfs_user_find_info(uint32_t cookie)
|
||||
{
|
||||
struct scst_sysfs_user_info *info, *res = NULL;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
list_for_each_entry(info, &scst_sysfs_user_info_list,
|
||||
info_list_entry) {
|
||||
if (info->info_cookie == cookie) {
|
||||
res = info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_EXIT_HRES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct scst_sysfs_user_info *scst_sysfs_user_get_info(uint32_t cookie)
|
||||
{
|
||||
struct scst_sysfs_user_info *res = NULL;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
res = scst_sysfs_user_find_info(cookie);
|
||||
if (res != NULL) {
|
||||
if (!res->info_being_executed)
|
||||
res->info_being_executed = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
TRACE_EXIT_HRES(res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_sysfs_user_get_info);
|
||||
|
||||
int scst_sysfs_user_add_info(struct scst_sysfs_user_info **out_info)
|
||||
{
|
||||
int res = 0;
|
||||
struct scst_sysfs_user_info *info;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (info == NULL) {
|
||||
PRINT_ERROR("Unable to allocate sysfs user info (size %d)",
|
||||
sizeof(*info));
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
while ((info->info_cookie == 0) ||
|
||||
(scst_sysfs_user_find_info(info->info_cookie) != NULL))
|
||||
info->info_cookie = scst_sysfs_info_cur_cookie++;
|
||||
|
||||
init_completion(&info->info_completion);
|
||||
|
||||
list_add_tail(&info->info_list_entry, &scst_sysfs_user_info_list);
|
||||
info->info_in_list = 1;
|
||||
|
||||
*out_info = info;
|
||||
|
||||
mutex_unlock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_sysfs_user_add_info);
|
||||
|
||||
void scst_sysfs_user_del_info(struct scst_sysfs_user_info *info)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
if (info->info_in_list)
|
||||
list_del(&info->info_list_entry);
|
||||
|
||||
mutex_unlock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
kfree(info);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_sysfs_user_del_info);
|
||||
|
||||
static bool scst_sysfs_user_info_executing(struct scst_sysfs_user_info *info)
|
||||
{
|
||||
bool res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
res = info->info_being_executed;
|
||||
|
||||
if (info->info_in_list) {
|
||||
list_del(&info->info_list_entry);
|
||||
info->info_in_list = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_sysfs_user_info_mutex);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
int scst_wait_info_completion(struct scst_sysfs_user_info *info,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int res, rc;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("Waiting for info %p completion", info);
|
||||
|
||||
while (1) {
|
||||
rc = wait_for_completion_interruptible_timeout(
|
||||
&info->info_completion, timeout);
|
||||
if (rc > 0) {
|
||||
TRACE_DBG("Waiting for info %p finished with %d",
|
||||
info, rc);
|
||||
break;
|
||||
} else if (rc == 0) {
|
||||
if (!scst_sysfs_user_info_executing(info)) {
|
||||
PRINT_ERROR("Timeout waiting for user "
|
||||
"space event %p", info);
|
||||
res = -EBUSY;
|
||||
goto out;
|
||||
} else {
|
||||
/* Req is being executed in the kernel */
|
||||
TRACE_DBG("Keep waiting for info %p completion",
|
||||
info);
|
||||
wait_for_completion(&info->info_completion);
|
||||
break;
|
||||
}
|
||||
} else if (rc != -ERESTARTSYS) {
|
||||
res = rc;
|
||||
PRINT_ERROR("wait_for_completion() failed: %d",
|
||||
res);
|
||||
goto out;
|
||||
} else {
|
||||
TRACE_DBG("Waiting for info %p finished with %d, "
|
||||
"retrying", info, rc);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_DBG("info %p, status %d", info, info->info_status);
|
||||
res = info->info_status;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(scst_wait_info_completion);
|
||||
|
||||
int __init scst_sysfs_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
@@ -494,6 +494,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
#else
|
||||
PRINT_ERROR("Unknown opcode %x", cmd->cdb[0]);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
goto out_done;
|
||||
@@ -585,8 +586,8 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
if (scst_cmd_is_expected_set(cmd)) {
|
||||
#ifdef CONFIG_SCST_USE_EXPECTED_VALUES
|
||||
# ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if ((cmd->data_direction != cmd->expected_data_direction) ||
|
||||
(cmd->bufflen != cmd->expected_transfer_len)) {
|
||||
if (unlikely((cmd->data_direction != cmd->expected_data_direction) ||
|
||||
(cmd->bufflen != cmd->expected_transfer_len))) {
|
||||
TRACE(TRACE_MINOR, "Expected values don't match "
|
||||
"decoded ones: data_direction %d, "
|
||||
"expected_data_direction %d, "
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
User space FILEIO handler
|
||||
=========================
|
||||
|
||||
Version 1.0.2, XX XXXXX 2009
|
||||
Version 2.0.0, XX XXXXX 2010
|
||||
----------------------------
|
||||
|
||||
User space program fileio_tgt uses interface of SCST's scst_user dev
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
/* 8 byte ASCII Vendor */
|
||||
#define VENDOR "SCST_USR"
|
||||
/* 4 byte ASCII Product Revision Level - left aligned */
|
||||
#define FIO_REV " 102"
|
||||
#define FIO_REV " 200"
|
||||
|
||||
#define MAX_USN_LEN (20+1) /* For '\0' */
|
||||
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ unsigned long trace_flag = DEFAULT_LOG_FLAGS;
|
||||
#endif /* defined(DEBUG) || defined(TRACING) */
|
||||
|
||||
#define DEF_BLOCK_SHIFT 9
|
||||
#define VERSION_STR "1.0.2"
|
||||
#define VERSION_STR "2.0.0"
|
||||
#define THREADS 7
|
||||
|
||||
#define MAX_VDEVS 10
|
||||
|
||||
Reference in New Issue
Block a user