diff -Nru iscsitarget-0.4.16+svn162/ChangeLog iscsitarget-1.4.19+svn275/ChangeLog --- iscsitarget-0.4.16+svn162/ChangeLog 2008-06-29 21:49:49.000000000 +0000 +++ iscsitarget-1.4.19+svn275/ChangeLog 2009-12-09 18:08:57.000000000 +0000 @@ -1,3 +1,125 @@ +Summary of changes from v1.4.18 to v1.4.19 +================================= +Andreas Florath + o re-enable MaxSessions parameter + o code cleanups + +Arne Redlich + o NOP-In support + +Harshal Shete + o add notes about cross compilation to README + +SZÉKELYI Szabolcs + o fix ietadm manpage + +Ross S. W. Walker + o fix initiators/targets.allow bugs + o fix compiler warnings + o fix return value of session_add() + o update RPM specfile improving RedHat and SuSE compatibility + (based on a patch from Matthew Wild) + o update RELEASE NOTES + +Kevin Ye + o fix session cleanup in case of -EPIPE during login + + +Summary of changes from v0.4.17 to v1.4.18 +================================= +Lars Ellenberg + o improve IETs procfs support to allow a larger number of targets + o compatibility fix for 2.6.28 (independently also provided by Francois + Micaux) + o ignore SIGPIPE in ietd + o allow cleanup of stale targets in the kernel module + +Andreas Florath + o support for a global worker threadpool instead of per target pools + (configurable via the worker_thread_pool_size module parameter) + +Arne Redlich + o compatibility fixes for 2.6.30, 2.6.29 + o in cooperation with Xie Gang: Unit Attention support (thanks to Stefan + Rubner for spotting a bug) + o in cooperation with Shreyansh Jain: support for splitting text messages into + several PDUs, allowing more targets to be reported during discovery + (thanks to Cheng Rengquan for bugfixes) + o clean up all connections, sessions and targets in the kernel module if the + daemon is gone + o rework sense data handling, plugging memleaks + o fix valgrind warnings of uses of uninitialized variables + o support for Reject PDUs (thanks to FUJITA Tomonori for a bugfix) + o fix SERVICE ACTION IN: IET only supports READ CAPACITY 16, return sense data + for all others + o allow READ CAPACITY even if a LU is RESERVEd + o iSNS: report the actual target port instead of the default iSCSI port + o fix list corruption if target thread creation fails + o fix stopping of threads that have never been awakened before + o fix CHAP account handling bugs + o fix netlink socket cleanup + o code cleanups + +Cheng Renquan + o remove superfluous linefeed from debug messages + o enable runtime switching of debug levels for the kernel module and + provide description for the module's debug flags parameter + +sdrb + o return proper status class in case of login failures + +Ross S. W. Walker + o support more than one portal per target during discovery, and allow + configuration of the presented portals using targets.allow - previously only + the incoming interface was reported (thanks to David Shirley for + reporting a bug) + o deprecate initiators.allow + o regex based filtering in initiators.allow and targets.allow + o move config files to /etc/iet + o add version and author info and description to kernel module + o fix debug log levels + o fix ietd.conf permissions + o move kernel module to /lib/modules//extra where it belongs + o improve init scripts, using common names and functions across distributions + o improve usage comments in ietd.conf + o specfile to build RPMs, including weak module support + o DKMS support + +Ming Zhang + o Use the LU's sector size in the format mode page instead of defaulting to 512 + +Summary of changes from v0.4.16 to v0.4.17 +================================= + +Charley Cheng + o handle the \0-termination of strings properly when building iSNS TLVs + +Denis ChengRq + o fix stopping of wthreads that have never been awakened + +Shreyansh Jain + o fix debugging code that hexdumps PDU content to the syslog + +Jagadish Kumar + o avoid busy looping if a connection's socket is out of wmem + +Arne Redlich + o add support for "ietadm --op show --user" + o SCSI fixes: MODE SENSE handling, INQUIRY CmdDt, HiSup, WCE and RCD handling + o fix handling of NOP-Out w/ ping data + o fix compilation against glibc >= 2.8 + o fix potential NULL-pointer derefences and resource leaks in the LUN param + parsing code + o documentation updates + +Ross S. W. Walker + o 2.6.26 and SLES compile fix + o SLES 10 SP2 compat patch + +Ming Zhang + o make needlessly global function static + + Summary of changes from v0.4.15 to v0.4.16 ================================= @@ -6,7 +128,7 @@ 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 avoid potential NULL-ptr dereferences in rx and tx buffer o fix the shell syntax in init scripts Dave Jiang @@ -49,7 +171,7 @@ 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. @@ -76,14 +198,14 @@ 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 + 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 + o added to ietadm ability to show the iSCSI parameters for an established session. Ming Zhang @@ -91,14 +213,14 @@ 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 + 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 ================================= @@ -261,7 +383,7 @@ Summary of changes from v0.3.8 to v0.4.0 ================================= - + Arne Redlich o iSNS bug fix. @@ -277,7 +399,7 @@ Summary of changes from v0.3.7 to v0.3.8 ================================= - + Arne Redlich o Fix ietadm global option bug. @@ -288,7 +410,7 @@ Summary of changes from v0.3.6 to v0.3.7 ================================= - + Arne Redlich o Fix target_alloc_pages(). @@ -298,7 +420,7 @@ Summary of changes from v0.3.5 to v0.3.6 ================================= - + Arne Redlich o Fix bugs about rejecting PDUs. @@ -310,7 +432,7 @@ Summary of changes from v0.3.4 to v0.3.5 ================================= - + Arne Redlich o Fix ietd security hole. o Fix REPORT LUN bug. diff -Nru iscsitarget-0.4.16+svn162/Makefile iscsitarget-1.4.19+svn275/Makefile --- iscsitarget-0.4.16+svn162/Makefile 2008-02-19 19:45:59.000000000 +0000 +++ iscsitarget-1.4.19+svn275/Makefile 2009-12-09 18:08:57.000000000 +0000 @@ -24,7 +24,7 @@ KVER := $(shell $(CC) $(CFLAGS) -E -dM $(VERSION_FILE) | \ grep UTS_RELEASE | awk '{ print $$3 }' | sed 's/\"//g') -KMOD := /lib/modules/$(KVER)/kernel +KMOD := /lib/modules/$(KVER)/extra KMAJ := $(shell echo $(KVER) | \ sed -e 's/^\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*.*/\1/') @@ -51,9 +51,34 @@ # base first the earlier patch sets will not need to be modified. # -# Compatibility patch for kernels >= 2.6.22 and <= 2.6.23 +# Compatibility patch for kernels <= 2.6.29 +ifeq ($(call kver_le,2,6,29),1) + PATCHES := $(PATCHES) compat-2.6.29.patch +endif + +# Compatibility patch for kernels <= 2.6.28 +ifeq ($(call kver_le,2,6,28),1) + PATCHES := $(PATCHES) compat-2.6.28.patch +endif + +# Compatibility patch for kernels >= 2.6.25 and <= 2.6.27 +ifeq ($(call kver_le,2,6,27),1) + PATCHES := $(PATCHES) compat-2.6.25-2.6.27.patch +endif + +# Compatibility patch for kernels <= 2.6.24 +ifeq ($(call kver_le,2,6,24),1) + PATCHES := $(PATCHES) compat-2.6.24.patch +endif + +# Compatibility patch for kernels <= 2.6.23 ifeq ($(call kver_le,2,6,23),1) - PATCHES := $(PATCHES) compat-2.6.22-2.6.23.patch + PATCHES := $(PATCHES) compat-2.6.23.patch +endif + +# Compatibility patch for kernels <= 2.6.22 +ifeq ($(call kver_le,2,6,22),1) + PATCHES := $(PATCHES) compat-2.6.22.patch endif # Compatibility patch for kernels >= 2.6.19 and <= 2.6.21 @@ -71,10 +96,22 @@ UNSUPPORTED := true endif -# Compatibility patch for RHEL4/CentOS4 -ifeq ($(call kver_lk,"2\.6\.9-.*\.(EL|plus\.c4)"),1) - PATCHES += compat-rhel4.patch - UNSUPPORTED := +# Compatibility patches for SuSE distros +ifneq ($(wildcard /etc/SuSE-release),) + # Compatibility patch for SLES 10 SP2 + ifeq ($(call kver_lk,"2\.6\.16\.60-.*"),1) + PATCHES += compat-sles10sp2.patch + UNSUPPORTED := + endif +endif + +# Compatibility patches for Redhat distros +ifneq ($(wildcard /etc/redhat-release),) + # Compatibility patch for RHEL4/CentOS4 + ifeq ($(call kver_lk,"2\.6\.9-.*\.(EL|plus\.c4)"),1) + PATCHES += compat-rhel4.patch + UNSUPPORTED := + endif endif MANPAGES:= ietadm.8 ietd.8 ietd.conf.5 @@ -96,7 +133,7 @@ MANDIR := /usr/share/man endif -DOCS:= ChangeLog COPYING README README.vmware +DOCS:= ChangeLog COPYING RELEASE_NOTES README README.vmware README.initiators ifeq ($(DOCDIR),) DOCDIR := /usr/share/doc/iscsitarget @@ -132,7 +169,7 @@ if [ ! -e .patched.* ]; then \ for p in $(PATCHES); do \ echo "Applying Patch $$p"; \ - patch -p0 < patches/$$p; \ + patch -p1 < patches/$$p; \ echo $$p >>.patched.$(KVER); \ done; \ fi @@ -145,7 +182,7 @@ done; \ for r in $$reverse; do \ echo "Reversing patch $$r"; \ - patch -p0 -R < patches/$$r; \ + patch -p1 -R < patches/$$r; \ done; \ rm -f .patched.*; \ fi @@ -158,7 +195,9 @@ depmod -aq $(KVER); \ fi -install: install-usr install-etc install-doc install-kernel depmod +install-files: install-usr install-etc install-doc install-kernel + +install: install-files depmod install-kernel: kernel/iscsi_trgt.ko @install -vD kernel/iscsi_trgt.ko \ @@ -170,16 +209,22 @@ install-etc: install-initd @if [ ! -e $(DISTDIR)/etc/ietd.conf ]; then \ - install -vD -m 644 etc/ietd.conf \ - $(DISTDIR)/etc/ietd.conf; \ + if [ ! -e $(DISTDIR)/etc/iet/ietd.conf ]; then \ + install -vD -m 640 etc/ietd.conf \ + $(DISTDIR)/etc/iet/ietd.conf; \ + fi \ fi @if [ ! -e $(DISTDIR)/etc/initiators.allow ]; then \ - install -vD -m 644 etc/initiators.allow \ - $(DISTDIR)/etc/initiators.allow; \ + if [ ! -e $(DISTDIR)/etc/iet/initiators.allow ]; then \ + install -vD -m 644 etc/initiators.allow \ + $(DISTDIR)/etc/iet/initiators.allow; \ + fi \ fi - @if [ ! -e $(DISTDIR)/etc/initiators.deny ]; then \ - install -vD -m 644 etc/initiators.deny \ - $(DISTDIR)/etc/initiators.deny; \ + @if [ ! -e $(DISTDIR)/etc/targets.allow ]; then \ + if [ ! -e $(DISTDIR)/etc/iet/targets.allow ]; then \ + install -vD -m 644 etc/targets.allow \ + $(DISTDIR)/etc/iet/targets.allow; \ + fi \ fi install-initd: diff -Nru iscsitarget-0.4.16+svn162/README iscsitarget-1.4.19+svn275/README --- iscsitarget-0.4.16+svn162/README 2007-11-02 11:54:39.000000000 +0000 +++ iscsitarget-1.4.19+svn275/README 2009-12-09 18:08:57.000000000 +0000 @@ -80,6 +80,36 @@ boot script will not be installed. So you need to install it to an appropriate directory manually. +Cross compilation +----------------- +To cross compile the iSCSI Enterprise Target for a particular +target the following things need to be setup on the development +machine: +1) Cross compiler toolchain. The tools need to be in the shell's +path for the following to work. +2) Linux kernel source code of the target. + +The global Makefile doesn't support cross compilation so the user +space code (ietd and ietadm) and the kernel code need to be build +separately. + +The command line to build the user space code is + +make CC=compiler_name usr + +e.g + +make CC=powerpc-unknown-linux-gnu-gcc usr + +The command line to build the kernel module is + +make ARCH= CROSS_COMPILE= \ + KSRC= kernel + +e.g. + +make ARCH=powerpc CROSS_COMPILE=powerpc-unknown-linux-gnu- \ + KSRC=/root/linux-2.6.30.2 kernel Configuration ------------- diff -Nru iscsitarget-0.4.16+svn162/README.initiators iscsitarget-1.4.19+svn275/README.initiators --- iscsitarget-0.4.16+svn162/README.initiators 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/README.initiators 2009-12-09 18:08:57.000000000 +0000 @@ -0,0 +1,29 @@ +New functionality of initiators.allow/deny +========================================== + +Prior to version 0.4.18 the way initiators.allow and initiators.deny +worked was to read initiators.deny for any targets that matched and +to blacklist any initiator ip addresses listed there, UNLESS the +initiators' ip address is also explicitly allowed by an entry in +initiators.allow. + +From version 0.4.18 on we are depreciating initiators.deny all +together in favor of an implicit deny on any failure to match +a target or initiator in initiators.allow. This provides all the +flexibility of the two files with one less file to worry about +misconfiguring. + +For backwards compatibility while we phase out initiators.deny, +if initiators.deny exists then we will USE THE OLD METHOD, if it +doesn't exist then we will use the newer implicit deny method. + +On new installations we will not install initiators.deny, but we +will still distribute the example version under the etc directory +in the archive. We will also not overwrite or delete existing +versions of these files on install. + +Also, new versions of initiators.allow will have the default +"ALL ALL" line at the bottom to allow any initiator access to +any target. + + diff -Nru iscsitarget-0.4.16+svn162/RELEASE_NOTES iscsitarget-1.4.19+svn275/RELEASE_NOTES --- iscsitarget-0.4.16+svn162/RELEASE_NOTES 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/RELEASE_NOTES 2009-12-09 18:08:57.000000000 +0000 @@ -0,0 +1,77 @@ + ========================================= + Release Notes for iSCSI Enterprise Target + ========================================= + + November 15th, 2009 + Version 1.4.19 + -------------- + +The IET development team is pleased to announce the release of version +1.4.19 of the iSCSI Enterprise Target. + +This release includes numerous bug fixes and compatibility improvements +and it is highly recommended that all production servers be on this +version for compatibility and stability reasons. + +We would like to thank all those that contributed for this release. As +we are a small project we rely heavily on user contributions and we +welcome all who wish to participate in improving IET. + +New since 1.4.18: + +- Added ability to limit number of sessions per target (MaxSessions) +- Added NOP-In heartbeat for connections so dropped or abandoned + connections and their sessions close faster +- Fixed a serious bug in initiators.allow code +- Updated RPM .spec file with added SuSE compatibility and better + overall cross-platform friendliness. + + + October 5th, 2009 + Version 1.4.18 + -------------- + +The version numbering of IET has changed in this release from the 0.X.X +series to the 1.X.X series. We did this because we felt that, since IET +has been stable and in production use for many years now, it deserved a +version number that better reflected that stability and maturity. We +are preserving the minor/maintenance numbers though in order to help +maintain some consistency between prior and future releases. + +New since 0.4.17: + +- Added support for recent kernel versions up to 2.6.31 +- Added support for even more targets via: + * multi PDU support during discovery + * improved procfs support + * global thread pool (module parameter) +- Added support to list all target addresses during discovery, with + the ability to filter those addresses via targets.allow +- Replaced initiators.deny with an implicit deny on a failure to find + a match in initiators.allow while preserving backwards compatiblity + with existing installations (iff initiators.deny doesn't exist) +- Added ability to filter initiators by their IQNs as well as their + IP addresses, using basic regex pattern to specify IQNs +- Moved the config files to /etc/iet/ while preserving backwards + compatiblity with existing installations (iff a valid config file + exists in the new location will it be used) +- Added support for Unit Attention Conditions + * SCSI RESERVE/RELEASE now issues a UAC on reservation loss +- Added support for DKMS and building RPM packages right from the + source archive (from either the source tar ball or subversion) + +Plus many many bug and compatibility fixes (see ChangeLog for details) + + + Special thanks go to: + --------------------- + +Shreyansh Jain, Lars Ellenberg, Ming Zhang, Francois Micaux, Cheng Renquan, +Andreas Florath, sdrb, Xie Gang, Stefan Rubner, FUJITA Tomonori, Oliver R., +Matthew Wild, Kevin Ye and to all list members who submitted bug reports, +suggestions and comments. + +Without whose contributions IET would not have been possible. + +Arne Redlich & Ross Walker + diff -Nru iscsitarget-0.4.16+svn162/debian/changelog iscsitarget-1.4.19+svn275/debian/changelog --- iscsitarget-0.4.16+svn162/debian/changelog 2009-12-09 20:06:55.000000000 +0000 +++ iscsitarget-1.4.19+svn275/debian/changelog 2009-12-09 20:05:56.000000000 +0000 @@ -1,3 +1,11 @@ +iscsitarget (1.4.19+svn275-ubuntu1) lucid; urgency=low + + * Merge from upstream SVN repo at + svn://svn.berlios.de/iscsitarget/trunk + -LP: #494693 + + -- Tim Gardner Wed, 09 Dec 2009 18:25:18 +0000 + iscsitarget (0.4.16+svn162-3ubuntu1) jaunty; urgency=low * Merge from debian unstable, remaining changes (LP: #310321): diff -Nru iscsitarget-0.4.16+svn162/dkms.conf iscsitarget-1.4.19+svn275/dkms.conf --- iscsitarget-0.4.16+svn162/dkms.conf 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/dkms.conf 2009-12-09 18:08:57.000000000 +0000 @@ -0,0 +1,52 @@ +# +# Master copy of dkms.conf for iscsitarget +# + +PACKAGE_NAME="iscsitarget" +PACKAGE_VERSION="1.4.18" +MOD_PATH=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION} + +BUILT_MODULE_NAME="iscsi_trgt" +BUILT_MODULE_LOCATION="kernel" +DEST_MODULE_LOCATION="/kernel/iscsi" + +MAKE="make -C ${kernel_source_dir} SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/kernel modules" + +CLEAN="make -C ${kernel_source_dir} SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/kernel clean" + +AUTOINSTALL="yes" + +# +# Patches newest - oldest, distro spec at bottom +# + +PATCH[0]="compat-2.6.29.patch" +PATCH_MATCH[0]="2\.6\.(9|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29)" + +PATCH[1]="compat-2.6.28.patch" +PATCH_MATCH[1]="2\.6\.(9|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28)" + +PATCH[2]="compat-2.6.25-2.6.27.patch" +PATCH_MATCH[2]="2\.6\.(9|14|15|16|17|18|19|20|21|22|23|24|25|26|27)" + +PATCH[3]="compat-2.6.24.patch" +PATCH_MATCH[3]="2\.6\.(9|14|15|16|17|18|19|20|21|22|23|24)" + +PATCH[4]="compat-2.6.23.patch" +PATCH_MATCH[4]="2\.6\.(9|14|15|16|17|18|19|20|21|22|23)" + +PATCH[5]="compat-2.6.22.patch" +PATCH_MATCH[5]="2\.6\.(9|14|15|16|17|18|19|20|21|22)" + +PATCH[6]="compat-2.6.19-2.6.21.patch" +PATCH_MATCH[6]="2\.6\.(9|14|15|16|17|18|19|20|21)" + +PATCH[7]="compat-2.6.14-2.6.18.patch" +PATCH_MATCH[7]="2\.6\.(9|14|15|16|17|18)" + +PATCH[8]="compat-sles10sp2.patch" +PATCH_MATCH[8]="2\.6\.16\.60-.*" + +PATCH[9]="compat-rhel4.patch" +PATCH_MATCH[9]="2\.6\.9-.*\.(el|plus\.c4)" + diff -Nru iscsitarget-0.4.16+svn162/doc/manpages/ietadm.8 iscsitarget-1.4.19+svn275/doc/manpages/ietadm.8 --- iscsitarget-0.4.16+svn162/doc/manpages/ietadm.8 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/doc/manpages/ietadm.8 2009-12-09 18:08:55.000000000 +0000 @@ -154,7 +154,7 @@ create dynamically a new target, numbered 2. \s-1CAUTION\s0 : the target will disappear if you restart ietd, you'll have to edit /etc/ietd.conf to make it permanent! .SH "ERROR MESSAGES" .IX Header "ERROR MESSAGES" -ietadm misses error messages. Look carefully the \s-1STDERR\s0 output : in case of error +ietadm misses error messages. Look carefully at the \s-1STDERR\s0 output : in case of error it will send a 3 number error code, ending with \-1, for instance : .PP ietd_request 203 3 \-1 @@ -162,7 +162,7 @@ .IX Header "OPTIONS" \&\fB\-\-op new \-\-tid=[id] \-\-params Name=[name]\fR .PP -add a new target with [id]. [id] must not be zero. +add a new target with [id]. If [id] is zero, the lowest free [id] is allocated automatically to the new target. .PP \&\fB\-\-op delete \-\-tid=[id]\fR .PP @@ -216,6 +216,17 @@ If you don't specify a target (omit \-\-tid option), you add a new account for discovery sessions. .PP +\&\fB\-\-op show \-\-tid=[id] \-\-user\fR +.PP +show a list of CHAP accounts. +If \-\-tid is omitted or [id] is \*(L"0\*(R" (zero), discovery accounts are displayed. +.PP +\&\fB\-\-op show \-\-tid=[id] \-\-user \-\-params=[user]=[name]\fR +.PP +show CHAP account information for the account specified by [name]. +[user] can be [IncomingUser] or [OutgoingUser]. +If \-\-tid is omitted or [id] is \*(L"0\*(R" (zero), [name] is supposed to be a discovery account name. +.PP \&\fB\-\-op delete \-\-tid=[id] \-\-user \-\-params=[user]=[name]\fR .PP delete specific account having [name] of specific diff -Nru iscsitarget-0.4.16+svn162/doc/manpages/ietd.8 iscsitarget-1.4.19+svn275/doc/manpages/ietd.8 --- iscsitarget-0.4.16+svn162/doc/manpages/ietd.8 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/doc/manpages/ietd.8 2009-04-13 18:56:21.000000000 +0000 @@ -18,8 +18,6 @@ .IR address \|] .RB [\| \-p .IR port \|] -.RB [\| \-s -.IR IP \|] .RB [\| \-u .IR UID \|] .SH DESCRIPTION @@ -53,9 +51,6 @@ .BI \-h,\ \-\-help Display help message on command line options. .TP -.BI \-s\ IP ,\ \-\-isns= IP -isns server's IP address -.TP .BI \-u\ UID ,\ \-\-uid= UID Specify running user id, default is current uid. .SH FILES diff -Nru iscsitarget-0.4.16+svn162/doc/manpages/ietd.conf.5 iscsitarget-1.4.19+svn275/doc/manpages/ietd.conf.5 --- iscsitarget-0.4.16+svn162/doc/manpages/ietd.conf.5 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/doc/manpages/ietd.conf.5 2009-12-09 18:08:55.000000000 +0000 @@ -1,6 +1,6 @@ .\" Process this file with .\" groff -man -Tascii ietd.conf.5 -.\" +.\" .TH "IETD.CONF" "5" "27 July 2005" "A. Lehmann, M. Zhang and A. Redlich" "File formats" .SH "NAME" /etc/ietd.conf \- configuration for iSCSI Enterprise Target Daemon @@ -15,12 +15,12 @@ .P The "Yes" and "No" for parameter values are case sensitive. The parameter names are case insensitive. .P -The file consists of a global part and zero or more "Target" stanzas. Everything until the first target definition belongs to the global configuration. +The file consists of a global part and zero or more "Target" stanzas. Everything until the first target definition belongs to the global configuration. Here is an example: IncomingUser joe secret -.br +.br OutgoingUser jack secret2 Target iqn.2001\-04.com.example:storage.disk2.sys1.xyz @@ -32,6 +32,7 @@ HeaderDigest None DataDigest None MaxConnections 1 + MaxSessions 0 InitialR2T Yes ImmediateData No MaxRecvDataSegmentLength 8192 @@ -41,6 +42,8 @@ DefaultTime2Wait 2 DefaultTime2Retain 20 MaxOutstandingR2T 8 + NOPInterval 0 + NOPTimeout 0 DataPDUInOrder Yes DataSequenceInOrder Yes ErrorRecoveryLevel 0 @@ -48,11 +51,11 @@ Stanzas start with the word "Target" and the target name. This name must be a globally unique name, as defined by the iSCSI standard : the "iSCSI Qualified Name". The daemon brings the targets up in the order listed. .SH "GLOBAL OPTIONS" Global Options are case sensitive. -.TP +.TP .B [IncomingUser ] -The +The .I -and +and .I used during discovery sessions to authenticate iSCSI initiators. Several of those can be specified for discovery. If no .B IncomingUser @@ -62,13 +65,13 @@ .I to be 12 characters long. This is enforced e.g. by MS Initiator. .RE -.TP +.TP .B [OutgoingUser ] -The +The .I -and +and .I -used during discovery sessions to authenticate the target to initiators. Only one outgoing +used during discovery sessions to authenticate the target to initiators. Only one outgoing .I / combination may be specified. .RS @@ -76,16 +79,16 @@ .I to be 12 characters long. This is enforced e.g. by MS Initiator. .RE -.TP +.TP .B Target iqn..[:] A target definition and the target name. The targets name (the .B iSCSI Qualified Name ) must be a globally unique name (as defined by the iSCSI standard) and has to start with .I iqn -followed by a single dot. The EUI\-64 form is not supported. +followed by a single dot. The EUI\-64 form is not supported. .I is the date (year and month) at which the domain is valid. This has to be followed by a single dot and the reversed domain name. -The optional +The optional .I \- which is freely selectable \- has to be separated by a single colon. For further details please check the iSCSI spec. @@ -94,7 +97,7 @@ Target iqn.2004\-07.com.example.host:storage.disk2.sys1.xyz .SH "TARGET OPTIONS" Target options are also case sensitive. -.TP +.TP .B [IncomingUser ] The .I @@ -104,46 +107,46 @@ .B IncomingUser Option, connections are allowed without authentication. A .I -has to be provided, if there is a +has to be provided, if there is a .I given. Specifying several different .B IncomingUser accounts is supported. -.TP +.TP .B [OutgoingUser ] The .I and .I used to authenticate this iSCSI target to initiators. Only one -.B +.B OutgoingUser per target is supported. It may be different from the username and password in section GLOBAL OPTIONS, which is used for discovery. A .I -has to be provided, if there is a +has to be provided, if there is a .I given. -.TP +.TP .B Lun Path=,Type=(fileio|blockio)[,ScsiId=][,ScsiSN=][,IOMode=(wb|ro)] | Sectors=,Type=nullio Parameters after should not contain any blank space character except the first blank space after is needed. .br - + .br This line must occur at least once. The value of .I can be between 0 and 2^14\-1. .br - + .br In .I fileio -mode (default), it defines a mapping between a "Logical Unit Number" +mode (default), it defines a mapping between a "Logical Unit Number" .I and a given device .I , which can be any block device (including regular block devices like hdX and sdX and virtual block devices like LVM and Software RAID devices) or regular files. .br - + .br In .I blockio @@ -155,7 +158,7 @@ This allows for efficient handling of non-aligned sector transfers (virtualized environments) and large block transfers (media servers). This mode works ideally with high-end storage HBAs and for applications that either do not need caching between application and disk or need the large block throughput. .br - + .br Optionally a .I @@ -168,7 +171,7 @@ .I must not exceed 16 characters and controls the content VPD 0x80. .br - + .br By default, LUNs are writable, employing write-through caching. By setting .I IOMode @@ -180,7 +183,7 @@ .I IOMode "wb" is ignored when employing blockio. .br - + .br In .I nullio @@ -189,36 +192,39 @@ and an unnamed virtual device with .I sectors. This is ONLY useful for performance measurement purposes. All writes to this virtual device will be discarded and reads will return random data. -.TP +.TP .B [Alias ] -This assigns an optional +This assigns an optional .I to the target. -.TP +.TP .B [HeaderDigest ] Optional. If set to "CRC32C" and the initiator is configured accordingly, the integrity of an iSCSI PDU's header segments will be protected by a CRC32C checksum. The default is "None". Note that header digests are not supported during discovery sessions. -.TP +.TP .B [DataDigest ] Optional. If set to "CRC32C" and the initiator is configured accordingly, the integrity of an iSCSI PDU's data segment will be protected by a CRC32C checksum. The default is "None". Note that data digests are not supported during discovery sessions. -.TP +.TP .B [MaxConnections ] -Optional. Has to be set to "1" (in words: one), which is also the default. -.TP +Optional. The number of connections within a session. Has to be set to "1" (in words: one), which is also the default since MC/S is not supported. +.TP +.B [MaxSessions ] +Optional. The maximum number of sessions for this target. If this is set to 0 (wich is the default) there is no explicit session limit. +.TP .B [InitialR2T ] Optional. If set to "Yes" (default), the initiator has to wait for the target to solicit SCSI data before sending it. Setting it to "No" allows the initiator to send a burst of .B FirstBurstLength bytes unsolicited right after and/or (depending on the setting of .B ImmediateData ) together with the command. Thus setting it to "No" may improve performance. -.TP +.TP .B [ImmediateData ] Optional. This allows the initiator to append unsolicited data to a command. To achieve better performance, this should be set to "Yes". The default is "No". -.TP +.TP .B [MaxRecvDataSegmentLength ] -Optional. Sets the maximum data segment length that can be received. The +Optional. Sets the maximum data segment length that can be received. The .I should be set to multiples of PAGE_SIZE. Currently the maximum supported value is 64 * PAGE_SIZE, e.g. 262144 if PAGE_SIZE is 4kB. Configuring too large values may lead to problems allocating sufficient memory, which in turn may lead to SCSI commands timing out at the initiator host. The default value is 8192. -.TP +.TP .B [MaxXmitDataSegmentLength ] Optional. Sets the maximum data segment length that can be sent. The .I @@ -226,15 +232,15 @@ .B MaxXmitDataSegmentLength and the .B MaxRecvDataSegmentLength -announced by the initiator. The +announced by the initiator. The .I should be set to multiples of PAGE_SIZE. Currently the maximum supported value is 64 * PAGE_SIZE, e.g. 262144 if PAGE_SIZE is 4kB. Configuring too large values may lead to problems allocating sufficient memory, which in turn may lead to SCSI commands timing out at the initiator host. The default value is 8192. -.TP +.TP .B [MaxBurstLength ] -Optional. Sets the maximum amount of either unsolicited or solicited data the initiator may send in a single burst. Any amount of data exceeding this value must be explicitly solicited by the target. The +Optional. Sets the maximum amount of either unsolicited or solicited data the initiator may send in a single burst. Any amount of data exceeding this value must be explicitly solicited by the target. The .I should be set to multiples of PAGE_SIZE. Configuring too large values may lead to problems allocating sufficient memory, which in turn may lead to SCSI commands timing out at the initiator host. The default value is 262144. -.TP +.TP .B [FirstBurstLength ] Optional. Sets the amount of unsolicited data the initiator may transmit in the first burst of a transfer either with and/or right after the command, depending on the settings of .B InitialR2T @@ -243,30 +249,51 @@ . .I should be set to multiples of PAGE_SIZE. Configuring too large values may lead to problems allocating sufficient memory, which in turn may lead to SCSI commands timing out at the initiator host. The default value is 65536. -.TP +.TP .B [DefaultTime2Wait ] Currently not supported. -.TP +.TP .B [DefaultTime2Retain ] Currently not supported. -.TP +.TP .B [MaxOutstandingR2T ] Optional. Controls the maximum number of data transfers the target may request at once, each of up to .B MaxBurstLength bytes. The default is 1. -.TP +.TP .B [DataPDUInOrder ] Optional. Has to be set to "Yes" \- which is also the default. -.TP +.TP .B [DataSequenceInOrder ] Optional. Has to be set to "Yes" \- which is also the default. -.TP +.TP .B [ErrorRecoveryLevel ] Optional. Has to be set to "0" (in words: zero), which is also the default. -.TP +.TP +.B [NOPInterval ] +Optional. If +.I value +is non-zero, the initiator will be "ping"ed during phases of inactivity (i.e. no data transfers) every +.I value +seconds to verify the connection is still alive. If the initiator fails to respond within +.B NOPTimeout +seconds, the connection will be closed. +.TP +.B [NOPTimeout ] +Optional. If a non-zero +.B NOPInterval +is used to periodically "ping" the initiator during phases of inactivity (i.e. no data transfers), the initiator must respond within +.I value +seconds, otherwise the connection will be closed. If +.I value +is set to zero or if it exceeds +.B NOPInterval +, it will be set to +.B NOPInterval. +.TP .B [Wthreads ] Optional. The iSCSI target employs several threads to perform the actual block I/O to the device. Depending on your hardware and your (expected) workload, the number of these threads may be carefully adjusted. The default value of 8 should be sufficient for most purposes. -.TP +.TP .B [QueuedCommands ] Optional. This parameter defines a window of commands an initiator may send and that will be buffered by the target. Depending on your hardware and your (expected) workload, the .I value @@ -275,7 +302,7 @@ Currently (as of 0.4.11) not all iSCSI target parameters are used. Header and data digests are not supported during discovery sessions. .SH "SEE ALSO" .B ietd (8) -.TP +.TP You should have a look at .B RFC 3720 for all the glory details. diff -Nru iscsitarget-0.4.16+svn162/etc/ietd.conf iscsitarget-1.4.19+svn275/etc/ietd.conf --- iscsitarget-0.4.16+svn162/etc/ietd.conf 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/etc/ietd.conf 2009-12-09 18:08:57.000000000 +0000 @@ -2,11 +2,18 @@ # # Everything until the first target definition belongs # to the global configuration. -# Right now this is only the user configuration used -# during discovery sessions. "IncomingUser" specifies credentials the -# initiator has to provide - several of these are supported. If mutual -# CHAP shall be employed, "OutgoingUser" specifies the user/pass -# combination the target will provide - only one is supported. +# +# "iSNSServer" is the iSNS server you want your portal to register +# with. +# +# "iSNSAccessControl" is for enabling initiator access control +# through the iSNS server. +# +# "IncomingUser" specifies credentials the initiator has to provide - +# several of these are supported. If mutual CHAP shall be employed, +# "OutgoingUser" specifies the user/pass combination the target will +# provide - only one is supported. +# # Leave them alone (keep them commented out) if you don't want to use # authentication for discovery sessions. @@ -25,35 +32,79 @@ # "yyyy-mm" is the date at which the domain is valid and the identifier # is freely selectable. For further details please check the iSCSI spec. -Target iqn.2001-04.com.example:storage.disk2.sys1.xyz - # Users, who can access this target. The same rules as for discovery - # users apply here. - # Leave them alone if you don't want to use authentication. +#Target iqn.2001-04.com.example:storage.disk2.sys1.xyz + # CHAP Users + # + # The same rules as for discovery users apply here. + # + # Don't set them if you don't want to use CHAP authentication. + # #IncomingUser joe secret #OutgoingUser jim 12charpasswd + # # Logical Unit definition - # You must define one logical unit at least. - # Block devices, regular files, LVM, and RAID can be offered - # to the initiators as a block device. - #Lun 0 Path=/dev/sdc,Type=fileio - # Alias name for this target - # Alias Test - # various iSCSI parameters + # + # Block devices, regular files (fileio only), LVM, and RAID + # can be offered to the initiators as a block device. + # + # Lun numbers MUST start with zero (each target needs a Lun 0) + # + #Lun 0 Path=/dev/sdc,Type=fileio,ScsiId=xyz,ScsiSN=xyz + # + # Alias name for this target (Not Used) + # + #Alias Test + # + # Various iSCSI parameters # (not all are used right now, see also iSCSI spec for details) - #MaxConnections 1 - #InitialR2T Yes - #ImmediateData No - #MaxRecvDataSegmentLength 8192 - #MaxXmitDataSegmentLength 8192 - #MaxBurstLength 262144 - #FirstBurstLength 65536 - #DefaultTime2Wait 2 - #DefaultTime2Retain 20 - #MaxOutstandingR2T 8 - #DataPDUInOrder Yes - #DataSequenceInOrder Yes - #ErrorRecoveryLevel 0 - #HeaderDigest CRC32C,None - #DataDigest CRC32C,None - # various target parameters - #Wthreads 8 + # + # Outgoing SCSI data (initiator to target user data or command + # parameters) is sent as either solicited data or unsolicited data. + # Solicited data is sent in response to R2T PDUs. Unsolicited data + # can be sent as part of an iSCSI command PDU sequence + # ("Immediate Data") or as a separate iSCSI data PDU sequence. + # + #MaxConnections 1 # Number of connections/session + # We only support 1 + #MaxSessions 0 # Number of sessions/target + # 0 = no explicit limit + #InitialR2T Yes # Wait first for R2T + # Yes = no unsolicited data + #ImmediateData Yes # Data can accompany command + # Yes = cmnd/data in same PDU + #MaxRecvDataSegmentLength 8192 # Max data per PDU to receive + #MaxXmitDataSegmentLength 8192 # Max data per PDU to transmit + #MaxBurstLength 262144 # Max data per sequence (R2T) + #FirstBurstLength 65536 # Max unsolicited data sequence + #DefaultTime2Wait 2 # Secs wait for ini to log out + # Not used + #DefaultTime2Retain 20 # Secs keep cmnds after log out + # Not used + #MaxOutstandingR2T 1 # Max outstanding R2Ts per cmnd + #DataPDUInOrder Yes # Data in PDUs is ordered + # We only support ordered + #DataSequenceInOrder Yes # PDUs in sequence are ordered + # We only support ordered + #ErrorRecoveryLevel 0 # We only support level 0 + #HeaderDigest None,CRC32C # PDU header checksum algo list + # None or CRC32C + # If only one is set then the + # initiator must agree to it + # or the connection will fail + #DataDigest None,CRC32C # PDU data checksum algo list + # Same as above + #MaxSessions 0 # Maximum number of sessions to + # this target - 0 = unlimited + #NOPInterval 0 # Send a NOP-In ping each after + # that many seconds if the conn + # is otherwise idle - 0 = off + #NOPTimeout 0 # Wait that many seconds for a + # response on a NOP-In ping + # If 0 or > NOPInterval, NOPInterval + # is used! + # + # Various target parameters + # + #Wthreads 8 # Number of IO threads + #QueuedCommands 32 # Number of queued commands + diff -Nru iscsitarget-0.4.16+svn162/etc/initd/initd iscsitarget-1.4.19+svn275/etc/initd/initd --- iscsitarget-0.4.16+svn162/etc/initd/initd 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/etc/initd/initd 2009-12-09 18:08:57.000000000 +0000 @@ -4,12 +4,17 @@ # PATH=/sbin:/bin:/usr/sbin:/usr/bin +OPTIONS="" + +if [ -f /etc/sysconfig/iscsi-target ]; then + . /etc/sysconfig/iscsi-target +fi start_server() { modprobe -q crc32c modprobe iscsi_trgt - /usr/sbin/ietd + /usr/sbin/ietd $OPTIONS } stop_server() diff -Nru iscsitarget-0.4.16+svn162/etc/initd/initd.debian iscsitarget-1.4.19+svn275/etc/initd/initd.debian --- iscsitarget-0.4.16+svn162/etc/initd/initd.debian 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/etc/initd/initd.debian 2009-12-09 18:08:57.000000000 +0000 @@ -4,61 +4,52 @@ # description: Starts and stops the iSCSI target # debianized start-stop script -PID_FILE=/var/run/iscsi_trgt.pid -CONFIG_FILE=/etc/ietd.conf +PATH=/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/ietd +OPTIONS="" +PIDFILE=/var/run/iscsi_trgt.pid -PATH=/sbin:/bin:/usr/sbin:/usr/bin +if [ -f /lib/init/vars.sh ]; then + . /lib/init/vars.sh +fi + +if [ -f /lib/lsb/init-functions ]; then + . /lib/lsb/init-functions +fi + +if [ -f /etc/sysconfig/iscsi-target ]; then + . /etc/sysconfig/iscsi-target +fi RETVAL=0 ietd_start() { - echo -n "Starting iSCSI enterprise target service: " + log_daemon_msg "Starting iSCSI Target" "ietd" modprobe -q crc32c modprobe iscsi_trgt - start-stop-daemon --start --exec $DAEMON --quiet - RETVAL=$? - if [ $RETVAL -eq 0 ]; then - echo "succeeded." - else - echo "failed." - fi + start-stop-daemon --start --exec $DAEMON --pidfile $PIDFILE -- $OPTIONS + log_end_msg $? } ietd_stop() { - echo -n "Removing iSCSI enterprise target devices: " - # ugly, but ietadm does not always provide correct exit values - RETURN=`ietadm --op delete 2>&1` - RETVAL=$? - if [ $RETVAL -eq 0 ] && [ x$RETURN != x"something wrong" ]; then - echo "succeeded." - else - echo "failed with reason :$RETURN" - exit 1 - fi - - echo -n "Stopping iSCSI enterprise target service: " - start-stop-daemon --stop --quiet --exec $DAEMON --pidfile $PID_FILE - RETVAL=$? - if [ $RETVAL -eq 0 ]; then - echo "succeeded." - else - echo "failed." - fi - # ugly, but pid file is not removed by ietd - rm -f $PID_FILE - - echo -n "Removing iSCSI enterprise target modules: " + log_daemon_msg "Stopping iSCSI Target" "ietd" + ietadm --op delete + start-stop-daemon --stop --exec $DAEMON --pidfile $PIDFILE + rm -f $PIDFILE modprobe -r iscsi_trgt - RETVAL=$? - modprobe -r crc32c 2>/dev/null - if [ $RETVAL -eq 0 ]; then - echo "succeeded." + log_end_msg $? +} + +ietd_status() +{ + PID=`pidof ietd` + if [ $PID ]; then + echo "iSCSI Target (pid $PID) is running..." else - echo "failed." - exit 1 + echo "iSCSI Target is stopped." + exit 1 fi } @@ -75,33 +66,10 @@ ietd_start ;; status) - PID=`pidof ietd` - if [ $PID ]; then - echo "iSCSI enterprise target is running at pid $PID" - else - echo "no iSCSI enterprise target found!" - exit 1 - fi - ;; - dump) - DUMP=`tempfile -p ietd` - RETVAL=$? - if [ $RETVAL -ne 0 ]; then - echo "Failed to create dump file $DUMP" - exit 1 - fi - ietadm --mode dump --all >$DUMP - RETVAL=$? - if [ $RETVAL -ne 0 ]; then - echo "Error dumping config from daemon" - rm $DUMP - exit 1 - fi - mv -u $DUMP $CONFIG_FILE - echo "Config dumped to $CONFIG_FILE" + ietd_status ;; *) - echo $"Usage: $0 {start|stop|restart|status|dump}" + echo $"Usage: $0 {start|stop|restart|status}" exit 1 esac diff -Nru iscsitarget-0.4.16+svn162/etc/initd/initd.gentoo iscsitarget-1.4.19+svn275/etc/initd/initd.gentoo --- iscsitarget-0.4.16+svn162/etc/initd/initd.gentoo 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/etc/initd/initd.gentoo 2009-12-09 18:08:57.000000000 +0000 @@ -2,38 +2,39 @@ # # Start the iSCSI Enterprise Target. # - -PATH=/sbin:/bin:/usr/sbin:/usr/bin +# To define start-up options, create a config file called +# /etc/conf.d/iscsi-target, in it define OPTIONS="...". depend() { - use net + use net + need localmount + after bootmisc } -start_server() +start() { - modprobe -q crc32c - modprobe iscsi_trgt - /usr/sbin/ietd + ebegin "Starting iSCSI Target" + modprobe -q crc32c + modprobe iscsi_trgt + start-stop-daemon --start --exec /usr/sbin/ietd --pidfile /var/run/iscsi_trgt.pid -- $OPTIONS + eend $? } -stop_server() +stop() { - ietadm --op delete - killall ietd - modprobe -r iscsi_trgt + ebegin "Stopping iSCSI Target" + ietadm --op delete + start-stop-daemon --stop --exec /usr/sbin/ietd --pidfile /var/run/iscsi_trgt.pid + rm -f /var/run/iscsi_trgt.pid + modprobe -r iscsi_trgt + eend $? } -start() +restart() { - ebegin "Starting iscsi" - start_server - eend 0 + stop + sleep 1 + start } -stop() -{ - ebegin "Stopping iscsi" - stop_server - eend 0 -} diff -Nru iscsitarget-0.4.16+svn162/etc/initd/initd.redhat iscsitarget-1.4.19+svn275/etc/initd/initd.redhat --- iscsitarget-0.4.16+svn162/etc/initd/initd.redhat 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/etc/initd/initd.redhat 2009-12-09 18:08:57.000000000 +0000 @@ -6,6 +6,9 @@ # pidfile: /var/run/ietd.pid # config: /etc/ietd.conf +PATH=/sbin:/bin:/usr/sbin:/usr/bin +OPTIONS="" + # Source function library. if [ -f /etc/init.d/functions ] ; then . /etc/init.d/functions @@ -15,29 +18,35 @@ exit 0 fi -PATH=/sbin:/bin:/usr/sbin:/usr/bin +if [ -f /etc/sysconfig/iscsi-target ]; then + . /etc/sysconfig/iscsi-target +fi RETVAL=0 start() { - echo -n "Starting iSCSI target service: " + echo -n "Starting iSCSI Target: " modprobe -q crc32c modprobe iscsi_trgt - daemon /usr/sbin/ietd + daemon /usr/sbin/ietd $OPTIONS RETVAL=$? + if [ $RETVAL -eq 0 ]; then + echo_success + else + echo_failure + fi echo return $RETVAL } stop() { - echo -n "Stopping iSCSI target service: " - ietadm --op delete >/dev/null 2>/dev/null - killall ietd 2> /dev/null - modprobe -r iscsi_trgt 2>/dev/null + echo -n "Stopping iSCSI Target: " + ietadm --op delete + killall ietd + modprobe -r iscsi_trgt RETVAL=$? - modprobe -r crc32c 2>/dev/null if [ $RETVAL -eq 0 ]; then echo_success else @@ -49,8 +58,9 @@ restart() { - stop - start + stop + sleep 1 + start } condrestart() @@ -65,10 +75,10 @@ { PID=`pidofproc ietd` if [ ! $PID ]; then - echo "iSCSI target stopped" + echo "iSCSI Target stopped" exit 1 else - echo "ietd (pid $PID) is running..." + echo "iSCSI Target (pid $PID) is running..." fi } @@ -80,7 +90,7 @@ stop ;; restart) - restart + restart ;; condrestart) condrestart @@ -89,7 +99,7 @@ status ;; *) - echo $"Usage: $0 {start|stop|restart|status}" + echo $"Usage: $0 {start|stop|restart|condrestart|status}" exit 1 esac diff -Nru iscsitarget-0.4.16+svn162/etc/initiators.allow iscsitarget-1.4.19+svn275/etc/initiators.allow --- iscsitarget-0.4.16+svn162/etc/initiators.allow 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/etc/initiators.allow 2009-12-09 18:08:57.000000000 +0000 @@ -1,7 +1,24 @@ +# The semantics are: +# +# * Without any entries no initiator can see or connect to any target. +# +# * By default we allow all initiators to connect to all targets with +# the "ALL ALL" entry. +# +# * Override which initiators can connect to which targets by putting an +# entry for a given target followed by a comma separated list of +# initiators, either IP address or IQN name (basic regex patterns for +# IQN names are accepted leave out ^ and $ specials as they are implicit), +# separate the two with whitespace. +# +# * Entry processing stops at the "ALL" target entry if present. +# +# # Some examples # -#iqn.2001-04.com.example:storage.disk1.sys1.xyz 192.168.22.2, 192.168.3.8 -#iqn.2001-04.com.example:storage.disk1.sys2.xyz [3ffe:302:11:1:211:43ff:fe31:5ae2], [3ffe:505:2:1::]/64 +#iqn.2001-04.com.example:storage.disk1.sys1.xyz 192.168.0.0/16, .*:mscs1-[1-4]\.example\.com +#iqn.2001-04.com.example:storage.disk1.sys2.xyz [3ffe:302:11:1:211:43ff:fe31:5ae2], [3ffe:505:2:1::]/64, 192.168.22.0/24 #iqn.2001-04.com.example:storage.disk1.sys3.xyz ALL -#iqn.2001-04.com.example:storage.disk1.sys4.xyz 192.168.22.3 -#ALL 192.168.22.4 +#iqn.2001-04.com.example:storage.disk1.sys4.xyz 192.168.22.3, iqn\.1998-01\.com\.vmware:.*\.example\.com +# ALL 192.168.0.0/16 +ALL ALL diff -Nru iscsitarget-0.4.16+svn162/etc/targets.allow iscsitarget-1.4.19+svn275/etc/targets.allow --- iscsitarget-0.4.16+svn162/etc/targets.allow 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/etc/targets.allow 2009-12-09 18:08:57.000000000 +0000 @@ -0,0 +1,23 @@ +# The semantics are: +# +# * Without any entries no target will accept connections or be discovered +# on any address. +# +# * By default we allow all targets to accept connections and to be +# discovered on any address with the "ALL ALL" entry. +# +# * Override which targets will accept connections on and be discovered on +# which addresses by putting an entry for a given target followed by a +# comma separated list of IP addresses, separate the two with whitespace. +# +# * Entry processing stops at the "ALL" target entry if present. +# +# +# Some examples +# +#iqn.2001-04.com.example:storage.disk1.sys1.xyz 192.168.0.0/16 +#iqn.2001-04.com.example:storage.disk1.sys2.xyz [3ffe:302:11:1:211:43ff:fe31:5ae2], 192.168.22.24 +#iqn.2001-04.com.example:storage.disk1.sys3.xyz ALL +#iqn.2001-04.com.example:storage.disk1.sys4.xyz 192.168.22.3 +# ALL 192.168.0.0/16 +ALL ALL diff -Nru iscsitarget-0.4.16+svn162/include/iet_u.h iscsitarget-1.4.19+svn275/include/iet_u.h --- iscsitarget-0.4.16+svn162/include/iet_u.h 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/include/iet_u.h 2009-12-09 18:08:55.000000000 +0000 @@ -1,7 +1,7 @@ #ifndef _IET_U_H #define _IET_U_H -#define IET_VERSION_STRING "0.4.16" +#define IET_VERSION_STRING "1.4.19" /* The maximum length of 223 bytes in the RFC. */ #define ISCSI_NAME_LEN 256 @@ -81,6 +81,8 @@ key_wthreads, key_target_type, key_queued_cmnds, + key_nop_interval, + key_nop_timeout, target_key_last, }; @@ -119,6 +121,14 @@ #define MIN_NR_QUEUED_CMNDS 1 #define MAX_NR_QUEUED_CMNDS 256 +#define DEFAULT_NOP_INTERVAL 0 +#define MIN_NOP_INTERVAL 0 +#define MAX_NOP_INTERVAL 90 + +#define DEFAULT_NOP_TIMEOUT 0 +#define MIN_NOP_TIMEOUT 0 +#define MAX_NOP_TIMEOUT 90 + #define NETLINK_IET 21 #define ADD_TARGET _IOW('i', 0, struct target_info) diff -Nru iscsitarget-0.4.16+svn162/iscsitarget.spec iscsitarget-1.4.19+svn275/iscsitarget.spec --- iscsitarget-0.4.16+svn162/iscsitarget.spec 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/iscsitarget.spec 2009-12-09 18:08:57.000000000 +0000 @@ -0,0 +1,442 @@ +## +## Global Package Definitions +## + +## IET Release +%define iet_version 1.4.18 + +## Package Revision +%define revision 1 + +## Build Options +# Build DKMS kernel module +# +# Two passes through rpmbuild are required, once for the userland +# binary package and another time with --target=noarch for the +# kernel dkms package. +%define dkms 0 + +# Build from SVN repository +%define svn 0 + +## Platform Definitions +# Determine distribution +%define is_suse %(test -e /etc/SuSE-release && echo 1 || echo 0) +%define is_fedora %(test -e /etc/fedora-release && echo 1 || echo 0) +%define is_redhat %(test -e /etc/redhat-release && echo 1 || echo 0) +%define is_mandrake %(test -e /etc/mandrake-release && echo 1 || echo 0) +%define is_mandriva %(test -e /etc/mandriva-release && echo 1 || echo 0) + +# Define kernel version information +%{!?kernel: %define kernel %(uname -r)} + +%define kver %(echo %{kernel} | sed -e 's/default//' -e 's/pae//i' -e 's/xen//' -e 's/smp//' -e 's/bigmem//' -e 's/hugemem//' -e 's/enterprise//' -e 's/-$//') +%define krel %(echo %{kver} | sed -e 's/-/_/g') +%define ktype %(echo kernel-%{kernel} | sed -e 's/%{kver}//' -e 's/--/-/' -e 's/-$//') + +%define module /lib/modules/%{kernel}/extra/iscsi/iscsi_trgt.ko + +# Set location of tools +%define __chkconfig /sbin/chkconfig +%define __depmod /sbin/depmod +%define __dkms /usr/sbin/dkms +%define __modprobe /sbin/modprobe +%define __service /sbin/service +%define __svn /usr/bin/svn +%if %is_suse +%define __weak_modules /usr/lib/module-init-tools/weak-modules +%else +%define __weak_modules /sbin/weak-modules +%endif + +# Subversion build information +%if %svn +%define svn_url http://svn.berlios.de/svnroot/repos/iscsitarget/trunk +%define iet_version %(%{__svn} info --non-interactive %{svn_url} | awk '{if ($1 == "Revision:") {print "svn_r"$2}}') +%endif + +# Build weak module (KABI Tracking) on platforms that support it +%define weak %(test -x %{__weak_modules} && echo 1 || echo 0) + +# Basic regex filters for unwanted dependencies (used for weak modules) +%if %weak +%define pro_filter "" +%if %is_redhat +%define req_filter "\\(fsync_bdev\\|sync_page_range\\)" +%else +%define req_filter "" +%endif +%endif + +# Define build user +%define user %(whoami) + + +## +## Userland Package +## + +## Information +Summary: iSCSI Enterprise Target +Name: iscsitarget +Version: %{iet_version} +Release: %{?revision: %{revision}}%{!?revision: 1} +License: GPL +Group: System Environment/Daemons +URL: http://sourceforge.net/projects/iscsitarget/ +Packager: IET development team + +## Source files +%if !%svn +Source0: %{name}-%{version}.tar.gz +%endif + +## Patches +#Patch0: %{name}-example.p + +## Install Requirements +Requires: %{name}-kmod = %{version} + +## Build Requirements +BuildRequires: kernel >= 2.6 +BuildRequires: gcc, make, patch, binutils, /usr/bin/install, openssl-devel +%if %is_suse +BuildRequires: kernel-source = %{kver} +%else +BuildRequires: %{ktype}-devel = %{kver} +%endif +%if %svn +BuildRequires: subversion +%endif + +## Build Definitions +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%{user} + +## Description +%description +iSCSI Enterprise Target + + +## +## Kernel Module Package +## +%if %dkms +%ifarch noarch +%package -n kmod-%{name} + +## Information +Summary: iSCSI Enterprise Target kernel module +Group: System Environment/Kernel +Release: %{release}_dkms + +## Install Requirements +Requires: dkms >= 2, gcc, make, patch, binutils +%if %is_suse +Requires: kernel-source +%else +Requires: %{ktype}-devel +%endif + +## Install Provides +Provides: %{name}-kmod = %{version} + +## Description +%description -n kmod-%{name} +iSCSI Enterprise Target kernel module +%endif +%else +%package -n kmod-%{name} + +## Information +Summary: iSCSI Enterprise Target kernel module +Group: System Environment/Kernel +Release: %{release}_%{krel} + +## Install Requirements +%if %weak +Requires: %{ktype} +Requires(post): %{__weak_modules} +Requires(postun): %{__weak_modules} +%else +Requires: %{ktype} = %{kver} +%endif +Requires(post): %{__depmod} +Requires(postun): %{__depmod} + +## Install Provides +Provides: kernel-modules = %{kver} +Provides: %{name}-kmod = %{version} + +## Description +%description -n kmod-%{name} +iSCSI Enterprise Target kernel module +%endif + + +## +## Package Creation +## + +## Preparation +%prep + + +## Setup +%if %svn +%setup -q -D -T -c -n %{name}-%{version} +if [ ! -f include/iet_u.h ]; then +%{__svn} export --force --non-interactive -q %{svn_url} . +%{__sed} -i -e "s/\(#define IET_VERSION_STRING\).*/\1\t\"%{version}\"/" include/iet_u.h +# Patches to apply to SVN +#%patch0 -p0 +fi +%else +%setup -q -n %{name}-%{version} +# Patches to apply to release +#%patch0 -p0 +%endif + + +## Build +%build +%{__make} distclean +%ifnarch noarch +%if %dkms +%{__make} usr +%else +%{__make} KERNELSRC=/lib/modules/%{kernel}/build +%endif +%endif + + +## Installation +%install +%{__rm} -rf %{buildroot} + +%ifnarch noarch +%if %dkms +%{__make} install-usr install-doc install-etc KERNELSRC=/lib/modules/%{kernel}/build DISTDIR=%{buildroot} +%else +%{__make} install-files KERNELSRC=/lib/modules/%{kernel}/build DISTDIR=%{buildroot} +%{__rm} -f %{buildroot}/lib/modules/%{kernel}/modules.* +%endif +%if %is_redhat || %is_fedora +%{__mkdir} -p %{buildroot}/etc/rc.d +%{__mv} %{buildroot}/etc/init.d %{buildroot}/etc/rc.d +%endif +%{__rm} -rf %{buildroot}/usr/share/doc/iscsitarget +%elseif %dkms +%{__mkdir} -p %{buildroot}/usr/src/%{name}-%{version} +%{__cp} -r COPYING include kernel patches %{buildroot}/usr/src/%{name}-%{version} +%{__sed} -e "s/PACKAGE_VERSION=.*/PACKAGE_VERSION=\"%{version}\"/" dkms.conf >%{buildroot}/usr/src/%{name}-%{version}/dkms.conf +%endif + +# Ugly hack to filter out unwanted dependencies +%if %weak +%global _use_internal_dependency_generator 0 +%if %(test -n "%{pro_filter}" && echo 1 || echo 0) +%define iet_provides %{_tmppath}/iet_provides-%{user} +%{__cat} << EOF > %{iet_provides} +%{__find_provides} "\$@" | %{__grep} -v %{pro_filter} +exit 0 +EOF +%{__chmod} 755 %{iet_provides} +%define __find_provides %{iet_provides} +%endif +%if %(test -n "%{req_filter}" && echo 1 || echo 0) +%define iet_requires %{_tmppath}/iet_requires-%{user} +%{__cat} << EOF > %{iet_requires} +%{__find_requires} "\$@" | %{__grep} -v %{req_filter} +exit 0 +EOF +%{__chmod} 755 %{iet_requires} +%define __find_requires %{iet_requires} +%endif +%endif + +## Cleaning +%clean +%{__rm} -rf %{buildroot} +%if %{?iet_provides:1}%{!?iet_provides:0} +%{__rm} -f %{iet_provides} +%endif +%if %{?iet_requires:1}%{!?iet_requires:0} +%{__rm} -f %{iet_requires} +%endif + + +## Post-Install Script +%ifnarch noarch +%post +%if %is_suse +%{__ln} -s %{_initrddir}/iscsi-target %{_sbindir}/rciscsi-target +%endif +%{__chkconfig} --add iscsi-target +%endif + + +## Pre-Uninstall Script +%ifnarch noarch +%preun +if [ "$1" = 0 ]; then + %{__service} iscsi-target stop &>/dev/null + %{__chkconfig} --del iscsi-target &>/dev/null +fi +%if %is_suse +%{__rm} -f %{_sbindir}/rciscsi-target +%endif +%endif + + +## Post-Uninstall Script +%ifnarch noarch +%postun +if [ "$1" != 0 ]; then + %{__service} iscsi-target condrestart &>/dev/null +fi +%endif + + +## Post-Install Script (Kernel Module) +%if %dkms +%ifarch noarch +%post -n kmod-%{name} +%{__dkms} add -m %{name} -v %{version} +%{__dkms} build -m %{name} -v %{version} +%{__dkms} install -m %{name} -v %{version} +%endif +%else +%post -n kmod-%{name} +%{__depmod} %{kernel} -a +%if %weak +if [ -x %{__weak_modules} ]; then + echo %{module} | %{__weak_modules} --add-modules +fi +%endif +%endif + + +## Pre-Uninstall Script (Kernel Module) +%if %dkms +%ifarch noarch +%preun -n kmod-%{name} +%{__dkms} remove -m %{name} -v %{version} --all +%endif +%else +%preun -n kmod-%{name} +%{__modprobe} -r -q --set-version %{kernel} iscsi_trgt +%if %weak +if [ -x %{__weak_modules} ]; then + echo %{module} | %{__weak_modules} --remove-modules +fi +%endif +%endif + + +## Post-Uninstall Script (Kernel Module) +%if !%dkms +%postun -n kmod-%{name} +%{__depmod} %{kernel} -a +%endif + + +## File Catalog +%ifnarch noarch +%files +%defattr(-, root, root) +%{_sbindir}/* +%{_mandir}/man?/* +%{_initrddir}/* +%config(noreplace) %{_sysconfdir}/iet/ietd.conf +%config(noreplace) %{_sysconfdir}/iet/initiators.allow +%config(noreplace) %{_sysconfdir}/iet/targets.allow +%doc ChangeLog COPYING RELEASE_NOTES README README.vmware README.initiators +%endif + + +## File Catalog (Kernel Module) +%if %dkms +%ifarch noarch +%files -n kmod-%{name} +%defattr(-, root, root) +/usr/src/%{name}-%{version}/* +%endif +%else +%files -n kmod-%{name} +%defattr(-, root, root) +/lib/modules/%{kernel} +%endif + + +%changelog +* Wed Oct 14 2009 Ross Walker - 1.4.18 +- Added more macros for better cross-distro support +- Modified Matt's update for better Redhat-SuSE compatibility + +* Fri Oct 09 2009 Matthew Wild - 1.4.18 +- Added openSuSE specific configuration +- Tidied up files section for init.d|rc.d +- run depmod with -a rather than -A option + +* Wed Sep 25 2009 Ross Walker - 0.4.17-244 +- SuSE puts weak-modules under /usr/lib/module-init-tools +- Kernel module now located in /lib/modules//extra/iscsi + +* Wed Sep 25 2009 Ross Walker - 0.4.17-242 +- Added ability to build weak modules for platforms that support them +- Cleaned up logic a little +- Made safe for multi-user builds +- Redacted old spec file maintainer's email address + +* Wed Sep 22 2009 Ross Walker - 0.4.17-236 +- Updated file catalog for new config directory + +* Wed Sep 09 2009 Ross Walker - 0.4.17-226 +- Added ability to build directly from subversion repo +- Added ability to build dkms kernel module + +* Mon Nov 10 2008 Ross Walker - 0.4.17-177 +- Changed kernel-module naming to kmod +- Updated versioning + +* Fri Feb 16 2007 Ross Walker - 0.4.14-96 +- Reworked spec file for latest release +- Commented and cleaned up sections +- Added additional documents to %files + +* Mon Nov 21 2005 Bastiaan Bakker - 0.4.13-0.1266.1 +- upstream snapshot 1266 +- added condrestart patch +- stop and start service on update or removal + +* Sun Nov 13 2005 Bastiaan Bakker - 0.4.13-0.1264.2 +- run %post and %preun for kernel package, not main package + +* Sun Nov 13 2005 Bastiaan Bakker - 0.4.13-0.1264.1 +- updated to snapshot 1264 + +* Thu Nov 03 2005 Bastiaan Bakker - 0.4.12-6 +- added openssl-devel build requirement +- removed '.ko' extension in modprobe command + +* Wed Nov 02 2005 Bastiaan Bakker - 0.4.12-5 +- fixed kernel-devel BuildRequires + +* Fri Sep 23 2005 Bastiaan Bakker - 0.4.12-4 +- fixed modprobe -r 'FATAL' message +- run depmod with correct kernel version + +* Fri Sep 23 2005 Bastiaan Bakker - 0.4.12-3 +- added config files +- set kernel module file permissions to 744 +- fixed provides/requires of kernel module +- removed BuildArch restriction + +* Thu Sep 22 2005 Bastiaan Bakker - 0.4.12-2 +- create separate subpackage for kernel module +- include man pages +- added kernel compatibility patch for kernels < 2.6.11 + +* Wed Aug 03 2005 Bastiaan Bakker +- First version. + diff -Nru iscsitarget-0.4.16+svn162/kernel/Makefile iscsitarget-1.4.19+svn275/kernel/Makefile --- iscsitarget-0.4.16+svn162/kernel/Makefile 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/Makefile 2009-12-09 18:08:55.000000000 +0000 @@ -13,5 +13,5 @@ iscsi_trgt-objs := tio.o iscsi.o nthread.o wthread.o config.o digest.o \ conn.o session.o target.o volume.o iotype.o \ file-io.o null-io.o target_disk.o event.o param.o \ - block-io.o + block-io.o ua.o diff -Nru iscsitarget-0.4.16+svn162/kernel/block-io.c iscsitarget-1.4.19+svn275/kernel/block-io.c --- iscsitarget-0.4.16+svn162/kernel/block-io.c 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/block-io.c 2009-04-13 18:56:21.000000000 +0000 @@ -154,14 +154,14 @@ { struct blockio_data *bio_data = volume->private; struct block_device *bdev; - int flags = LUReadonly(volume) ? MS_RDONLY : 0; + int flags = FMODE_READ | (LUReadonly(volume) ? 0 : FMODE_WRITE); int err = 0; bio_data->path = kstrdup(path, GFP_KERNEL); if (!bio_data->path) return -ENOMEM; - bdev = open_bdev_excl(path, flags, THIS_MODULE); + bdev = open_bdev_exclusive(path, flags, THIS_MODULE); if (IS_ERR(bdev)) { err = PTR_ERR(bdev); eprintk("Can't open device %s, error %d\n", path, err); @@ -323,9 +323,10 @@ blockio_detach(struct iet_volume *volume) { struct blockio_data *bio_data = volume->private; + int flags = FMODE_READ | (LUReadonly(volume) ? 0 : FMODE_WRITE); if (bio_data->bdev) - close_bdev_excl(bio_data->bdev); + close_bdev_exclusive(bio_data->bdev, flags); kfree(bio_data->path); kfree(volume->private); diff -Nru iscsitarget-0.4.16+svn162/kernel/config.c iscsitarget-1.4.19+svn275/kernel/config.c --- iscsitarget-0.4.16+svn162/kernel/config.c 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/config.c 2009-12-09 18:08:55.000000000 +0000 @@ -43,8 +43,6 @@ if (!(proc_iet_dir = proc_mkdir("iet", init_net.proc_net))) goto err; - proc_iet_dir->owner = THIS_MODULE; - for (i = 0; i < ARRAY_SIZE(iet_proc_entries); i++) { ent = create_proc_entry(iet_proc_entries[i].name, 0, proc_iet_dir); if (ent) @@ -309,8 +307,16 @@ return err; } +static int release(struct inode *i __attribute__((unused)), + struct file *f __attribute__((unused))) +{ + target_del_all(); + return 0; +} + struct file_operations ctr_fops = { .owner = THIS_MODULE, .unlocked_ioctl = ioctl, .compat_ioctl = ioctl, + .release = release }; diff -Nru iscsitarget-0.4.16+svn162/kernel/conn.c iscsitarget-1.4.19+svn275/kernel/conn.c --- iscsitarget-0.4.16+svn162/kernel/conn.c 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/conn.c 2009-12-09 18:08:55.000000000 +0000 @@ -46,9 +46,8 @@ "%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->daddr)); break; case AF_INET6: - snprintf(buf, sizeof(buf), - "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", - NIP6(inet6_sk(sk)->daddr)); + snprintf(buf, sizeof(buf), "[%pI6]", + &inet6_sk(sk)->daddr); break; default: break; @@ -96,6 +95,28 @@ target->nthread_info.old_data_ready(sk, len); } +/* + * @locking: grabs the target's nthread_lock to protect it from races with + * set_conn_wspace_wait() + */ +static void iet_write_space(struct sock *sk) +{ + struct iscsi_conn *conn = sk->sk_user_data; + struct network_thread_info *info = &conn->session->target->nthread_info; + + spin_lock_bh(&info->nthread_lock); + + if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && + test_bit(CONN_WSPACE_WAIT, &conn->state)) { + clear_bit(CONN_WSPACE_WAIT, &conn->state); + __nthread_wakeup(info); + } + + spin_unlock_bh(&info->nthread_lock); + + info->old_write_space(sk); +} + static void iet_socket_bind(struct iscsi_conn *conn) { int opt = 1; @@ -114,6 +135,9 @@ target->nthread_info.old_data_ready = conn->sock->sk->sk_data_ready; conn->sock->sk->sk_data_ready = iet_data_ready; + + target->nthread_info.old_write_space = conn->sock->sk->sk_write_space; + conn->sock->sk->sk_write_space = iet_write_space; write_unlock_bh(&conn->sock->sk->sk_callback_lock); oldfs = get_fs(); @@ -134,6 +158,7 @@ list_del(&conn->list); list_del(&conn->poll_list); + del_timer_sync(&conn->nop_timer); digest_cleanup(conn); kfree(conn); @@ -168,6 +193,7 @@ INIT_LIST_HEAD(&conn->pdu_list); INIT_LIST_HEAD(&conn->write_list); INIT_LIST_HEAD(&conn->poll_list); + init_timer(&conn->nop_timer); list_add(&conn->list, &session->conn_list); @@ -216,3 +242,12 @@ return 0; } + +/* target_lock() supposed to be held */ +void conn_del_all(struct iscsi_session *session) +{ + struct iscsi_conn *conn; + + list_for_each_entry(conn, &session->conn_list, list) + conn_close(conn); +} diff -Nru iscsitarget-0.4.16+svn162/kernel/event.c iscsitarget-1.4.19+svn275/kernel/event.c --- iscsitarget-0.4.16+svn162/kernel/event.c 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/event.c 2009-04-13 18:56:21.000000000 +0000 @@ -92,6 +92,5 @@ void event_exit(void) { - if (nl) - sock_release(nl->sk_socket); + netlink_kernel_release(nl); } diff -Nru iscsitarget-0.4.16+svn162/kernel/file-io.c iscsitarget-1.4.19+svn275/kernel/file-io.c --- iscsitarget-0.4.16+svn162/kernel/file-io.c 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/file-io.c 2009-04-13 18:56:21.000000000 +0000 @@ -307,7 +307,7 @@ return err; } -void fileio_show(struct iet_volume *lu, struct seq_file *seq) +static void fileio_show(struct iet_volume *lu, struct seq_file *seq) { struct fileio_data *p = lu->private; seq_printf(seq, " path:%s\n", p->path); diff -Nru iscsitarget-0.4.16+svn162/kernel/iscsi.c iscsitarget-1.4.19+svn275/kernel/iscsi.c --- iscsitarget-0.4.16+svn162/kernel/iscsi.c 2007-11-27 00:29:05.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/iscsi.c 2009-12-09 18:08:55.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2002-2003 Ardis Technolgies + * Copyright (C) 2008 Arne Redlich * * Released under the terms of the GNU GPL v2.0. */ @@ -14,9 +15,10 @@ #include "iotype.h" unsigned long debug_enable_flags; +unsigned long worker_thread_pool_size; static struct kmem_cache *iscsi_cmnd_cache; -static char dummy_data[1024]; +static u8 dummy_data[PAGE_SIZE]; static int ctr_major; static char ctr_name[] = "ietctl"; @@ -138,7 +140,7 @@ /** * create a new command. * - * iscsi_cmnd_create - + * iscsi_cmnd_create - * @conn: ptr to connection (for i/o) * * @return ptr to command or NULL @@ -172,7 +174,7 @@ /** * create a new command used as response. * - * iscsi_cmnd_create_rsp_cmnd - + * iscsi_cmnd_create_rsp_cmnd - * @cmnd: ptr to request command * * @return ptr to response command or NULL @@ -301,6 +303,7 @@ struct iscsi_cmnd *rsp; struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req); struct iscsi_scsi_rsp_hdr *rsp_hdr; + struct iscsi_sense_data *sense; rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); @@ -308,99 +311,93 @@ rsp_hdr->opcode = ISCSI_OP_SCSI_RSP; rsp_hdr->flags = ISCSI_FLG_FINAL; rsp_hdr->response = ISCSI_RESPONSE_COMMAND_COMPLETED; - rsp_hdr->cmd_status = SAM_STAT_GOOD; + rsp_hdr->cmd_status = req->status; rsp_hdr->itt = req_hdr->itt; + if (req->status == SAM_STAT_CHECK_CONDITION) { + assert(!rsp->tio); + rsp->tio = tio_alloc(1); + sense = (struct iscsi_sense_data *) + page_address(rsp->tio->pvec[0]); + + assert(sense); + clear_page(sense); + sense->length = cpu_to_be16(IET_SENSE_BUF_SIZE); + + memcpy(sense->data, req->sense_buf, IET_SENSE_BUF_SIZE); + rsp->pdu.datasize = sizeof(struct iscsi_sense_data) + + IET_SENSE_BUF_SIZE; + + rsp->tio->size = (rsp->pdu.datasize + 3) & -4; + rsp->tio->offset = 0; + } + return rsp; } -static struct iscsi_cmnd *create_sense_rsp(struct iscsi_cmnd *req, - u8 sense_key, u8 asc, u8 ascq) +void iscsi_cmnd_set_sense(struct iscsi_cmnd *cmnd, u8 sense_key, u8 asc, + u8 ascq) { - struct iscsi_cmnd *rsp; - struct iscsi_scsi_rsp_hdr *rsp_hdr; - struct tio *tio; - struct iscsi_sense_data *sense; - - rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); - - rsp_hdr = (struct iscsi_scsi_rsp_hdr *)&rsp->pdu.bhs; - rsp_hdr->opcode = ISCSI_OP_SCSI_RSP; - rsp_hdr->flags = ISCSI_FLG_FINAL; - rsp_hdr->response = ISCSI_RESPONSE_COMMAND_COMPLETED; - rsp_hdr->cmd_status = SAM_STAT_CHECK_CONDITION; - rsp_hdr->itt = cmnd_hdr(req)->itt; + cmnd->status = SAM_STAT_CHECK_CONDITION; - tio = rsp->tio = tio_alloc(1); - sense = (struct iscsi_sense_data *) page_address(tio->pvec[0]); - assert(sense); - clear_page(sense); - sense->length = cpu_to_be16(14); - sense->data[0] = 0xf0; - sense->data[2] = sense_key; - sense->data[7] = 6; // Additional sense length - sense->data[12] = asc; - sense->data[13] = ascq; - - rsp->pdu.datasize = sizeof(struct iscsi_sense_data) + 14; - tio->size = (rsp->pdu.datasize + 3) & -4; - tio->offset = 0; + cmnd->sense_buf[0] = 0xf0; + cmnd->sense_buf[2] = sense_key; + cmnd->sense_buf[7] = 6; // Additional sense length + cmnd->sense_buf[12] = asc; + cmnd->sense_buf[13] = ascq; +} - return rsp; +static struct iscsi_cmnd *create_sense_rsp(struct iscsi_cmnd *req, + u8 sense_key, u8 asc, u8 ascq) +{ + iscsi_cmnd_set_sense(req, sense_key, asc, ascq); + return create_scsi_rsp(req); } -void send_scsi_rsp(struct iscsi_cmnd *req, int (*func)(struct iscsi_cmnd *)) +void send_scsi_rsp(struct iscsi_cmnd *req, void (*func)(struct iscsi_cmnd *)) { struct iscsi_cmnd *rsp; struct iscsi_scsi_rsp_hdr *rsp_hdr; u32 size; - int ret = func(req); - switch (ret) { - case 0: - case -EBUSY: - rsp = create_scsi_rsp(req); + func(req); + rsp = create_scsi_rsp(req); + + switch (req->status) { + case SAM_STAT_GOOD: + case SAM_STAT_RESERVATION_CONFLICT: rsp_hdr = (struct iscsi_scsi_rsp_hdr *) &rsp->pdu.bhs; if ((size = cmnd_read_size(req)) != 0) { rsp_hdr->flags |= ISCSI_FLG_RESIDUAL_UNDERFLOW; rsp_hdr->residual_count = cpu_to_be32(size); } - if (ret == -EBUSY) - rsp_hdr->cmd_status = SAM_STAT_RESERVATION_CONFLICT; - break; - case -EIO: - /* Medium Error/Write Fault */ - rsp = create_sense_rsp(req, MEDIUM_ERROR, 0x03, 0x0); break; default: - rsp = create_sense_rsp(req, ILLEGAL_REQUEST, 0x24, 0x0); + break; } + iscsi_cmnd_init_write(rsp); } -void send_data_rsp(struct iscsi_cmnd *req, int (*func)(struct iscsi_cmnd *)) +void send_data_rsp(struct iscsi_cmnd *req, void (*func)(struct iscsi_cmnd *)) { struct iscsi_cmnd *rsp; - switch (func(req)) { - case 0: + func(req); + + if (req->status == SAM_STAT_GOOD) do_send_data_rsp(req); - return; - case -EIO: - /* Medium Error/Unrecovered Read Error */ - rsp = create_sense_rsp(req, MEDIUM_ERROR, 0x11, 0x0); - break; - default: - rsp = create_sense_rsp(req, ILLEGAL_REQUEST, 0x24, 0x0); + else { + rsp = create_scsi_rsp(req); + iscsi_cmnd_init_write(rsp); } - iscsi_cmnd_init_write(rsp); } /** * Free a command. * Also frees the additional header. * - * iscsi_cmnd_remove - + * iscsi_cmnd_remove - * @cmnd: ptr to command */ @@ -410,6 +407,12 @@ if (!cmnd) return; + + if (cmnd_timer_active(cmnd)) { + clear_cmnd_timer_active(cmnd); + del_timer_sync(&cmnd->timer); + } + dprintk(D_GENERIC, "%p\n", cmnd); conn = cmnd->conn; kfree(cmnd->pdu.ahs); @@ -569,7 +572,7 @@ return cmnd; } -static int cmnd_insert_hash(struct iscsi_cmnd *cmnd) +static int cmnd_insert_hash_ttt(struct iscsi_cmnd *cmnd, u32 ttt) { struct iscsi_session *session = cmnd->conn->session; struct iscsi_cmnd *tmp; @@ -577,17 +580,11 @@ int err = 0; u32 itt = cmnd->pdu.bhs.itt; - dprintk(D_GENERIC, "%p:%x\n", cmnd, itt); - if (itt == ISCSI_RESERVED_TAG) { - err = -ISCSI_REASON_PROTOCOL_ERROR; - goto out; - } - - head = &session->cmnd_hash[cmnd_hashfn(cmnd->pdu.bhs.itt)]; + head = &session->cmnd_hash[cmnd_hashfn(itt)]; spin_lock(&session->cmnd_hash_lock); - tmp = __cmnd_find_hash(session, itt, ISCSI_RESERVED_TAG); + tmp = __cmnd_find_hash(session, itt, ttt); if (!tmp) { list_add_tail(&cmnd->hash_list, head); set_cmnd_hashed(cmnd); @@ -596,12 +593,24 @@ spin_unlock(&session->cmnd_hash_lock); + return err; +} + +static int cmnd_insert_hash(struct iscsi_cmnd *cmnd) +{ + int err; + + dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd->pdu.bhs.itt); + + if (cmnd->pdu.bhs.itt == ISCSI_RESERVED_TAG) + return -ISCSI_REASON_PROTOCOL_ERROR; + + err = cmnd_insert_hash_ttt(cmnd, ISCSI_RESERVED_TAG); if (!err) { update_stat_sn(cmnd); err = check_cmd_sn(cmnd); } -out: return err; } @@ -617,8 +626,8 @@ spin_lock(&session->cmnd_hash_lock); - tmp = __cmnd_find_hash(session, cmnd->pdu.bhs.itt, ISCSI_RESERVED_TAG); - + tmp = __cmnd_find_hash(session, cmnd->pdu.bhs.itt, + cmnd->target_task_tag); if (tmp && tmp == cmnd) __cmnd_remove_hash(tmp); else @@ -829,24 +838,34 @@ } } -static int noop_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) +static int nop_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) { u32 size, tmp; int i, err = 0; if (cmnd_ttt(cmnd) != cpu_to_be32(ISCSI_RESERVED_TAG)) { - /* - * We don't request a NOP-Out by sending a NOP-In. - * See 10.18.2 in the draft 20. - */ - eprintk("initiator bug %x\n", cmnd_itt(cmnd)); - err = -ISCSI_REASON_PROTOCOL_ERROR; - goto out; + cmnd->req = cmnd_find_hash(conn->session, cmnd->pdu.bhs.itt, + cmnd->pdu.bhs.ttt); + if (!cmnd->req) { + /* + * We didn't request this NOP-Out (by sending a + * NOP-In, see 10.18.2 of the RFC) or our fake NOP-Out + * timed out. + */ + eprintk("initiator bug %x\n", cmnd_itt(cmnd)); + err = -ISCSI_REASON_PROTOCOL_ERROR; + goto out; + } + + del_timer_sync(&cmnd->req->timer); + clear_cmnd_timer_active(cmnd->req); + dprintk(D_GENERIC, "NOP-Out: %p, ttt %x, timer %p\n", + cmnd->req, cmnd_ttt(cmnd->req), &cmnd->req->timer); } if (cmnd_itt(cmnd) == cpu_to_be32(ISCSI_RESERVED_TAG)) { if (!(cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE)) - eprintk("%s\n","initiator bug!"); + eprintk("%s\n", "initiator bug!"); update_stat_sn(cmnd); err = check_cmd_sn(cmnd); if (err) @@ -1158,7 +1177,7 @@ struct iscsi_session *session; struct iscsi_conn *conn; struct iscsi_cmnd *cmnd, *tmp; - struct iet_volume *volumes; + struct iet_volume *volume; list_for_each_entry(session, &target->session_list, list) { list_for_each_entry(conn, &session->conn_list, list) { @@ -1174,10 +1193,15 @@ } } - list_for_each_entry(volumes, &target->volumes, list) - if (all || volumes->lun == lun) + list_for_each_entry(volume, &target->volumes, list) { + if (all || volume->lun == lun) { /* force release */ - volume_release(volumes, 0, 1); + volume_release(volume, 0, 1); + /* power-on, reset, or bus device reset occurred */ + ua_establish_for_all_sessions(target, volume->lun, + 0x29, 0x0); + } + } return 0; } @@ -1210,7 +1234,7 @@ "Task Reassign", }; - if ((fun < ISCSI_FUNCTION_ABORT_TASK) || + if ((fun < ISCSI_FUNCTION_ABORT_TASK) || (fun > ISCSI_FUNCTION_TASK_REASSIGN)) fun = 0; @@ -1312,19 +1336,24 @@ iscsi_cmnd_init_write(rsp); } -static void noop_out_exec(struct iscsi_cmnd *req) +static void nop_hdr_setup(struct iscsi_hdr *hdr, u8 opcode, __be32 itt, + __be32 ttt) +{ + hdr->opcode = opcode; + hdr->flags = ISCSI_FLG_FINAL; + hdr->itt = itt; + hdr->ttt = ttt; +} + +static void nop_out_exec(struct iscsi_cmnd *req) { struct iscsi_cmnd *rsp; - struct iscsi_nop_in_hdr *rsp_hdr; if (cmnd_itt(req) != cpu_to_be32(ISCSI_RESERVED_TAG)) { rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); - rsp_hdr = (struct iscsi_nop_in_hdr *)&rsp->pdu.bhs; - rsp_hdr->opcode = ISCSI_OP_NOOP_IN; - rsp_hdr->flags = ISCSI_FLG_FINAL; - rsp_hdr->itt = req->pdu.bhs.itt; - rsp_hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); + nop_hdr_setup(&rsp->pdu.bhs, ISCSI_OP_NOP_IN, req->pdu.bhs.itt, + cpu_to_be32(ISCSI_RESERVED_TAG)); if (req->pdu.datasize) assert(req->tio); @@ -1339,8 +1368,86 @@ assert(get_pgcnt(req->pdu.datasize, 0) < ISCSI_CONN_IOV_MAX); rsp->pdu.datasize = req->pdu.datasize; iscsi_cmnd_init_write(rsp); - } else + } else { + if (req->req) { + dprintk(D_GENERIC, "releasing NOP-Out %p, ttt %x; " + "removing NOP-In %p, ttt %x\n", req->req, + cmnd_ttt(req->req), req, cmnd_ttt(req)); + cmnd_release(req->req, 0); + } iscsi_cmnd_remove(req); + } +} + +static void nop_in_timeout(unsigned long data) +{ + struct iscsi_cmnd *req = (struct iscsi_cmnd *)data; + + printk(KERN_INFO "NOP-In ping timed out - closing sid:cid %llu:%u\n", + req->conn->session->sid, req->conn->cid); + clear_cmnd_timer_active(req); + conn_close(req->conn); +} + +/* create a fake NOP-Out req and treat the NOP-In as our rsp to it */ +void send_nop_in(struct iscsi_conn *conn) +{ + struct iscsi_cmnd *req = cmnd_alloc(conn, 1); + struct iscsi_cmnd *rsp = iscsi_cmnd_create_rsp_cmnd(req, 0); + + req->target_task_tag = get_next_ttt(conn->session); + + + nop_hdr_setup(&req->pdu.bhs, ISCSI_OP_NOP_OUT, + cpu_to_be32(ISCSI_RESERVED_TAG), req->target_task_tag); + nop_hdr_setup(&rsp->pdu.bhs, ISCSI_OP_NOP_IN, + cpu_to_be32(ISCSI_RESERVED_TAG), req->target_task_tag); + + dprintk(D_GENERIC, "NOP-Out: %p, ttt %x, timer %p; " + "NOP-In: %p, ttt %x;\n", req, cmnd_ttt(req), &req->timer, rsp, + cmnd_ttt(rsp)); + + init_timer(&req->timer); + req->timer.data = (unsigned long)req; + req->timer.function = nop_in_timeout; + + if (cmnd_insert_hash_ttt(req, req->target_task_tag)) { + eprintk("%s\n", + "failed to insert fake NOP-Out into hash table"); + cmnd_release(rsp, 0); + cmnd_release(req, 0); + } else + iscsi_cmnd_init_write(rsp); +} + +static void nop_in_tx_end(struct iscsi_cmnd *cmnd) +{ + struct iscsi_conn *conn = cmnd->conn; + u32 t; + + if (cmnd->pdu.bhs.ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) + return; + + /* + * NOP-In ping issued by the target. + * FIXME: Sanitize the NOP timeout earlier, during configuration + */ + t = conn->session->target->trgt_param.nop_timeout; + + if (!t || t > conn->session->target->trgt_param.nop_interval) { + eprintk("Adjusting NOPTimeout of tid %u from %u to %u " + "(== NOPInterval)\n", conn->session->target->tid, + t, + conn->session->target->trgt_param.nop_interval); + t = conn->session->target->trgt_param.nop_interval; + conn->session->target->trgt_param.nop_timeout = t; + } + + dprintk(D_GENERIC, "NOP-In %p, %x: timer %p\n", cmnd, cmnd_ttt(cmnd), + &cmnd->req->timer); + + set_cmnd_timer_active(cmnd->req); + mod_timer(&cmnd->req->timer, jiffies + HZ * t); } static void logout_exec(struct iscsi_cmnd *req) @@ -1364,8 +1471,8 @@ dprintk(D_GENERIC, "%p,%x,%u\n", cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn); switch (cmnd_opcode(cmnd)) { - case ISCSI_OP_NOOP_OUT: - noop_out_exec(cmnd); + case ISCSI_OP_NOP_OUT: + nop_out_exec(cmnd); break; case ISCSI_OP_SCSI_CMD: scsi_cmnd_exec(cmnd); @@ -1490,8 +1597,15 @@ conn->write_size = sizeof(cmnd->pdu.bhs); switch (cmnd_opcode(cmnd)) { - case ISCSI_OP_NOOP_IN: - cmnd_set_sn(cmnd, 1); + case ISCSI_OP_NOP_IN: + if (cmnd->pdu.bhs.itt == ISCSI_RESERVED_TAG) { + /* NOP-In ping generated by us. Don't advance StatSN. */ + cmnd_set_sn(cmnd, 0); + cmnd_set_sn(cmnd->req, 0); + cmnd->pdu.bhs.sn = cpu_to_be32(conn->stat_sn); + cmnd->req->pdu.bhs.sn = cpu_to_be32(conn->stat_sn); + } else + cmnd_set_sn(cmnd, 1); cmnd_send_pdu(conn, cmnd); break; case ISCSI_OP_SCSI_RSP: @@ -1546,7 +1660,9 @@ dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); switch (cmnd_opcode(cmnd)) { - case ISCSI_OP_NOOP_IN: + case ISCSI_OP_NOP_IN: + nop_in_tx_end(cmnd); + break; case ISCSI_OP_SCSI_RSP: case ISCSI_OP_SCSI_TASK_MGT_RSP: case ISCSI_OP_TEXT_RSP: @@ -1574,7 +1690,7 @@ * This functions reorders the commands. * Called from the read thread. * - * iscsi_session_push_cmnd - + * iscsi_session_push_cmnd - * @cmnd: ptr to command */ @@ -1661,8 +1777,8 @@ return; switch (cmnd_opcode(cmnd)) { - case ISCSI_OP_NOOP_OUT: - err = noop_out_start(conn, cmnd); + case ISCSI_OP_NOP_OUT: + err = nop_out_start(conn, cmnd); break; case ISCSI_OP_SCSI_CMD: if (!(err = cmnd_insert_hash(cmnd))) @@ -1704,7 +1820,7 @@ dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); switch (cmnd_opcode(cmnd)) { case ISCSI_OP_SCSI_REJECT: - case ISCSI_OP_NOOP_OUT: + case ISCSI_OP_NOP_OUT: case ISCSI_OP_SCSI_CMD: case ISCSI_OP_SCSI_TASK_MGT_MSG: case ISCSI_OP_TEXT_CMD: @@ -1731,6 +1847,8 @@ static void iscsi_exit(void) { + wthread_module_exit(); + unregister_chrdev(ctr_major, ctr_name); iet_procfs_exit(); @@ -1741,6 +1859,8 @@ iotype_exit(); + ua_exit(); + if (iscsi_cmnd_cache) kmem_cache_destroy(iscsi_cmnd_cache); } @@ -1766,12 +1886,19 @@ if (!iscsi_cmnd_cache) goto err; + err = ua_init(); + if (err < 0) + goto err; + if ((err = tio_init()) < 0) goto err; if ((err = iotype_init()) < 0) goto err; + if ((err = wthread_module_init()) < 0) + goto err; + return 0; err: @@ -1779,9 +1906,19 @@ return err; } -module_param(debug_enable_flags, ulong, S_IRUGO); +module_param(worker_thread_pool_size, ulong, S_IRUGO); +MODULE_PARM_DESC(worker_thread_pool_size, + "Size of the worker thread pool " + "(0 = dedicated threads per target (default))"); + +module_param(debug_enable_flags, ulong, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_enable_flags, + "debug bitmask, low bits (0 ... 8) used, see iscsi_dbg.h"); module_init(iscsi_init); module_exit(iscsi_exit); +MODULE_VERSION(IET_VERSION_STRING); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("iSCSI Enterprise Target"); +MODULE_AUTHOR("IET development team "); diff -Nru iscsitarget-0.4.16+svn162/kernel/iscsi.h iscsitarget-1.4.19+svn275/kernel/iscsi.h --- iscsitarget-0.4.16+svn162/kernel/iscsi.h 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/iscsi.h 2009-12-09 18:08:55.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2002-2003 Ardis Technolgies + * Copyright (C) 2008 Arne Redlich * * Released under the terms of the GNU GPL v2.0. */ @@ -7,6 +8,7 @@ #ifndef __ISCSI_H__ #define __ISCSI_H__ +#include #include #include #include @@ -17,6 +19,8 @@ #include "iscsi_hdr.h" #include "iet_u.h" +#define IET_SENSE_BUF_SIZE 18 + struct iscsi_sess_param { int initial_r2t; int immediate_data; @@ -43,6 +47,8 @@ int wthreads; int target_type; int queued_cmnds; + int nop_interval; + int nop_timeout; }; struct tio { @@ -66,6 +72,7 @@ void (*old_state_change)(struct sock *); void (*old_data_ready)(struct sock *, int); + void (*old_write_space)(struct sock *); }; struct worker_thread_info; @@ -112,10 +119,15 @@ struct list_head volumes; struct list_head session_list; + /* Prevents races between add/del session and adding UAs */ + spinlock_t session_list_lock; + struct network_thread_info nthread_info; - struct worker_thread_info wthread_info; + /* Points either to own list or global pool */ + struct worker_thread_info * wthread_info; struct semaphore target_sem; + struct completion *done; }; struct iscsi_queue { @@ -171,10 +183,12 @@ #define IET_HASH_ORDER 8 #define cmnd_hashfn(itt) hash_long((itt), IET_HASH_ORDER) +#define UA_HASH_LEN 8 + struct iscsi_session { struct list_head list; struct iscsi_target *target; - + struct completion *done; char *initiator; u64 sid; @@ -191,12 +205,17 @@ spinlock_t cmnd_hash_lock; struct list_head cmnd_hash[1 << IET_HASH_ORDER]; + spinlock_t ua_hash_lock; + struct list_head ua_hash[UA_HASH_LEN]; + u32 next_ttt; }; enum connection_state_bit { CONN_ACTIVE, CONN_CLOSING, + CONN_WSPACE_WAIT, + CONN_NEED_NOP_IN, }; #define ISCSI_CONN_IOV_MAX (((256 << 10) >> PAGE_SHIFT) + 1) @@ -223,6 +242,7 @@ atomic_t nr_busy_cmnds; struct list_head pdu_list; /* in/outcoming pdus */ struct list_head write_list; /* list of data pdus to be sent */ + struct timer_list nop_timer; struct iscsi_cmnd *read_cmnd; struct msghdr read_msg; @@ -267,6 +287,10 @@ struct tio *tio; + u8 status; + + struct timer_list timer; + u32 r2t_sn; u32 r2t_length; u32 is_unsolicited_data; @@ -277,6 +301,16 @@ u32 ddigest; struct iscsi_cmnd *req; + + unsigned char sense_buf[IET_SENSE_BUF_SIZE]; +}; + +struct ua_entry { + struct list_head entry; + struct iscsi_session *session; /* only used for debugging ATM */ + u32 lun; + u8 asc; + u8 ascq; }; #define ISCSI_OP_SCSI_REJECT ISCSI_OP_VENDOR1_CMD @@ -285,19 +319,24 @@ #define ISCSI_OP_SCSI_ABORT ISCSI_OP_VENDOR4_CMD /* iscsi.c */ +extern unsigned long worker_thread_pool_size; extern struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *, int); extern void cmnd_rx_start(struct iscsi_cmnd *); extern void cmnd_rx_end(struct iscsi_cmnd *); extern void cmnd_tx_start(struct iscsi_cmnd *); extern void cmnd_tx_end(struct iscsi_cmnd *); extern void cmnd_release(struct iscsi_cmnd *, int); -extern void send_data_rsp(struct iscsi_cmnd *, int (*)(struct iscsi_cmnd *)); -extern void send_scsi_rsp(struct iscsi_cmnd *, int (*)(struct iscsi_cmnd *)); +extern void send_data_rsp(struct iscsi_cmnd *, void (*)(struct iscsi_cmnd *)); +extern void send_scsi_rsp(struct iscsi_cmnd *, void (*)(struct iscsi_cmnd *)); +extern void iscsi_cmnd_set_sense(struct iscsi_cmnd *, u8 sense_key, u8 asc, + u8 ascq); +extern void send_nop_in(struct iscsi_conn *); /* conn.c */ extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16); extern int conn_add(struct iscsi_session *, struct conn_info *); extern int conn_del(struct iscsi_session *, struct conn_info *); +extern void conn_del_all(struct iscsi_session *); extern int conn_free(struct iscsi_conn *); extern void conn_close(struct iscsi_conn *); extern void conn_info_show(struct seq_file *, struct iscsi_session *); @@ -306,14 +345,18 @@ extern int nthread_init(struct iscsi_target *); extern int nthread_start(struct iscsi_target *); extern int nthread_stop(struct iscsi_target *); +extern void __nthread_wakeup(struct network_thread_info *); extern void nthread_wakeup(struct iscsi_target *); /* wthread.c */ -extern int wthread_init(struct iscsi_target *); -extern int wthread_start(struct iscsi_target *); -extern int wthread_stop(struct iscsi_target *); +extern int wthread_init(struct worker_thread_info *info); +extern int wthread_start(struct worker_thread_info *info, int wthreads, u32 tid); +extern int wthread_stop(struct worker_thread_info *info); extern void wthread_queue(struct iscsi_cmnd *); extern struct target_type *target_type_array[]; +extern int wthread_module_init(void); +extern void wthread_module_exit(void); +extern struct worker_thread_info *worker_thread_pool; /* target.c */ extern int target_lock(struct iscsi_target *, int); @@ -321,6 +364,8 @@ struct iscsi_target *target_lookup_by_id(u32); extern int target_add(struct target_info *); extern int target_del(u32 id); +extern void target_del_all(void); +extern struct seq_operations iet_seq_op; /* config.c */ extern int iet_procfs_init(void); @@ -332,6 +377,7 @@ extern struct iscsi_session *session_lookup(struct iscsi_target *, u64); extern int session_add(struct iscsi_target *, struct session_info *); extern int session_del(struct iscsi_target *, u64); +extern void session_del_all(struct iscsi_target *); /* volume.c */ extern struct file_operations volume_seq_fops; @@ -371,6 +417,21 @@ extern int event_init(void); extern void event_exit(void); +/* ua.c */ +int ua_init(void); +void ua_exit(void); +struct ua_entry * ua_get_first(struct iscsi_session *, u32 lun); +struct ua_entry * ua_get_match(struct iscsi_session *, u32 lun, u8 asc, + u8 ascq); +void ua_free(struct ua_entry *); +int ua_pending(struct iscsi_session *, u32 lun); +void ua_establish_for_session(struct iscsi_session *, u32 lun, u8 asc, + u8 ascq); +void ua_establish_for_other_sessions(struct iscsi_session *, u32 lun, u8 asc, + u8 ascq); +void ua_establish_for_all_sessions(struct iscsi_target *, u32 lun, u8 asc, + u8 ascq); + #define get_pgcnt(size, offset) ((((size) + ((offset) & ~PAGE_CACHE_MASK)) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) static inline void iscsi_cmnd_get_length(struct iscsi_pdu *pdu) @@ -416,6 +477,7 @@ CMND_pending, CMND_tmfabort, CMND_rxstart, + CMND_timer_active, }; #define set_cmnd_hashed(cmnd) set_bit(CMND_hashed, &(cmnd)->flags) @@ -446,6 +508,11 @@ #define set_cmnd_rxstart(cmnd) set_bit(CMND_rxstart, &(cmnd)->flags) #define cmnd_rxstart(cmnd) test_bit(CMND_rxstart, &(cmnd)->flags) +#define set_cmnd_timer_active(cmnd) set_bit(CMND_timer_active, &(cmnd)->flags) +#define clear_cmnd_timer_active(cmnd) \ + clear_bit(CMND_timer_active, &(cmnd)->flags) +#define cmnd_timer_active(cmnd) test_bit(CMND_timer_active, &(cmnd)->flags) + #define VENDOR_ID "IET" #define PRODUCT_ID "VIRTUAL-DISK" #define PRODUCT_REV "0" diff -Nru iscsitarget-0.4.16+svn162/kernel/iscsi_dbg.h iscsitarget-1.4.19+svn275/kernel/iscsi_dbg.h --- iscsitarget-0.4.16+svn162/kernel/iscsi_dbg.h 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/iscsi_dbg.h 2009-12-09 18:08:55.000000000 +0000 @@ -10,6 +10,7 @@ #define D_THREAD (1UL << 6) #define D_TASK_MGT (1UL << 7) #define D_IOMODE (1UL << 8) +#define D_UAC (1UL << 9) #define D_DATA (D_READ | D_WRITE) @@ -24,6 +25,12 @@ } \ } while (0) +#define dprintk_ua(ua, sess, lun) \ + dprintk(D_UAC, "sess %llu, lun %u: %p %x %x\n", \ + (sess)->sid, lun, ua, \ + (ua) ? (ua)->asc : 0, \ + (ua) ? (ua)->ascq : 0) + #define eprintk(fmt, args...) do { \ printk(KERN_ERR PFX "%s(%d) " fmt, __FUNCTION__, \ __LINE__, args);\ diff -Nru iscsitarget-0.4.16+svn162/kernel/iscsi_hdr.h iscsitarget-1.4.19+svn275/kernel/iscsi_hdr.h --- iscsitarget-0.4.16+svn162/kernel/iscsi_hdr.h 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/iscsi_hdr.h 2009-12-09 18:08:55.000000000 +0000 @@ -43,7 +43,7 @@ #define ISCSI_OPCODE_MASK 0x3F /* Client to Server Message Opcode values */ -#define ISCSI_OP_NOOP_OUT 0x00 +#define ISCSI_OP_NOP_OUT 0x00 #define ISCSI_OP_SCSI_CMD 0x01 #define ISCSI_OP_SCSI_TASK_MGT_MSG 0x02 #define ISCSI_OP_LOGIN_CMD 0x03 @@ -58,7 +58,7 @@ #define ISCSI_OP_VENDOR4_CMD 0x1f /* Server to Client Message Opcode values */ -#define ISCSI_OP_NOOP_IN 0x20 +#define ISCSI_OP_NOP_IN 0x20 #define ISCSI_OP_SCSI_RSP 0x21 #define ISCSI_OP_SCSI_TASK_MGT_RSP 0x22 #define ISCSI_OP_LOGIN_RSP 0x23 diff -Nru iscsitarget-0.4.16+svn162/kernel/nthread.c iscsitarget-1.4.19+svn275/kernel/nthread.c --- iscsitarget-0.4.16+svn162/kernel/nthread.c 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/nthread.c 2009-12-09 18:08:55.000000000 +0000 @@ -1,6 +1,8 @@ /* * Network thread. * (C) 2004 - 2005 FUJITA Tomonori + * (C) 2008 Arne Redlich + * * This code is licenced under the GPL. */ @@ -18,13 +20,18 @@ D_DATA_READY, }; +void __nthread_wakeup(struct network_thread_info *info) +{ + set_bit(D_DATA_READY, &info->flags); + wake_up_process(info->task); +} + void nthread_wakeup(struct iscsi_target *target) { struct network_thread_info *info = &target->nthread_info; spin_lock_bh(&info->nthread_lock); - set_bit(D_DATA_READY, &info->flags); - wake_up_process(info->task); + __nthread_wakeup(info); spin_unlock_bh(&info->nthread_lock); } @@ -283,6 +290,23 @@ return 0; } +/* + * @locking: grabs the target's nthread_lock to protect it from races with + * iet_write_space() + */ +static void set_conn_wspace_wait(struct iscsi_conn *conn) +{ + struct network_thread_info *info = &conn->session->target->nthread_info; + struct sock *sk = conn->sock->sk; + + spin_lock_bh(&info->nthread_lock); + + if (sk_stream_wspace(sk) < sk_stream_min_wspace(sk)) + set_bit(CONN_WSPACE_WAIT, &conn->state); + + spin_unlock_bh(&info->nthread_lock); +} + /* This is taken from the Ardis code. */ static int write_data(struct iscsi_conn *conn) { @@ -399,8 +423,11 @@ conn->write_offset = (idx << PAGE_CACHE_SHIFT) + offset; out_iov: conn->write_size = size; - if ((saved_size == size) && res == -EAGAIN) - return res; + if (res == -EAGAIN) { + set_conn_wspace_wait(conn); + if (saved_size == size) + return res; + } return saved_size - size; @@ -542,6 +569,45 @@ return 0; } +static void conn_nop_timeout(unsigned long data) +{ + struct iscsi_conn *conn = (struct iscsi_conn *)data; + + if (test_bit(CONN_ACTIVE, &conn->state)) + set_bit(CONN_NEED_NOP_IN, &conn->state); + + dprintk(D_THREAD, "conn %llu:%hu, NOP timer %p\n", conn->session->sid, + conn->cid, &conn->nop_timer); + + nthread_wakeup(conn->session->target); +} + +static void conn_reset_nop_timer(struct iscsi_conn *conn) +{ + struct iscsi_target *target = conn->session->target; + + if (target->trgt_param.nop_interval) + mod_timer(&conn->nop_timer, + jiffies + HZ * target->trgt_param.nop_interval); +} + +static void conn_start_nop_timer(struct iscsi_conn *conn) +{ + struct iscsi_target *target = conn->session->target; + + if (!target->trgt_param.nop_interval || timer_pending(&conn->nop_timer)) + return; + + conn->nop_timer.data = (unsigned long)conn; + conn->nop_timer.function = conn_nop_timeout; + + dprintk(D_THREAD, "conn %llu:%hu, NOP timer %p\n", conn->session->sid, + conn->cid, &conn->nop_timer); + + mod_timer(&conn->nop_timer, + jiffies + HZ * target->trgt_param.nop_interval); +} + static void process_io(struct iscsi_conn *conn) { struct iscsi_target *target = conn->session->target; @@ -549,22 +615,34 @@ res = recv(conn); - if (is_data_available(conn) > 0 || res > 0) + if (is_data_available(conn) > 0 || res > 0) { + conn_reset_nop_timer(conn); wakeup = 1; + } if (!test_bit(CONN_ACTIVE, &conn->state)) { wakeup = 1; goto out; } + if (test_bit(CONN_WSPACE_WAIT, &conn->state)) + goto out; + res = send(conn); - if (!list_empty(&conn->write_list) || conn->write_cmnd) + if (!list_empty(&conn->write_list) || conn->write_cmnd) { + conn_reset_nop_timer(conn); wakeup = 1; + } out: if (wakeup) nthread_wakeup(target); + else if (test_and_clear_bit(CONN_NEED_NOP_IN, &conn->state)) { + send_nop_in(conn); + nthread_wakeup(target); + } else + conn_start_nop_timer(conn); return; } @@ -572,15 +650,18 @@ static void close_conn(struct iscsi_conn *conn) { struct iscsi_session *session = conn->session; + struct iscsi_target *target = conn->session->target; struct iscsi_cmnd *cmnd; - assert(conn); + if (target->trgt_param.nop_interval) + del_timer_sync(&conn->nop_timer); conn->sock->ops->shutdown(conn->sock, 2); write_lock_bh(&conn->sock->sk->sk_callback_lock); - conn->sock->sk->sk_state_change = session->target->nthread_info.old_state_change; - conn->sock->sk->sk_data_ready = session->target->nthread_info.old_data_ready; + conn->sock->sk->sk_state_change = target->nthread_info.old_state_change; + conn->sock->sk->sk_data_ready = target->nthread_info.old_data_ready; + conn->sock->sk->sk_write_space = target->nthread_info.old_write_space; write_unlock_bh(&conn->sock->sk->sk_callback_lock); fput(conn->file); @@ -604,11 +685,15 @@ assert(0); } - event_send(session->target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0); + event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0); conn_free(conn); - if (list_empty(&session->conn_list)) - session_del(session->target, session->sid); + if (list_empty(&session->conn_list)) { + if (session->done) + complete(session->done); + else + session_del(target, session->sid); + } } static int istd(void *arg) @@ -654,6 +739,7 @@ info->old_state_change = NULL; info->old_data_ready = NULL; + info->old_write_space = NULL; INIT_LIST_HEAD(&info->active_conns); @@ -693,8 +779,10 @@ err = kthread_stop(info->task); - if (!err) - info->task = NULL; + if (err < 0 && err != -EINTR) + return err; - return err; + info->task = NULL; + + return 0; } diff -Nru iscsitarget-0.4.16+svn162/kernel/param.c iscsitarget-1.4.19+svn275/kernel/param.c --- iscsitarget-0.4.16+svn162/kernel/param.c 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/param.c 2009-12-09 18:08:55.000000000 +0000 @@ -116,7 +116,12 @@ CHECK_PARAM(info, iparam, wthreads, MIN_NR_WTHREADS, MAX_NR_WTHREADS); CHECK_PARAM(info, iparam, target_type, 0, (unsigned int) ARRAY_SIZE(target_type_array) - 1); - CHECK_PARAM(info, iparam, queued_cmnds, MIN_NR_QUEUED_CMNDS, MAX_NR_QUEUED_CMNDS); + CHECK_PARAM(info, iparam, queued_cmnds, MIN_NR_QUEUED_CMNDS, + MAX_NR_QUEUED_CMNDS); + CHECK_PARAM(info, iparam, nop_interval, MIN_NOP_INTERVAL, + MAX_NOP_INTERVAL); + CHECK_PARAM(info, iparam, nop_timeout, MIN_NOP_TIMEOUT, + MAX_NOP_TIMEOUT); } static void trgt_param_set(struct iscsi_target *target, struct iscsi_param_info *info) @@ -124,10 +129,14 @@ struct iscsi_trgt_param *param = &target->trgt_param; u32 *iparam = info->target_param; - if (SET_PARAM(param, info, iparam, wthreads)) - wthread_start(target); + if (!worker_thread_pool && + SET_PARAM(param, info, iparam, wthreads)) + wthread_start(target->wthread_info, + target->trgt_param.wthreads, target->tid); SET_PARAM(param, info, iparam, target_type); SET_PARAM(param, info, iparam, queued_cmnds); + SET_PARAM(param, info, iparam, nop_interval); + SET_PARAM(param, info, iparam, nop_timeout); } static void trgt_param_get(struct iscsi_trgt_param *param, struct iscsi_param_info *info) @@ -137,6 +146,8 @@ GET_PARAM(param, info, iparam, wthreads); GET_PARAM(param, info, iparam, target_type); GET_PARAM(param, info, iparam, queued_cmnds); + GET_PARAM(param, info, iparam, nop_interval); + GET_PARAM(param, info, iparam, nop_timeout); } static int trgt_param(struct iscsi_target *target, struct iscsi_param_info *info, int set) diff -Nru iscsitarget-0.4.16+svn162/kernel/session.c iscsitarget-1.4.19+svn275/kernel/session.c --- iscsitarget-0.4.16+svn162/kernel/session.c 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/session.c 2009-12-09 18:08:55.000000000 +0000 @@ -23,6 +23,7 @@ { int i; struct iscsi_session *session; + struct iet_volume *vol; dprintk(D_SETUP, "%p %u %#Lx\n", target, target->tid, (unsigned long long) info->sid); @@ -52,9 +53,19 @@ for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++) INIT_LIST_HEAD(&session->cmnd_hash[i]); + spin_lock_init(&session->ua_hash_lock); + for (i = 0; i < ARRAY_SIZE(session->ua_hash); i++) + INIT_LIST_HEAD(&session->ua_hash[i]); + + list_for_each_entry(vol, &target->volumes, list) + /* power-on, reset, or bus device reset occurred */ + ua_establish_for_session(session, vol->lun, 0x29, 0x0); + session->next_ttt = 1; + spin_lock(&target->session_list_lock); list_add(&session->list, &target->session_list); + spin_unlock(&target->session_list_lock); return session; } @@ -62,9 +73,14 @@ static int session_free(struct iscsi_session *session) { int i; + struct ua_entry *ua, *tmp; + struct list_head *l; + struct iscsi_target *target = session->target; dprintk(D_SETUP, "%#Lx\n", (unsigned long long) session->sid); + spin_lock(&target->session_list_lock); + assert(list_empty(&session->conn_list)); for (i = 0; i < ARRAY_SIZE(session->cmnd_hash); i++) { @@ -72,28 +88,37 @@ BUG(); } + for (i = 0; i < ARRAY_SIZE(session->ua_hash); i++) { + l = &session->ua_hash[i]; + list_for_each_entry_safe(ua, tmp, l, entry) { + list_del_init(&ua->entry); + ua_free(ua); + } + } + list_del(&session->list); kfree(session->initiator); kfree(session); + spin_unlock(&target->session_list_lock); + return 0; } int session_add(struct iscsi_target *target, struct session_info *info) { struct iscsi_session *session; - int err = -EEXIST; session = session_lookup(target, info->sid); if (session) - return err; + return -EEXIST; session = iet_session_alloc(target, info); if (!session) - err = -ENOMEM; + return -ENOMEM; - return err; + return 0; } int session_del(struct iscsi_target *target, u64 sid) @@ -112,6 +137,29 @@ return session_free(session); } +void session_del_all(struct iscsi_target *target) +{ + DECLARE_COMPLETION_ONSTACK(done); + struct iscsi_session *sess; + + while (!list_empty(&target->session_list)) { + init_completion(&done); + target_lock(target, 0); + sess = list_entry(target->session_list.next, struct + iscsi_session, list); + sess->done = &done; + conn_del_all(sess); + target_unlock(target); + wait_for_completion(&done); + target_lock(target, 0); + session_free(sess); + target_unlock(target); + } + + if (target->done) + complete(target->done); +} + static void iet_session_info_show(struct seq_file *seq, struct iscsi_target *target) { struct iscsi_session *session; @@ -123,14 +171,14 @@ } } -static int iet_sessions_info_show(struct seq_file *seq, void *v) -{ - return iet_info_show(seq, iet_session_info_show); -} - static int iet_session_seq_open(struct inode *inode, struct file *file) { - return single_open(file, iet_sessions_info_show, NULL); + int res; + res = seq_open(file, &iet_seq_op); + if (!res) + ((struct seq_file *)file->private_data)->private = + iet_session_info_show; + return res; } struct file_operations session_seq_fops = { @@ -138,5 +186,5 @@ .open = iet_session_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; diff -Nru iscsitarget-0.4.16+svn162/kernel/target.c iscsitarget-1.4.19+svn275/kernel/target.c --- iscsitarget-0.4.16+svn162/kernel/target.c 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/target.c 2009-12-09 18:08:55.000000000 +0000 @@ -100,8 +100,11 @@ if ((err = nthread_start(target)) < 0) return err; - if ((err = wthread_start(target)) < 0) { - nthread_stop(target); + if (!worker_thread_pool) { + err = wthread_start(target->wthread_info, + target->trgt_param.wthreads, target->tid); + if (err) + nthread_stop(target); } return err; @@ -109,7 +112,9 @@ static void target_thread_stop(struct iscsi_target *target) { - wthread_stop(target); + if (!worker_thread_pool) + wthread_stop(target->wthread_info); + nthread_stop(target); } @@ -137,6 +142,14 @@ goto out; } + if (!worker_thread_pool) { + target->wthread_info = kmalloc(sizeof(struct worker_thread_info), GFP_KERNEL); + if (!target->wthread_info) { + err = -ENOMEM; + goto out; + } + } + target->tid = info->tid = tid; memcpy(&target->sess_param, &default_session_param, sizeof(default_session_param)); @@ -145,24 +158,32 @@ strncpy(target->name, name, sizeof(target->name) - 1); init_MUTEX(&target->target_sem); + spin_lock_init(&target->session_list_lock); INIT_LIST_HEAD(&target->session_list); INIT_LIST_HEAD(&target->volumes); atomic_set(&target->nr_volumes, 0); - list_add(&target->t_list, &target_list); - nthread_init(target); - wthread_init(target); + + if (!worker_thread_pool) + wthread_init(target->wthread_info); + else + target->wthread_info = worker_thread_pool; + if ((err = target_thread_start(target)) < 0) { target_thread_stop(target); goto out; } + list_add(&target->t_list, &target_list); + return 0; out: + if (!worker_thread_pool) + kfree(target->wthread_info); kfree(target); module_put(THIS_MODULE); @@ -217,65 +238,120 @@ iscsi_volume_destroy(volume); } + if (!worker_thread_pool) + kfree(target->wthread_info); kfree(target); module_put(THIS_MODULE); } -int target_del(u32 id) +/* @locking: target_list_sem must be locked */ +int __target_del(struct iscsi_target *target) { - struct iscsi_target *target; - int err; - - if ((err = down_interruptible(&target_list_sem)) < 0) - return err; - - if (!(target = __target_lookup_by_id(id))) { - err = -ENOENT; - goto out; - } - target_lock(target, 0); if (!list_empty(&target->session_list)) { - err = -EBUSY; target_unlock(target); - goto out; + return -EBUSY; } list_del(&target->t_list); nr_targets--; target_unlock(target); - up(&target_list_sem); - target_destroy(target); return 0; -out: - up(&target_list_sem); - return err; } -int iet_info_show(struct seq_file *seq, iet_show_info_t *func) +int target_del(u32 id) { - int err; struct iscsi_target *target; - - if ((err = down_interruptible(&target_list_sem)) < 0) + int err = down_interruptible(&target_list_sem); + if (err < 0) return err; - list_for_each_entry(target, &target_list, t_list) { - seq_printf(seq, "tid:%u name:%s\n", target->tid, target->name); + target = __target_lookup_by_id(id); + if (!target) { + err = -ENOENT; + goto out; + } + + err = __target_del(target); + out: + up(&target_list_sem); + return err; +} - if ((err = target_lock(target, 1)) < 0) - break; +void target_del_all(void) +{ + DECLARE_COMPLETION_ONSTACK(done); + struct iscsi_target *target, *tmp; - func(seq, target); + down(&target_list_sem); - target_unlock(target); + if (!list_empty(&target_list)) + iprintk("Removing all connections, sessions and targets\n"); + + list_for_each_entry_safe(target, tmp, &target_list, t_list) { + init_completion(&done); + target->done = &done; + session_del_all(target); + wait_for_completion(&done); + __target_del(target); } + next_target_id = 0; + up(&target_list_sem); +} + +static void *iet_seq_start(struct seq_file *m, loff_t *pos) +{ + int err; + + /* are you sure this is to be interruptible? */ + err = down_interruptible(&target_list_sem); + if (err < 0) + return ERR_PTR(err); + + return seq_list_start(&target_list, *pos); +} + +static void *iet_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + return seq_list_next(v, &target_list, pos); +} + +static void iet_seq_stop(struct seq_file *m, void *v) +{ + up(&target_list_sem); +} + +static int iet_seq_show(struct seq_file *m, void *p) +{ + iet_show_info_t *func = (iet_show_info_t *)m->private; + struct iscsi_target *target = + list_entry(p, struct iscsi_target, t_list); + int err; + + /* relly, interruptible? I'd think target_lock(target, 0) + * would be more appropriate. --lge */ + err = target_lock(target, 1); + if (err < 0) + return err; + + seq_printf(m, "tid:%u name:%s\n", target->tid, target->name); + + func(m, target); + + target_unlock(target); return 0; } + +struct seq_operations iet_seq_op = { + .start = iet_seq_start, + .next = iet_seq_next, + .stop = iet_seq_stop, + .show = iet_seq_show, +}; diff -Nru iscsitarget-0.4.16+svn162/kernel/target_disk.c iscsitarget-1.4.19+svn275/kernel/target_disk.c --- iscsitarget-0.4.16+svn162/kernel/target_disk.c 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/target_disk.c 2009-12-09 18:08:55.000000000 +0000 @@ -55,12 +55,15 @@ return sizeof(iec_m_pg); } -static int insert_format_m_pg(u8 *ptr) +static int insert_format_m_pg(u8 *ptr, u32 sector_size) { unsigned char format_m_pg[] = {0x03, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00}; + memcpy(ptr, format_m_pg, sizeof(format_m_pg)); + ptr[12] = (sector_size >> 8) & 0xff; + ptr[13] = sector_size & 0xff; return sizeof(format_m_pg); } @@ -81,7 +84,7 @@ return sizeof(geo_m_pg); } -static int build_mode_sense_response(struct iscsi_cmnd *cmnd) +static void build_mode_sense_response(struct iscsi_cmnd *cmnd) { struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); struct tio *tio = cmnd->tio; @@ -91,7 +94,7 @@ /* changeable parameter mode pages are unsupported */ if ((scb[2] & 0xc0) >> 6 == 0x1) - return -1; + goto set_sense; pcode = req->scb[2] & 0x3f; @@ -121,7 +124,7 @@ len += insert_disconnect_pg(data + len); break; case 0x3: - len += insert_format_m_pg(data + len); + len += insert_format_m_pg(data + len, 1 << cmnd->lun->blk_shift); break; case 0x4: len += insert_geo_m_pg(data + len, cmnd->lun->blk_cnt); @@ -138,7 +141,7 @@ break; case 0x3f: len += insert_disconnect_pg(data + len); - len += insert_format_m_pg(data + len); + len += insert_format_m_pg(data + len, 1 << cmnd->lun->blk_shift); len += insert_geo_m_pg(data + len, cmnd->lun->blk_cnt); len += insert_caching_pg(data + len, LUWCache(cmnd->lun), LURCache(cmnd->lun)); @@ -149,14 +152,20 @@ err = -1; } - data[0] = len - 1; - - tio_set(tio, len, 0); + if (!err) { + data[0] = len - 1; + tio_set(tio, len, 0); + return; + } - return err; + tio_put(tio); + cmnd->tio = NULL; + set_sense: + /* Invalid Field In CDB */ + iscsi_cmnd_set_sense(cmnd, ILLEGAL_REQUEST, 0x24, 0x0); } -static int build_inquiry_response(struct iscsi_cmnd *cmnd) +static void build_inquiry_response(struct iscsi_cmnd *cmnd) { struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); struct tio *tio = cmnd->tio; @@ -169,7 +178,7 @@ * - CmdDt set: not supported */ if ((scb[1] & 0x3) > 0x1 || (!(scb[1] & 0x3) && scb[2])) - return err; + goto set_sense; assert(!tio); tio = cmnd->tio = tio_alloc(1); @@ -179,7 +188,7 @@ if (!(scb[1] & 0x3)) { data[2] = 4; - data[3] = 0x42; + data[3] = 0x52; data[4] = 59; data[7] = 0x02; memset(data + 8, 0x20, 28); @@ -242,14 +251,21 @@ } } - tio_set(tio, min_t(u8, tio->size, scb[4]), 0); - if (!cmnd->lun) - data[0] = TYPE_NO_LUN; + if (!err) { + tio_set(tio, min_t(u8, tio->size, scb[4]), 0); + if (!cmnd->lun) + data[0] = TYPE_NO_LUN; + return; + } - return err; + tio_put(tio); + cmnd->tio = NULL; + set_sense: + /* Invalid Field In CDB */ + iscsi_cmnd_set_sense(cmnd, ILLEGAL_REQUEST, 0x24, 0x0); } -static int build_report_luns_response(struct iscsi_cmnd *cmnd) +static void build_report_luns_response(struct iscsi_cmnd *cmnd) { struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); struct tio *tio = cmnd->tio; @@ -259,8 +275,11 @@ size = (u32)req->scb[6] << 24 | (u32)req->scb[7] << 16 | (u32)req->scb[8] << 8 | (u32)req->scb[9]; - if (size < 16) - return -1; + if (size < 16) { + /* Invalid Field In CDB */ + iscsi_cmnd_set_sense(cmnd, ILLEGAL_REQUEST, 0x24, 0x0); + return; + } len = atomic_read(&cmnd->conn->session->target->nr_volumes) * 8; size = min(size & ~(8 - 1), len + 8); @@ -290,11 +309,9 @@ rest = PAGE_CACHE_SIZE; } } - - return 0; } -static int build_read_capacity_response(struct iscsi_cmnd *cmnd) +static void build_read_capacity_response(struct iscsi_cmnd *cmnd) { struct tio *tio = cmnd->tio; u32 *data; @@ -310,10 +327,9 @@ data[1] = cpu_to_be32(1U << cmnd->lun->blk_shift); tio_set(tio, 8, 0); - return 0; } -static int build_request_sense_response(struct iscsi_cmnd *cmnd) +static void build_request_sense_response(struct iscsi_cmnd *cmnd) { struct tio *tio = cmnd->tio; u8 *data; @@ -328,18 +344,23 @@ data[2] = NO_SENSE; data[7] = 10; tio_set(tio, 18, 0); - - return 0; } -static int build_service_action_response(struct iscsi_cmnd *cmnd) +static void build_service_action_in_response(struct iscsi_cmnd *cmnd) { struct tio *tio = cmnd->tio; u32 *data; u64 *data64; -/* assert((req->scb[1] & 0x1f) == 0x10); */ assert(!tio); + + /* only READ_CAPACITY_16 service action is currently supported */ + if ((cmnd_hdr(cmnd)->scb[1] & 0x1F) != 0x10) { + /* Invalid Field In CDB */ + iscsi_cmnd_set_sense(cmnd, ILLEGAL_REQUEST, 0x24, 0x0); + return; + } + tio = cmnd->tio = tio_alloc(1); data = page_address(tio->pvec[0]); assert(data); @@ -349,20 +370,21 @@ data[2] = cpu_to_be32(1UL << cmnd->lun->blk_shift); tio_set(tio, 12, 0); - return 0; } -static int build_read_response(struct iscsi_cmnd *cmnd) +static void build_read_response(struct iscsi_cmnd *cmnd) { struct tio *tio = cmnd->tio; assert(tio); assert(cmnd->lun); - return tio_read(cmnd->lun, tio); + if (tio_read(cmnd->lun, tio)) + /* Medium Error/Unrecovered Read Error */ + iscsi_cmnd_set_sense(cmnd, MEDIUM_ERROR, 0x11, 0x0); } -static int build_write_response(struct iscsi_cmnd *cmnd) +static void build_write_response(struct iscsi_cmnd *cmnd) { int err; struct tio *tio = cmnd->tio; @@ -375,41 +397,83 @@ if (!err && !LUWCache(cmnd->lun)) err = tio_sync(cmnd->lun, tio); - return err; + if (err) + /* Medium Error/Write Fault */ + iscsi_cmnd_set_sense(cmnd, MEDIUM_ERROR, 0x03, 0x0); } -static int build_sync_cache_response(struct iscsi_cmnd *cmnd) +static void build_sync_cache_response(struct iscsi_cmnd *cmnd) { assert(cmnd->lun); - return tio_sync(cmnd->lun, NULL); + if (tio_sync(cmnd->lun, NULL)) + /* Medium Error/Write Fault */ + iscsi_cmnd_set_sense(cmnd, MEDIUM_ERROR, 0x03, 0x0); } -static int build_generic_response(struct iscsi_cmnd *cmnd) +static void build_generic_response(struct iscsi_cmnd *cmnd) { - return 0; + return; } -static int build_reserve_response(struct iscsi_cmnd *cmnd) +static void build_reserve_response(struct iscsi_cmnd *cmnd) { - return volume_reserve(cmnd->lun, cmnd->conn->session->sid); + switch (volume_reserve(cmnd->lun, cmnd->conn->session->sid)) { + case -ENOENT: + /* Logical Unit Not Supported (?) */ + iscsi_cmnd_set_sense(cmnd, ILLEGAL_REQUEST, 0x25, 0x0); + break; + case -EBUSY: + cmnd->status = SAM_STAT_RESERVATION_CONFLICT; + break; + default: + break; + } } -static int build_release_response(struct iscsi_cmnd *cmnd) +static void build_release_response(struct iscsi_cmnd *cmnd) { - return volume_release(cmnd->lun, - cmnd->conn->session->sid, 0); + if (volume_release(cmnd->lun, + cmnd->conn->session->sid, 0)) + cmnd->status = SAM_STAT_RESERVATION_CONFLICT; } -static int build_reservation_conflict_response(struct iscsi_cmnd *cmnd) +static void build_reservation_conflict_response(struct iscsi_cmnd *cmnd) { - return -EBUSY; + cmnd->status = SAM_STAT_RESERVATION_CONFLICT; } -static int disk_execute_cmnd(struct iscsi_cmnd *cmnd) +static int disk_check_ua(struct iscsi_cmnd *cmnd) { struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct ua_entry *ua; - req->opcode &= ISCSI_OPCODE_MASK; + if (cmnd->lun && ua_pending(cmnd->conn->session, cmnd->lun->lun)) { + switch(req->scb[0]){ + case INQUIRY: + case REQUEST_SENSE: + break; + case REPORT_LUNS: + ua = ua_get_match(cmnd->conn->session, + cmnd->lun->lun, + /* reported luns data has changed */ + 0x3f, 0x0e); + ua_free(ua); + break; + default: + ua = ua_get_first(cmnd->conn->session, cmnd->lun->lun); + iscsi_cmnd_set_sense(cmnd, UNIT_ATTENTION, ua->asc, + ua->ascq); + ua_free(ua); + send_scsi_rsp(cmnd, build_generic_response); + return 1; + } + } + return 0; +} + +static int disk_check_reservation(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); if (is_volume_reserved(cmnd->lun, cmnd->conn->session->sid)) { @@ -418,16 +482,36 @@ case RELEASE: case REPORT_LUNS: case REQUEST_SENSE: + case READ_CAPACITY: /* allowed commands when reserved */ break; + case SERVICE_ACTION_IN: + if ((cmnd_hdr(cmnd)->scb[1] & 0x1F) == 0x10) + break; + /* fall through */ default: /* return reservation conflict for all others */ send_scsi_rsp(cmnd, build_reservation_conflict_response); - return 0; + return 1; } } + return 0; +} + +static int disk_execute_cmnd(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + + req->opcode &= ISCSI_OPCODE_MASK; + + if (disk_check_ua(cmnd)) + return 0; + + if (disk_check_reservation(cmnd)) + return 0; + switch (req->scb[0]) { case INQUIRY: send_data_rsp(cmnd, build_inquiry_response); @@ -445,7 +529,7 @@ send_data_rsp(cmnd, build_request_sense_response); break; case SERVICE_ACTION_IN: - send_data_rsp(cmnd, build_service_action_response); + send_data_rsp(cmnd, build_service_action_in_response); break; case READ_6: case READ_10: diff -Nru iscsitarget-0.4.16+svn162/kernel/ua.c iscsitarget-1.4.19+svn275/kernel/ua.c --- iscsitarget-0.4.16+svn162/kernel/ua.c 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/ua.c 2009-12-09 18:08:55.000000000 +0000 @@ -0,0 +1,164 @@ +/* + * IET Unit Attention support + * + * Copyright (C) 2009 Xie Gang + * Copyright (C) 2009 Arne Redlich + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" + +#define ua_hashfn(lun) ((lun % UA_HASH_LEN)) + +static struct kmem_cache *ua_cache; + +int ua_init(void) +{ + ua_cache = KMEM_CACHE(ua_entry, 0); + if (!ua_cache) { + eprintk("%s", "Failed to create ua cache\n"); + return -ENOMEM; + } + + return 0; +} + +void ua_exit(void) +{ + if (ua_cache) + kmem_cache_destroy(ua_cache); +} + +/* sess->ua_hash_lock needs to be held */ +static struct ua_entry * ua_find_hash(struct iscsi_session *sess, u32 lun, + u8 asc, u8 ascq, int match) +{ + struct ua_entry *ua; + struct list_head *h = &sess->ua_hash[ua_hashfn(lun)]; + + list_for_each_entry(ua, h, entry) { + if (ua->lun == lun) { + if (!match) + return ua; + if (ua->asc == asc && ua->ascq == ascq) + return ua; + } + } + + return NULL; +} + +int ua_pending(struct iscsi_session *sess, u32 lun) +{ + struct ua_entry *ua; + + spin_lock(&sess->ua_hash_lock); + ua = ua_find_hash(sess, lun, 0, 0, 0); + spin_unlock(&sess->ua_hash_lock); + + dprintk_ua(ua, sess, lun); + + return ua ? 1 : 0; +} + +/* sess->ua_hash_lock needs to be held */ +static struct ua_entry * __ua_get_hash(struct iscsi_session *sess, u32 lun, + u8 asc, u8 ascq, int match) +{ + struct ua_entry *ua = ua_find_hash(sess, lun, asc, ascq, match); + + if (ua) + list_del_init(&ua->entry); + + return ua; +} + +struct ua_entry * ua_get_first(struct iscsi_session *sess, u32 lun) +{ + struct ua_entry *ua; + + spin_lock(&sess->ua_hash_lock); + ua = __ua_get_hash(sess, lun, 0, 0, 0); + spin_unlock(&sess->ua_hash_lock); + + dprintk_ua(ua, sess, lun); + + return ua; +} + +struct ua_entry * ua_get_match(struct iscsi_session *sess, u32 lun, + u8 asc, u8 ascq) +{ + struct ua_entry *ua; + + spin_lock(&sess->ua_hash_lock); + ua = __ua_get_hash(sess, lun, asc, ascq, 1); + spin_unlock(&sess->ua_hash_lock); + + dprintk_ua(ua, sess, lun); + + return ua; +} + +void ua_establish_for_session(struct iscsi_session *sess, u32 lun, + u8 asc, u8 ascq) +{ + struct list_head *l = &sess->ua_hash[ua_hashfn(lun)]; + struct ua_entry *ua = kmem_cache_alloc(ua_cache, GFP_KERNEL); + + if (!ua) { + eprintk("%s", "Failed to alloc ua"); + return; + } + + ua->asc = asc; + ua->ascq = ascq; + ua->lun = lun; + ua->session = sess; + + spin_lock(&sess->ua_hash_lock); + list_add_tail(&ua->entry, l); + spin_unlock(&sess->ua_hash_lock); + + dprintk_ua(ua, sess, lun); +} + +void ua_establish_for_other_sessions(struct iscsi_session *sess, u32 lun, + u8 asc, u8 ascq) +{ + struct list_head *l = &sess->target->session_list; + struct iscsi_session *s; + + spin_lock(&sess->target->session_list_lock); + list_for_each_entry(s, l, list) + if (s->sid != sess->sid) + ua_establish_for_session(s, lun, asc, ascq); + spin_unlock(&sess->target->session_list_lock); +} + +void ua_establish_for_all_sessions(struct iscsi_target *target, u32 lun, + u8 asc, u8 ascq) +{ + struct list_head *l = &target->session_list; + struct iscsi_session *s; + + spin_lock(&target->session_list_lock); + list_for_each_entry(s, l, list) + ua_establish_for_session(s, lun, asc, ascq); + spin_unlock(&target->session_list_lock); + +} + +void ua_free(struct ua_entry *ua) +{ + if (!ua) + return; + + dprintk_ua(ua, ua->session, ua->lun); + BUG_ON(!list_empty(&ua->entry)); + kmem_cache_free(ua_cache, ua); +} diff -Nru iscsitarget-0.4.16+svn162/kernel/volume.c iscsitarget-1.4.19+svn275/kernel/volume.c --- iscsitarget-0.4.16+svn162/kernel/volume.c 2008-06-29 21:49:48.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/volume.c 2009-04-13 18:56:21.000000000 +0000 @@ -245,14 +245,14 @@ } } -static int iet_volumes_info_show(struct seq_file *seq, void *v) -{ - return iet_info_show(seq, iet_volume_info_show); -} - static int iet_volume_seq_open(struct inode *inode, struct file *file) { - return single_open(file, iet_volumes_info_show, NULL); + int res; + res = seq_open(file, &iet_seq_op); + if (!res) + ((struct seq_file *)file->private_data)->private = + iet_volume_info_show; + return res; } struct file_operations volume_seq_fops = { @@ -260,5 +260,5 @@ .open = iet_volume_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; diff -Nru iscsitarget-0.4.16+svn162/kernel/wthread.c iscsitarget-1.4.19+svn275/kernel/wthread.c --- iscsitarget-0.4.16+svn162/kernel/wthread.c 2007-11-02 11:54:37.000000000 +0000 +++ iscsitarget-1.4.19+svn275/kernel/wthread.c 2009-04-13 18:56:21.000000000 +0000 @@ -9,9 +9,11 @@ #include "iscsi.h" #include "iscsi_dbg.h" +struct worker_thread_info *worker_thread_pool; + void wthread_queue(struct iscsi_cmnd *cmnd) { - struct worker_thread_info *info = &cmnd->conn->session->target->wthread_info; + struct worker_thread_info *info = cmnd->conn->session->target->wthread_info; if (!list_empty(&cmnd->list)) { struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); @@ -89,9 +91,8 @@ return 0; } -static int start_one_worker_thread(struct iscsi_target *target) +static int start_one_worker_thread(struct worker_thread_info *info, u32 tid) { - struct worker_thread_info *info = &target->wthread_info; struct worker_thread *wt; struct task_struct *task; @@ -99,7 +100,7 @@ return -ENOMEM; wt->w_info = info; - task = kthread_create(worker_thread, wt, "istiod%d", target->tid); + task = kthread_create(worker_thread, wt, "istiod%d", tid); if (IS_ERR(task)) { kfree(wt); return PTR_ERR(task); @@ -120,7 +121,9 @@ int err; assert(wt->w_task); - if ((err = kthread_stop(wt->w_task)) < 0) + err = kthread_stop(wt->w_task); + + if (err < 0 && err != -EINTR) return err; list_del(&wt->w_list); @@ -130,10 +133,8 @@ return 0; } -int wthread_init(struct iscsi_target *target) +int wthread_init(struct worker_thread_info *info) { - struct worker_thread_info *info = &target->wthread_info; - spin_lock_init(&info->wthread_lock); info->nr_running_wthreads = 0; @@ -146,19 +147,18 @@ return 0; } -int wthread_start(struct iscsi_target *target) +int wthread_start(struct worker_thread_info *info, int wthreads, u32 tid) { int err = 0; - struct worker_thread_info *info = &target->wthread_info; - while (info->nr_running_wthreads < target->trgt_param.wthreads) { - if ((err = start_one_worker_thread(target)) < 0) { + while (info->nr_running_wthreads < wthreads) { + if ((err = start_one_worker_thread(info, tid)) < 0) { eprintk("Fail to create a worker thread %d\n", err); goto out; } } - while (info->nr_running_wthreads > target->trgt_param.wthreads) { + while (info->nr_running_wthreads > wthreads) { struct worker_thread *wt; wt = list_entry(info->wthread_list.next, struct worker_thread, w_list); if ((err = stop_one_worker_thread(wt)) < 0) { @@ -170,11 +170,10 @@ return err; } -int wthread_stop(struct iscsi_target *target) +int wthread_stop(struct worker_thread_info *info) { struct worker_thread *wt, *tmp; int err = 0; - struct worker_thread_info *info = &target->wthread_info; list_for_each_entry_safe(wt, tmp, &info->wthread_list, w_list) { if ((err = stop_one_worker_thread(wt)) < 0) { @@ -185,3 +184,39 @@ return err; } + +int wthread_module_init() +{ + int err; + + if (!worker_thread_pool_size) + return 0; + + worker_thread_pool = kmalloc(sizeof(struct worker_thread_info), + GFP_KERNEL); + if (!worker_thread_pool) + return -ENOMEM; + + wthread_init(worker_thread_pool); + + err = wthread_start(worker_thread_pool, worker_thread_pool_size, 0); + if (err) { + kfree(worker_thread_pool); + worker_thread_pool = NULL; + return err; + } + + iprintk("iscsi_trgt using worker thread pool; size = %ld\n", + worker_thread_pool_size); + + return 0; +} + +void wthread_module_exit() +{ + if (!worker_thread_pool_size) + return; + + wthread_stop(worker_thread_pool); + kfree(worker_thread_pool); +} diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.14-2.6.18.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.14-2.6.18.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.14-2.6.18.patch 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.14-2.6.18.patch 2009-12-09 18:08:56.000000000 +0000 @@ -1,8 +1,8 @@ Index: kernel/iscsi.h =================================================================== ---- kernel/iscsi.h (revision 105) -+++ kernel/iscsi.h (working copy) -@@ -233,8 +233,8 @@ struct iscsi_conn { +--- 1/kernel/iscsi.h (revision 105) ++++ 2/kernel/iscsi.h (working copy) +@@ -254,8 +254,8 @@ struct iscsi_conn { u32 write_offset; int write_state; @@ -15,9 +15,9 @@ Index: kernel/digest.c =================================================================== ---- kernel/digest.c (revision 105) -+++ kernel/digest.c (working copy) -@@ -13,8 +13,7 @@ +--- 1/kernel/digest.c (revision 105) ++++ 2/kernel/digest.c (working copy) +@@ -12,8 +12,7 @@ void digest_alg_available(unsigned int *val) { @@ -27,7 +27,7 @@ printk("CRC32C digest algorithm not available in kernel\n"); *val |= ~DIGEST_CRC32C; } -@@ -38,22 +37,15 @@ int digest_init(struct iscsi_conn *conn) +@@ -37,22 +36,15 @@ int digest_init(struct iscsi_conn *conn) if (!(conn->ddigest_type & DIGEST_ALL)) conn->ddigest_type = DIGEST_NONE; @@ -55,7 +55,7 @@ err = -ENOMEM; goto out; } -@@ -74,10 +66,10 @@ out: +@@ -73,10 +65,10 @@ out: */ void digest_cleanup(struct iscsi_conn *conn) { @@ -70,7 +70,7 @@ } /** -@@ -168,28 +160,28 @@ static inline void __dbg_simulate_data_d +@@ -167,28 +159,28 @@ static inline void __dbg_simulate_data_d (sg).length = (l); \ } while (0) @@ -109,7 +109,7 @@ if (crc != cmnd->hdigest) return -EIO; -@@ -198,19 +190,18 @@ int digest_rx_header(struct iscsi_cmnd * +@@ -197,19 +189,18 @@ int digest_rx_header(struct iscsi_cmnd * void digest_tx_header(struct iscsi_cmnd *cmnd) { @@ -132,7 +132,7 @@ offset += tio->offset; idx = offset >> PAGE_CACHE_SHIFT; -@@ -220,7 +211,7 @@ static void digest_data(struct hash_desc +@@ -219,7 +210,7 @@ static void digest_data(struct hash_desc assert(count <= ISCSI_CONN_IOV_MAX); @@ -141,7 +141,7 @@ for (i = 0; size; i++) { if (offset + size > PAGE_CACHE_SIZE) -@@ -235,8 +226,8 @@ static void digest_data(struct hash_desc +@@ -234,8 +225,8 @@ static void digest_data(struct hash_desc offset = 0; } @@ -152,7 +152,7 @@ } int digest_rx_data(struct iscsi_cmnd *cmnd) -@@ -262,10 +253,9 @@ int digest_rx_data(struct iscsi_cmnd *cm +@@ -261,10 +252,9 @@ int digest_rx_data(struct iscsi_cmnd *cm offset = 0; } @@ -165,7 +165,7 @@ if (crc != cmnd->ddigest) return -EIO; } -@@ -279,6 +269,6 @@ void digest_tx_data(struct iscsi_cmnd *c +@@ -278,6 +268,6 @@ void digest_tx_data(struct iscsi_cmnd *c struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs; assert(tio); @@ -175,9 +175,9 @@ } Index: kernel/file-io.c =================================================================== ---- kernel/file-io.c (revision 105) -+++ kernel/file-io.c (working copy) -@@ -52,9 +52,9 @@ static int fileio_make_request(struct ie +--- 1/kernel/file-io.c (revision 105) ++++ 2/kernel/file-io.c (working copy) +@@ -53,9 +53,9 @@ static int fileio_make_request(struct ie set_fs(get_ds()); if (rw == READ) @@ -191,21 +191,21 @@ Index: kernel/iscsi.c =================================================================== ---- kernel/iscsi.c (revision 105) -+++ kernel/iscsi.c (working copy) -@@ -15,7 +15,7 @@ - +--- 1/kernel/iscsi.c (revision 105) ++++ 2/kernel/iscsi.c (working copy) +@@ -16,7 +16,7 @@ unsigned long debug_enable_flags; + unsigned long worker_thread_pool_size; -static struct kmem_cache *iscsi_cmnd_cache; +static kmem_cache_t *iscsi_cmnd_cache; - static char dummy_data[1024]; + static u8 dummy_data[PAGE_SIZE]; static int ctr_major; Index: kernel/tio.c =================================================================== ---- kernel/tio.c (revision 105) -+++ kernel/tio.c (working copy) +--- 1/kernel/tio.c (revision 105) ++++ 2/kernel/tio.c (working copy) @@ -35,7 +35,7 @@ static int tio_add_pages(struct tio *tio return 0; } diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.19-2.6.21.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.19-2.6.21.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.19-2.6.21.patch 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.19-2.6.21.patch 2009-12-09 18:08:56.000000000 +0000 @@ -1,9 +1,9 @@ Index: kernel/event.c =================================================================== ---- kernel/event.c (working copy) -+++ kernel/event.c (revision 122) +--- 1/kernel/event.c (working copy) ++++ 2/kernel/event.c (revision 122) @@ -95,8 +95,7 @@ int event_send(u32 tid, u64 sid, u32 cid - + int event_init(void) { - nl = netlink_kernel_create(NETLINK_IET, 1, event_recv, NULL, @@ -14,24 +14,24 @@ else Index: kernel/iscsi.c =================================================================== ---- kernel/iscsi.c (working copy) -+++ kernel/iscsi.c (revision 137) -@@ -1757,7 +1757,8 @@ static int iscsi_init(void) +--- 1/kernel/iscsi.c (working copy) ++++ 2/kernel/iscsi.c (revision 137) +@@ -1767,7 +1767,8 @@ static int iscsi_init(void) if ((err = event_init()) < 0) goto err; - + - iscsi_cmnd_cache = KMEM_CACHE(iscsi_cmnd, 0); + iscsi_cmnd_cache = kmem_cache_create("iscsi_cmnd", sizeof(struct iscsi_cmnd), + 0, 0, NULL, NULL); if (!iscsi_cmnd_cache) goto err; - + Index: kernel/tio.c =================================================================== ---- kernel/tio.c (working copy) -+++ kernel/tio.c (revision 137) +--- 1/kernel/tio.c (working copy) ++++ 2/kernel/tio.c (revision 137) @@ -110,7 +110,8 @@ int tio_sync(struct iet_volume *lu, stru - + int tio_init(void) { - tio_cache = KMEM_CACHE(tio, 0); @@ -39,3 +39,18 @@ + 0, 0, NULL, NULL); return tio_cache ? 0 : -ENOMEM; } + +Index: kernel/ua.c +=================================================================== +--- 1/kernel/ua.c ++++ 2/kernel/ua.c +@@ -18,7 +18,8 @@ static struct kmem_cache *ua_cache; + + int ua_init(void) + { +- ua_cache = KMEM_CACHE(ua_entry, 0); ++ ua_cache = kmem_cache_create("iet_ua_cache", sizeof(struct ua_entry), ++ 0, 0, NULL, NULL); + if (!ua_cache) { + eprintk("%s", "Failed to create ua cache\n"); + return -ENOMEM; diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.22.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.22.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.22.patch 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.22.patch 2009-12-09 18:08:56.000000000 +0000 @@ -0,0 +1,95 @@ +Index: kernel/volume.c +=================================================================== +--- a/kernel/volume.c (revision 205) ++++ b/kernel/volume.c (working copy) +@@ -10,6 +10,7 @@ + #include "iscsi.h" + #include "iscsi_dbg.h" + #include "iotype.h" ++#include "seq_list.h" + + struct iet_volume *volume_lookup(struct iscsi_target *target, u32 lun) + { +Index: kernel/seq_list.c +=================================================================== +--- a/kernel/seq_list.c (revision 0) ++++ b/kernel/seq_list.c (revision 0) +@@ -0,0 +1,34 @@ ++/* ++ * seq_list_* API lifted from the kernel's seq_file.c for backward compatibility ++ * with kernels < 2.6.23 ++ */ ++ ++#include ++ ++struct list_head *seq_list_start(struct list_head *head, loff_t pos) ++{ ++ struct list_head *lh; ++ ++ list_for_each(lh, head) ++ if (pos-- == 0) ++ return lh; ++ ++ return NULL; ++} ++ ++struct list_head *seq_list_start_head(struct list_head *head, loff_t pos) ++{ ++ if (!pos) ++ return head; ++ ++ return seq_list_start(head, pos - 1); ++} ++ ++struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos) ++{ ++ struct list_head *lh; ++ ++ lh = ((struct list_head *)v)->next; ++ ++*ppos; ++ return lh == head ? NULL : lh; ++} +Index: kernel/target.c +=================================================================== +--- a/kernel/target.c (revision 205) ++++ b/kernel/target.c (working copy) +@@ -7,6 +7,7 @@ + #include "iscsi.h" + #include "digest.h" + #include "iscsi_dbg.h" ++#include "seq_list.h" + + #define MAX_NR_TARGETS (1UL << 30) + +Index: kernel/seq_list.h +=================================================================== +--- a/kernel/seq_list.h (revision 0) ++++ b/kernel/seq_list.h (revision 0) +@@ -0,0 +1,16 @@ ++/* ++ * seq_list_* API lifted from the kernel's seq_file.c for backward compatibility ++ * with kernels < 2.6.23 ++ */ ++ ++#ifndef __SEQ_LIST_H ++#define __SEQ_LIST_H ++ ++#include ++#include ++ ++struct list_head *seq_list_start(struct list_head *head, loff_t pos); ++struct list_head *seq_list_start_head(struct list_head *head, loff_t pos); ++struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos); ++ ++#endif +Index: kernel/Makefile +=================================================================== +--- a/kernel/Makefile (revision 205) ++++ b/kernel/Makefile (working copy) +@@ -13,5 +13,5 @@ obj-m += iscsi_trgt.o + iscsi_trgt-objs := tio.o iscsi.o nthread.o wthread.o config.o digest.o \ + conn.o session.o target.o volume.o iotype.o \ + file-io.o null-io.o target_disk.o event.o param.o \ +- block-io.o ua.o ++ block-io.o ua.o seq_list.o + diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.23.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.23.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.23.patch 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.23.patch 2009-04-13 18:56:21.000000000 +0000 @@ -0,0 +1,152 @@ +Index: kernel/block-io.c +=================================================================== +--- 1/kernel/block-io.c (working copy) ++++ 2/kernel/block-io.c (revision 145) +@@ -29,10 +29,15 @@ struct tio_work { + struct completion tio_complete; + }; + +-static void blockio_bio_endio(struct bio *bio, int error) ++static int ++blockio_bio_endio(struct bio *bio, unsigned int bytes_done, int error) + { + struct tio_work *tio_work = bio->bi_private; + ++ /* Ignore partials */ ++ if (bio->bi_size) ++ return 1; ++ + error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? error : -EIO; + + if (error) +@@ -43,6 +48,8 @@ static void blockio_bio_endio(struct bio + complete(&tio_work->tio_complete); + + bio_put(bio); ++ ++ return 0; + } + + /* +Index: kernel/config.c +=================================================================== +--- 1/kernel/config.c (working copy) ++++ 2/kernel/config.c (revision 145) +@@ -40,7 +40,7 @@ int iet_procfs_init(void) + int i; + struct proc_dir_entry *ent; + +- if (!(proc_iet_dir = proc_mkdir("iet", init_net.proc_net))) ++ if (!(proc_iet_dir = proc_mkdir("net/iet", 0))) + goto err; + + proc_iet_dir->owner = THIS_MODULE; +Index: kernel/digest.c +=================================================================== +--- 1/kernel/digest.c (working copy) ++++ 2/kernel/digest.c (revision 145) +@@ -160,17 +160,22 @@ static inline void __dbg_simulate_data_d + } + } + ++/* Copied from linux-iscsi initiator and slightly adjusted */ ++#define SETSG(sg, p, l) do { \ ++ (sg).page = virt_to_page((p)); \ ++ (sg).offset = ((unsigned long)(p) & ~PAGE_CACHE_MASK); \ ++ (sg).length = (l); \ ++} while (0) ++ + static void digest_header(struct hash_desc *hash, struct iscsi_pdu *pdu, + u8 *crc) + { + struct scatterlist sg[2]; + unsigned int nbytes = sizeof(struct iscsi_hdr); + +- sg_init_table(sg, pdu->ahssize ? 2 : 1); +- +- sg_set_buf(&sg[0], &pdu->bhs, nbytes); ++ SETSG(sg[0], &pdu->bhs, nbytes); + if (pdu->ahssize) { +- sg_set_buf(&sg[1], pdu->ahs, pdu->ahssize); ++ SETSG(sg[1], pdu->ahs, pdu->ahssize); + nbytes += pdu->ahssize; + } + +@@ -214,7 +219,6 @@ static void digest_data(struct hash_desc + + assert(count <= ISCSI_CONN_IOV_MAX); + +- sg_init_table(sg, ARRAY_SIZE(cmnd->conn->hash_sg)); + crypto_hash_init(hash); + + for (i = 0; size; i++) { +@@ -223,13 +227,13 @@ static void digest_data(struct hash_desc + else + length = size; + +- sg_set_page(&sg[i], tio->pvec[idx + i], length, offset); ++ sg[i].page = tio->pvec[idx + i]; ++ sg[i].offset = offset; ++ sg[i].length = length; + size -= length; + offset = 0; + } + +- sg_mark_end(&sg[i - 1]); +- + crypto_hash_update(hash, sg, nbytes); + crypto_hash_final(hash, crc); + } +Index: kernel/event.c +=================================================================== +--- 1/kernel/event.c (working copy) ++++ 2/kernel/event.c (revision 145) +@@ -28,7 +28,7 @@ static int event_recv_msg(struct sk_buff + return 0; + } + +-static void event_recv_skb(struct sk_buff *skb) ++static int event_recv_skb(struct sk_buff *skb) + { + int err; + struct nlmsghdr *nlh; +@@ -37,7 +37,7 @@ static void event_recv_skb(struct sk_buf + while (skb->len >= NLMSG_SPACE(0)) { + nlh = (struct nlmsghdr *)skb->data; + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) +- break; ++ return 0; + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen = skb->len; +@@ -47,6 +47,19 @@ static void event_recv_skb(struct sk_buf + netlink_ack(skb, nlh, 0); + skb_pull(skb, rlen); + } ++ return 0; ++} ++ ++static void event_recv(struct sock *sk, int length) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { ++ if (event_recv_skb(skb) && skb->len) ++ skb_queue_head(&sk->sk_receive_queue, skb); ++ else ++ kfree_skb(skb); ++ } + } + + static int notify(void *data, int len, int gfp_mask) +@@ -82,8 +95,8 @@ int event_send(u32 tid, u64 sid, u32 cid + + int event_init(void) + { +- nl = netlink_kernel_create(&init_net, NETLINK_IET, 1, event_recv_skb, +- NULL, THIS_MODULE); ++ nl = netlink_kernel_create(NETLINK_IET, 1, event_recv, NULL, ++ THIS_MODULE); + if (!nl) + return -ENOMEM; + else diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.24.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.24.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.24.patch 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.24.patch 2009-04-13 18:56:21.000000000 +0000 @@ -0,0 +1,12 @@ +diff --git a/kernel/event.c b/kernel/event.c +index 240404d..e45ed67 100644 +--- a/kernel/event.c ++++ b/kernel/event.c +@@ -92,5 +92,6 @@ int event_init(void) + + void event_exit(void) + { +- netlink_kernel_release(nl); ++ if (nl) ++ sock_release(nl->sk_socket); + } diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.25-2.6.27.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.25-2.6.27.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.25-2.6.27.patch 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.25-2.6.27.patch 2009-04-13 18:56:21.000000000 +0000 @@ -0,0 +1,33 @@ +diff --git a/kernel/block-io.c b/kernel/block-io.c +index 708f101..e4a25f7 100644 +--- a/kernel/block-io.c ++++ b/kernel/block-io.c +@@ -154,14 +154,14 @@ blockio_open_path(struct iet_volume *volume, const char *path) + { + struct blockio_data *bio_data = volume->private; + struct block_device *bdev; +- int flags = FMODE_READ | (LUReadonly(volume) ? 0 : FMODE_WRITE); ++ int flags = LUReadonly(volume) ? MS_RDONLY : 0; + int err = 0; + + bio_data->path = kstrdup(path, GFP_KERNEL); + if (!bio_data->path) + return -ENOMEM; + +- bdev = open_bdev_exclusive(path, flags, THIS_MODULE); ++ bdev = open_bdev_excl(path, flags, THIS_MODULE); + if (IS_ERR(bdev)) { + err = PTR_ERR(bdev); + eprintk("Can't open device %s, error %d\n", path, err); +@@ -323,10 +323,9 @@ static void + blockio_detach(struct iet_volume *volume) + { + struct blockio_data *bio_data = volume->private; +- int flags = FMODE_READ | (LUReadonly(volume) ? 0 : FMODE_WRITE); + + if (bio_data->bdev) +- close_bdev_exclusive(bio_data->bdev, flags); ++ close_bdev_excl(bio_data->bdev); + kfree(bio_data->path); + + kfree(volume->private); diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.28.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.28.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.28.patch 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.28.patch 2009-04-13 18:56:21.000000000 +0000 @@ -0,0 +1,16 @@ +diff --git a/kernel/conn.c b/kernel/conn.c +index 09b4c0c..a5c0228 100644 +--- a/kernel/conn.c ++++ b/kernel/conn.c +@@ -46,8 +46,9 @@ void conn_info_show(struct seq_file *seq, struct iscsi_session *session) + "%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->daddr)); + break; + case AF_INET6: +- snprintf(buf, sizeof(buf), "[%pI6]", +- &inet6_sk(sk)->daddr); ++ snprintf(buf, sizeof(buf), ++ "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", ++ NIP6(inet6_sk(sk)->daddr)); + break; + default: + break; diff -Nru iscsitarget-0.4.16+svn162/patches/compat-2.6.29.patch iscsitarget-1.4.19+svn275/patches/compat-2.6.29.patch --- iscsitarget-0.4.16+svn162/patches/compat-2.6.29.patch 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-2.6.29.patch 2009-12-09 18:08:56.000000000 +0000 @@ -0,0 +1,13 @@ +diff --git a/kernel/config.c b/kernel/config.c +index 51331fb..9e479c0 100644 +--- a/kernel/config.c ++++ b/kernel/config.c +@@ -43,6 +43,8 @@ int iet_procfs_init(void) + if (!(proc_iet_dir = proc_mkdir("iet", init_net.proc_net))) + goto err; + ++ proc_iet_dir->owner = THIS_MODULE; ++ + for (i = 0; i < ARRAY_SIZE(iet_proc_entries); i++) { + ent = create_proc_entry(iet_proc_entries[i].name, 0, proc_iet_dir); + if (ent) diff -Nru iscsitarget-0.4.16+svn162/patches/compat-rhel4.patch iscsitarget-1.4.19+svn275/patches/compat-rhel4.patch --- iscsitarget-0.4.16+svn162/patches/compat-rhel4.patch 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-rhel4.patch 2009-04-13 18:56:21.000000000 +0000 @@ -1,5 +1,5 @@ ---- kernel/config.c -+++ kernel/config.c +--- 1/kernel/config.c ++++ 2/kernel/config.c @@ -216,7 +216,7 @@ static int add_target(unsigned long ptr) return err; } @@ -17,8 +17,8 @@ - .compat_ioctl = ioctl, + .ioctl = ioctl, }; ---- kernel/event.c -+++ kernel/event.c +--- 1/kernel/event.c ++++ 2/kernel/event.c @@ -71,7 +72,7 @@ static int notify(void *data, int len, i if (!(skb = alloc_skb(NLMSG_SPACE(len), gfp_mask))) return -ENOMEM; diff -Nru iscsitarget-0.4.16+svn162/patches/compat-sles10sp2.patch iscsitarget-1.4.19+svn275/patches/compat-sles10sp2.patch --- iscsitarget-0.4.16+svn162/patches/compat-sles10sp2.patch 1970-01-01 00:00:00.000000000 +0000 +++ iscsitarget-1.4.19+svn275/patches/compat-sles10sp2.patch 2009-04-13 18:56:21.000000000 +0000 @@ -0,0 +1,175 @@ +Index: kernel/iscsi.h +=================================================================== +--- 1/kernel/iscsi.h.p 2008-11-11 12:00:45.000000000 -0500 ++++ 2/kernel/iscsi.h 2008-11-11 12:00:59.000000000 -0500 +@@ -241,8 +241,8 @@ struct iscsi_conn { + u32 write_offset; + int write_state; + +- struct crypto_tfm *rx_digest_tfm; +- struct crypto_tfm *tx_digest_tfm; ++ struct hash_desc rx_hash; ++ struct hash_desc tx_hash; + struct scatterlist hash_sg[ISCSI_CONN_IOV_MAX]; + }; + +Index: kernel/digest.c +=================================================================== +--- 1/kernel/digest.c.p 2008-11-11 12:00:53.000000000 -0500 ++++ 2/kernel/digest.c 2008-11-11 12:01:38.000000000 -0500 +@@ -12,7 +12,8 @@ + + void digest_alg_available(unsigned int *val) + { +- if (*val & DIGEST_CRC32C && !crypto_alg_available("crc32c", 0)) { ++ if (*val & DIGEST_CRC32C && ++ !crypto_has_alg("crc32c", 0, CRYPTO_ALG_ASYNC)) { + printk("CRC32C digest algorithm not available in kernel\n"); + *val |= ~DIGEST_CRC32C; + } +@@ -36,15 +37,22 @@ int digest_init(struct iscsi_conn *conn) + if (!(conn->ddigest_type & DIGEST_ALL)) + conn->ddigest_type = DIGEST_NONE; + +- if (conn->hdigest_type & DIGEST_CRC32C || conn->ddigest_type & DIGEST_CRC32C) { +- conn->rx_digest_tfm = crypto_alloc_tfm("crc32c", 0); +- if (!conn->rx_digest_tfm) { ++ if (conn->hdigest_type & DIGEST_CRC32C || ++ conn->ddigest_type & DIGEST_CRC32C) { ++ conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, ++ CRYPTO_ALG_ASYNC); ++ conn->rx_hash.flags = 0; ++ if (IS_ERR(conn->rx_hash.tfm)) { ++ conn->rx_hash.tfm = NULL; + err = -ENOMEM; + goto out; + } + +- conn->tx_digest_tfm = crypto_alloc_tfm("crc32c", 0); +- if (!conn->tx_digest_tfm) { ++ conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, ++ CRYPTO_ALG_ASYNC); ++ conn->tx_hash.flags = 0; ++ if (IS_ERR(conn->tx_hash.tfm)) { ++ conn->tx_hash.tfm = NULL; + err = -ENOMEM; + goto out; + } +@@ -65,10 +73,10 @@ out: + */ + void digest_cleanup(struct iscsi_conn *conn) + { +- if (conn->tx_digest_tfm) +- crypto_free_tfm(conn->tx_digest_tfm); +- if (conn->rx_digest_tfm) +- crypto_free_tfm(conn->rx_digest_tfm); ++ if (conn->tx_hash.tfm) ++ crypto_free_hash(conn->tx_hash.tfm); ++ if (conn->rx_hash.tfm) ++ crypto_free_hash(conn->rx_hash.tfm); + } + + /** +@@ -159,28 +167,28 @@ static inline void __dbg_simulate_data_d + (sg).length = (l); \ + } while (0) + +-static void digest_header(struct crypto_tfm *tfm, struct iscsi_pdu *pdu, u8 *crc) ++static void digest_header(struct hash_desc *hash, struct iscsi_pdu *pdu, ++ u8 *crc) + { + struct scatterlist sg[2]; +- int i = 0; ++ unsigned int nbytes = sizeof(struct iscsi_hdr); + +- SETSG(sg[i], &pdu->bhs, sizeof(struct iscsi_hdr)); +- i++; ++ SETSG(sg[0], &pdu->bhs, nbytes); + if (pdu->ahssize) { +- SETSG(sg[i], pdu->ahs, pdu->ahssize); +- i++; ++ SETSG(sg[1], pdu->ahs, pdu->ahssize); ++ nbytes += pdu->ahssize; + } + +- crypto_digest_init(tfm); +- crypto_digest_update(tfm, sg, i); +- crypto_digest_final(tfm, crc); ++ crypto_hash_init(hash); ++ crypto_hash_update(hash, sg, nbytes); ++ crypto_hash_final(hash, crc); + } + + int digest_rx_header(struct iscsi_cmnd *cmnd) + { + u32 crc; + +- digest_header(cmnd->conn->rx_digest_tfm, &cmnd->pdu, (u8 *) &crc); ++ digest_header(&cmnd->conn->rx_hash, &cmnd->pdu, (u8 *) &crc); + if (crc != cmnd->hdigest) + return -EIO; + +@@ -189,18 +197,19 @@ int digest_rx_header(struct iscsi_cmnd * + + void digest_tx_header(struct iscsi_cmnd *cmnd) + { +- digest_header(cmnd->conn->tx_digest_tfm, &cmnd->pdu, (u8 *) &cmnd->hdigest); ++ digest_header(&cmnd->conn->tx_hash, &cmnd->pdu, (u8 *) &cmnd->hdigest); + } + +-static void digest_data(struct crypto_tfm *tfm, struct iscsi_cmnd *cmnd, ++static void digest_data(struct hash_desc *hash, struct iscsi_cmnd *cmnd, + struct tio *tio, u32 offset, u8 *crc) + { + struct scatterlist *sg = cmnd->conn->hash_sg; + u32 size, length; + int i, idx, count; ++ unsigned int nbytes; + + size = cmnd->pdu.datasize; +- size = (size + 3) & ~3; ++ nbytes = size = (size + 3) & ~3; + + offset += tio->offset; + idx = offset >> PAGE_CACHE_SHIFT; +@@ -210,7 +219,7 @@ static void digest_data(struct crypto_tf + + assert(count <= ISCSI_CONN_IOV_MAX); + +- crypto_digest_init(tfm); ++ crypto_hash_init(hash); + + for (i = 0; size; i++) { + if (offset + size > PAGE_CACHE_SIZE) +@@ -225,8 +234,8 @@ static void digest_data(struct crypto_tf + offset = 0; + } + +- crypto_digest_update(tfm, sg, count); +- crypto_digest_final(tfm, crc); ++ crypto_hash_update(hash, sg, nbytes); ++ crypto_hash_final(hash, crc); + } + + int digest_rx_data(struct iscsi_cmnd *cmnd) +@@ -252,9 +261,10 @@ int digest_rx_data(struct iscsi_cmnd *cm + offset = 0; + } + +- digest_data(cmnd->conn->rx_digest_tfm, cmnd, tio, offset, (u8 *) &crc); ++ digest_data(&cmnd->conn->rx_hash, cmnd, tio, offset, (u8 *) &crc); + +- if (!cmnd->conn->read_overflow && (cmnd_opcode(cmnd) != ISCSI_OP_PDU_REJECT)) { ++ if (!cmnd->conn->read_overflow && ++ (cmnd_opcode(cmnd) != ISCSI_OP_PDU_REJECT)) { + if (crc != cmnd->ddigest) + return -EIO; + } +@@ -268,6 +278,6 @@ void digest_tx_data(struct iscsi_cmnd *c + struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs; + + assert(tio); +- digest_data(cmnd->conn->tx_digest_tfm, cmnd, tio, ++ digest_data(&cmnd->conn->tx_hash, cmnd, tio, + be32_to_cpu(req->buffer_offset), (u8 *) &cmnd->ddigest); + } Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/chap.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/chap.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/config.h iscsitarget-1.4.19+svn275/usr/config.h --- iscsitarget-0.4.16+svn162/usr/config.h 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/config.h 2009-12-09 18:08:56.000000000 +0000 @@ -2,8 +2,7 @@ #define CONFIG_H struct config_operations { - int (*init) (char *, char **, int *); - int (*default_load) (char *); + void (*init) (char *, char **, int *); int (*target_add) (u32 *, char *); int (*target_stop) (u32); int (*target_del) (u32); @@ -14,7 +13,9 @@ int (*account_add) (u32, int, char *, char *); int (*account_del) (u32, int, char *); int (*account_query) (u32, int, char *, char *); - int (*initiator_access) (u32, int); + int (*account_list) (u32, int, u32 *, u32 *, char *, size_t); + int (*initiator_allow) (u32, int, char *); + int (*target_allow) (u32, struct sockaddr *); }; extern struct config_operations *cops; diff -Nru iscsitarget-0.4.16+svn162/usr/conn.c iscsitarget-1.4.19+svn275/usr/conn.c --- iscsitarget-0.4.16+svn162/usr/conn.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/conn.c 2009-04-13 18:56:22.000000000 +0000 @@ -27,6 +27,7 @@ memset(conn, 0, sizeof(*conn)); conn->state = STATE_FREE; param_set_defaults(conn->session_param, session_keys); + INIT_LIST_HEAD(&conn->rsp_buf_list); return conn; } @@ -132,6 +133,19 @@ conn->rwsize = BHS_SIZE; } +void conn_free_rsp_buf_list(struct connection *conn) +{ + struct buf_segment *seg, *tmp; + + list_for_each_entry_safe(seg, tmp, &conn->rsp_buf_list, entry) { + list_del(&seg->entry); + free(seg); + } + + conn->rsp.datasize = 0; + conn->rsp.data = NULL; +} + void conn_free_pdu(struct connection *conn) { conn->iostate = IOSTATE_FREE; @@ -143,8 +157,5 @@ free(conn->rsp.ahs); conn->rsp.ahs = NULL; } - if (conn->rsp.data) { - free(conn->rsp.data); - conn->rsp.data = NULL; - } + conn_free_rsp_buf_list(conn); } Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/conn.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/conn.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/ctldev.c iscsitarget-1.4.19+svn275/usr/ctldev.c --- iscsitarget-0.4.16+svn162/usr/ctldev.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/ctldev.c 2009-12-09 18:08:56.000000000 +0000 @@ -84,7 +84,7 @@ memset(&info, 0, sizeof(info)); - memcpy(info.name, name, sizeof(info.name) - 1); + snprintf(info.name, sizeof(info.name), "%s", name); info.tid = *tid; if ((err = ioctl(ctrl_fd, ADD_TARGET, &info)) < 0) log_warning("can't create a target %d %u\n", errno, info.tid); Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/ctldev.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/ctldev.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/event.c iscsitarget-1.4.19+svn275/usr/event.c --- iscsitarget-0.4.16+svn162/usr/event.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/event.c 2009-12-09 18:08:56.000000000 +0000 @@ -25,7 +25,7 @@ { struct iovec iov[2]; struct msghdr msg; - struct nlmsghdr nlh; + struct nlmsghdr nlh = {0}; iov[0].iov_base = &nlh; iov[0].iov_len = sizeof(nlh); @@ -82,13 +82,13 @@ exit(1); } - log_debug(1, "conn %u session %#" PRIx64 " target %u, state %u", + log_debug(1, "conn %u session %llu target %u, state %u", event.cid, event.sid, event.tid, event.state); switch (event.state) { case E_CONN_CLOSE: if (!(session = session_find_id(event.tid, event.sid))) { - log_warning("session %#" PRIx64 " not found?", event.sid); + log_warning("session %llu not found?", event.sid); goto retry; } Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/event.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/event.o differ Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/ietadm and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/ietadm differ diff -Nru iscsitarget-0.4.16+svn162/usr/ietadm.c iscsitarget-1.4.19+svn275/usr/ietadm.c --- iscsitarget-0.4.16+svn162/usr/ietadm.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/ietadm.c 2009-04-13 18:56:22.000000000 +0000 @@ -29,6 +29,8 @@ #define SET_LUNIT (1 << 3) #define SET_USER (1 << 4) +typedef int (user_handle_fn_t)(struct ietadm_req *req, char *user, char *pass); + enum ietadm_op { OP_NEW, OP_DELETE, @@ -72,6 +74,14 @@ show iSCSI parameters in effect for session [sid]. If\n\ [sid] is \"0\" (zero), the configured parameters\n\ will be displayed.\n\ + --op show --tid=[id] --user\n\ + show list of Discovery (--tid omitted / id=0 (zero))\n\ + or target CHAP accounts.\n\ + --op show --tid=[id] --user --params=[user]=[name]\n\ + show CHAP account information. [user] can be\n\ + \"IncomingUser\" or \"OutgoingUser\". If --tid is\n\ + omitted / id=0 (zero), [user] is treated as Discovery\n\ + user.\n\ --op new --tid=[id] --lun=[lun] --params Path=[path]\n\ add a new logical unit with [lun] to specific\n\ target with [id]. The logical unit is offered\n\ @@ -142,7 +152,8 @@ return err; } -static int ietd_response_recv(int fd, struct ietadm_req *req) +static int ietd_response_recv(int fd, struct ietadm_req *req, void *rsp_data, + size_t rsp_data_sz) { int err, ret; struct iovec iov[2]; @@ -161,6 +172,15 @@ } else err = rsp.err; + if (!err && rsp_data_sz && rsp_data) { + ret = read(fd, rsp_data, rsp_data_sz); + if (ret != rsp_data_sz) { + err = (ret < 0) ? -errno : -EIO; + fprintf(stderr, "%s %d %d %d\n", __FUNCTION__, + __LINE__, ret, err); + } + } + return err; } @@ -183,7 +203,8 @@ return fd; } -static int ietd_request(struct ietadm_req *req) +static int ietd_request(struct ietadm_req *req, void *rsp_data, + size_t rsp_data_sz) { int fd = -1, err = -EIO; @@ -195,7 +216,7 @@ if ((err = ietd_request_send(fd, req)) < 0) goto out; - err = ietd_response_recv(fd, req); + err = ietd_response_recv(fd, req, rsp_data, rsp_data_sz); out: if (fd > 0) @@ -318,7 +339,7 @@ break; } - err = ietd_request(&req); + err = ietd_request(&req, NULL, 0); if (!err && req.rcmnd == C_TRGT_SHOW) show_iscsi_param(key_target, req.u.trgt.target_param); @@ -357,7 +378,7 @@ break; } - err = ietd_request(&req); + err = ietd_request(&req, NULL, 0); out: return err; } @@ -385,7 +406,7 @@ break; case OP_SHOW: req.rcmnd = C_SESS_SHOW; - err = ietd_request(&req); + err = ietd_request(&req, NULL, 0); if (!err) show_iscsi_param(key_session, req.u.trgt.session_param); break; @@ -395,30 +416,10 @@ return err; } -static int user_handle(int op, u32 set, u32 tid, char *params) +static int parse_user_params(char *params, u32 *auth_dir, char **user, + char **pass) { - int err = -EINVAL; - char *p, *q, *user = NULL, *pass = NULL; - struct ietadm_req req; - - if (set & ~(SET_TARGET | SET_USER)) - goto out; - - memset(&req, 0, sizeof(req)); - req.tid = tid; - - switch (op) { - case OP_NEW: - req.rcmnd = C_ACCT_NEW; - break; - case OP_DELETE: - req.rcmnd = C_ACCT_DEL; - break; - case OP_UPDATE: - case OP_SHOW: - fprintf(stderr, "Unsupported.\n"); - goto out; - } + char *p, *q; while ((p = strsep(¶ms, ",")) != NULL) { if (!*p) @@ -431,37 +432,187 @@ q++; if (!strcasecmp(p, "IncomingUser")) { - if (user) - fprintf(stderr, "Already specified user %s\n", q); - user = q; - req.u.acnt.auth_dir = AUTH_DIR_INCOMING; + if (*user) + fprintf(stderr, + "Already specified IncomingUser %s\n", + q); + *user = q; + *auth_dir = AUTH_DIR_INCOMING; } else if (!strcasecmp(p, "OutgoingUser")) { - if (user) - fprintf(stderr, "Already specified user %s\n", q); - user = q; - req.u.acnt.auth_dir = AUTH_DIR_OUTGOING; + if (*user) + fprintf(stderr, + "Already specified OutgoingUser %s\n", + q); + *user = q; + *auth_dir = AUTH_DIR_OUTGOING; } else if (!strcasecmp(p, "Password")) { - if (pass) - fprintf(stderr, "Already specified pass %s\n", q); - pass = q; + if (*pass) + fprintf(stderr, + "Already specified Password %s\n", q); + *pass = q; } else { fprintf(stderr, "Unknown parameter %p\n", q); - goto out; + return -EINVAL; } } + return 0; +} - if ((op == OP_NEW && ((user && !pass) || (!user && pass) || (!user && !pass))) || - (op == OP_DELETE && ((!user && pass) || (!user && !pass)))) { - fprintf(stderr, - "You need to specify a user and its password %s %s\n", pass, user); - goto out; +static void show_account(int auth_dir, char *user, char *pass) +{ + char buf[(ISCSI_NAME_LEN + 1) * 2] = {0}; + + snprintf(buf, ISCSI_NAME_LEN, "%s", user); + if (pass) + snprintf(buf + strlen(buf), ISCSI_NAME_LEN, " %s", pass); + + printf("%sUser %s\n", (auth_dir == AUTH_DIR_INCOMING) ? + "Incoming" : "Outgoing", buf); +} + +static int user_handle_show_user(struct ietadm_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); + + err = ietd_request(req, NULL, 0); + if (!err) + show_account(req->u.acnt.auth_dir, req->u.acnt.u.user.name, + req->u.acnt.u.user.pass); + + return err; +} + +static int user_handle_show_list(struct ietadm_req *req) +{ + int i, err, retry; + size_t buf_sz = 0; + char *buf; + + req->u.acnt.auth_dir = AUTH_DIR_INCOMING; + req->rcmnd = C_ACCT_LIST; + + do { + retry = 0; + + buf_sz = buf_sz ? buf_sz : ISCSI_NAME_LEN; + + buf = calloc(buf_sz, sizeof(char *)); + if (!buf) { + fprintf(stderr, "Memory allocation failed\n"); + return -ENOMEM; + } + + req->u.acnt.u.list.alloc_len = buf_sz; + + err = ietd_request(req, buf, buf_sz); + if (err) { + free(buf); + break; + } + + if (req->u.acnt.u.list.overflow) { + buf_sz = ISCSI_NAME_LEN * (req->u.acnt.u.list.count + + req->u.acnt.u.list.overflow); + retry = 1; + free(buf); + continue; + } + + for (i = 0; i < req->u.acnt.u.list.count; i++) + 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; + buf_sz = 0; + retry = 1; + } + + free(buf); + + } while (retry); + + return err; +} + +static int user_handle_show(struct ietadm_req *req, char *user, char *pass) +{ + if (pass) + fprintf(stderr, "Ignoring specified password\n"); + + if (user) + return user_handle_show_user(req, user); + else + return user_handle_show_list(req); +} + +static int user_handle_new(struct ietadm_req *req, char *user, char *pass) +{ + if (!user || !pass) { + fprintf(stderr, "Username and password must be specified\n"); + return -EINVAL; } - strncpy(req.u.acnt.user, user, sizeof(req.u.acnt.user) - 1); + 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); + + return ietd_request(req, NULL, 0); +} + +static int user_handle_del(struct ietadm_req *req, char *user, char *pass) +{ + if (!user) { + fprintf(stderr, "Username must be specified\n"); + return -EINVAL; + } if (pass) - strncpy(req.u.acnt.pass, pass, sizeof(req.u.acnt.pass) - 1); + fprintf(stderr, "Ignoring specified password\n"); + + req->rcmnd = C_ACCT_DEL; + + strncpy(req->u.acnt.u.user.name, user, + sizeof(req->u.acnt.u.user.name) - 1); + + return ietd_request(req, NULL, 0); +} + +static int user_handle(int op, u32 set, u32 tid, char *params) +{ + int err = -EINVAL; + char *user = NULL, *pass = NULL; + struct ietadm_req req; + static user_handle_fn_t *user_handle_fn[] = { + user_handle_new, + user_handle_del, + NULL, + user_handle_show, + }, *fn; + + if (set & ~(SET_TARGET | SET_USER)) + goto out; + + memset(&req, 0, sizeof(req)); + req.tid = tid; + + err = parse_user_params(params, &req.u.acnt.auth_dir, &user, &pass); + if (err) + goto out; + + fn = user_handle_fn[op]; + if (!fn) { + fprintf(stderr, "Unsupported\n"); + goto out; + } - err = ietd_request(&req); + err = fn(&req, user, pass); out: return err; } @@ -494,7 +645,7 @@ break; } - err = ietd_request(&req); + err = ietd_request(&req, NULL, 0); out: return err; } @@ -518,7 +669,7 @@ break; } - err = ietd_request(&req); + err = ietd_request(&req, NULL, 0); return err; } diff -Nru iscsitarget-0.4.16+svn162/usr/ietadm.h iscsitarget-1.4.19+svn275/usr/ietadm.h --- iscsitarget-0.4.16+svn162/usr/ietadm.h 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/ietadm.h 2009-04-13 18:56:22.000000000 +0000 @@ -16,8 +16,17 @@ struct msg_acnt { u32 auth_dir; - char user[ISCSI_NAME_LEN]; - char pass[ISCSI_NAME_LEN]; + union { + struct { + char name[ISCSI_NAME_LEN]; + char pass[ISCSI_NAME_LEN]; + } user; + struct { + u32 alloc_len; + u32 count; + u32 overflow; + } list; + } u; }; struct msg_lunit { @@ -54,6 +63,8 @@ C_SYS_DEL, C_SYS_UPDATE, C_SYS_SHOW, + + C_ACCT_LIST, }; struct ietadm_req { Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/ietadm.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/ietadm.o differ Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/ietd and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/ietd differ diff -Nru iscsitarget-0.4.16+svn162/usr/ietd.c iscsitarget-1.4.19+svn275/usr/ietd.c --- iscsitarget-0.4.16+svn162/usr/ietd.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/ietd.c 2009-12-09 18:08:56.000000000 +0000 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -28,24 +29,10 @@ #include "iscsid.h" #include "ietadm.h" -#define LISTEN_MAX 8 -#define INCOMING_MAX 32 - -enum { - POLL_LISTEN, - POLL_IPC = POLL_LISTEN + LISTEN_MAX, - POLL_NL, - POLL_ISNS, - POLL_SCN_LISTEN, - POLL_SCN, - POLL_INCOMING, - POLL_MAX = POLL_INCOMING + INCOMING_MAX, -}; - static char* server_address; uint16_t server_port = ISCSI_LISTEN_PORT; -static struct pollfd poll_array[POLL_MAX]; +struct pollfd poll_array[POLL_MAX]; static struct connection *incoming[INCOMING_MAX]; static int incoming_cnt; int ctrl_fd, ipc_fd, nl_fd; @@ -66,7 +53,7 @@ {0, 0, 0, 0}, }; -/* This will be comfigurable by command line options */ +/* This will be configurable by command line options */ extern struct config_operations plain_ops; struct config_operations *cops = &plain_ops; @@ -118,7 +105,9 @@ hints.ai_flags = AI_PASSIVE; if (getaddrinfo(server_address, servname, &hints, &res0)) { - log_error("unable to get address info (%s)!", strerror(errno)); + log_error("unable to get address info (%s)!", + (errno == EAI_SYSTEM) ? strerror(errno) : + gai_strerror(errno)); exit(1); } @@ -135,10 +124,12 @@ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt))) log_warning("unable to set SO_KEEPALIVE on server socket (%s)!", strerror(errno)); + opt = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) log_warning("unable to set SO_REUSEADDR on server socket (%s)!", strerror(errno)); + opt = 1; if (res->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))) @@ -413,13 +404,16 @@ conn_close: if (conn->state == STATE_CLOSE) { - log_debug(0, "connection closed"); + struct session *session = conn->session; + log_debug(1, "connection closed"); conn_free_pdu(conn); conn_free(conn); close(pollfd->fd); pollfd->fd = -1; incoming[i] = NULL; incoming_cnt--; + if (session && !session->conn_cnt) + session_remove(session); } } } @@ -434,6 +428,10 @@ char *isns = NULL; int isns_ac = 0; + /* otherwise we would die in some later write() during the event_loop + * instead of getting EPIPE! */ + signal(SIGPIPE, SIG_IGN); + while ((ch = getopt_long(argc, argv, "c:fd:s:u:g:a:p:vh", long_options, &longindex)) >= 0) { switch (ch) { case 'c': @@ -503,14 +501,25 @@ } else if (pid) exit(0); - chdir("/"); + if (chdir("/") < 0) { + log_error("failed to set working dir to /: %m"); + exit(1); + } + if (lockf(fd, F_TLOCK, 0) < 0) { log_error("unable to lock pid file"); exit(1); } - ftruncate(fd, 0); + if (ftruncate(fd, 0) < 0) { + log_error("failed to ftruncate the PID file: %m"); + exit(1); + } + sprintf(buf, "%d\n", getpid()); - write(fd, buf, strlen(buf)); + if (write(fd, buf, strlen(buf)) < strlen(buf)) { + log_error("failed to write PID to PID file: %m"); + exit(1); + } close(0); open("/dev/null", O_RDWR); @@ -523,8 +532,6 @@ if (isns) timeout = isns_init(isns, isns_ac); - cops->default_load(config); - if (gid && setgid(gid) < 0) perror("setgid"); Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/ietd.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/ietd.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/iscsi_hdr.h iscsitarget-1.4.19+svn275/usr/iscsi_hdr.h --- iscsitarget-0.4.16+svn162/usr/iscsi_hdr.h 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/iscsi_hdr.h 2009-12-09 18:08:56.000000000 +0000 @@ -32,7 +32,7 @@ #define ISCSI_OPCODE_MASK 0x3F /* Client to Server Message Opcode values */ -#define ISCSI_OP_NOOP_OUT 0x00 +#define ISCSI_OP_NOP_OUT 0x00 #define ISCSI_OP_SCSI_CMD 0x01 #define ISCSI_OP_SCSI_TASK_MGT_MSG 0x02 #define ISCSI_OP_LOGIN_CMD 0x03 @@ -42,7 +42,7 @@ #define ISCSI_OP_SNACK_CMD 0x10 /* Server to Client Message Opcode values */ -#define ISCSI_OP_NOOP_IN 0x20 +#define ISCSI_OP_NOP_IN 0x20 #define ISCSI_OP_SCSI_RSP 0x21 #define ISCSI_OP_SCSI_TASK_MGT_RSP 0x22 #define ISCSI_OP_LOGIN_RSP 0x23 @@ -132,6 +132,7 @@ u8 rsvd2[10]; } __packed; +#define ISCSI_FLG_CONTINUE 0x40 #define ISCSI_FLG_FINAL 0x80 #define ISCSI_FLG_TRANSIT 0x80 #define ISCSI_FLG_CSG_SECURITY 0x00 @@ -176,6 +177,8 @@ #define ISCSI_STATUS_SVC_UNAVAILABLE 0x01 #define ISCSI_STATUS_NO_RESOURCES 0x02 +#define ISCSI_RESERVED_TAG 0xffffffff + struct iscsi_logout_req_hdr { u8 opcode; u8 flags; @@ -210,4 +213,34 @@ u32 rsvd5; } __packed; +#define ISCSI_REASON_NO_FULL_FEATURE_PHASE 0x01 +#define ISCSI_REASON_DATA_DIGEST_ERROR 0x02 +#define ISCSI_REASON_DATA_SNACK_REJECT 0x03 +#define ISCSI_REASON_PROTOCOL_ERROR 0x04 +#define ISCSI_REASON_UNSUPPORTED_COMMAND 0x05 +#define ISCSI_REASON_IMMEDIATE_COMMAND_REJECT 0x06 +#define ISCSI_REASON_TASK_IN_PROGRESS 0x07 +#define ISCSI_REASON_INVALID_SNACK 0x08 +#define ISCSI_REASON_INVALID_PDU_FIELD 0x09 +#define ISCSI_REASON_BOOKMARK_REJECT 0x0a +#define ISCSI_REASON_NEGOTIATION_RESET 0x0b +#define ISCSI_REASON_WAITING_LOGOUT 0x0c + +struct iscsi_reject_hdr { + u8 opcode; + u8 flags; + u8 reason; + u8 rsvd1; + u8 ahslength; + u8 datalength[3]; + u32 rsvd2[2]; + u32 ffffffff; + u32 rsvd3; + u32 stat_sn; + u32 exp_cmd_sn; + u32 max_cmd_sn; + u32 data_sn; + u32 rsvd4[2]; +} __packed; + #endif /* ISCSI_HDR_H */ diff -Nru iscsitarget-0.4.16+svn162/usr/iscsid.c iscsitarget-1.4.19+svn275/usr/iscsid.c --- iscsitarget-0.4.16+svn162/usr/iscsid.c 2007-12-28 21:29:47.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/iscsid.c 2009-12-09 18:08:56.000000000 +0000 @@ -16,6 +16,14 @@ #include "iscsid.h" +static u32 ttt; + +static u32 get_next_ttt(struct connection *conn __attribute__((unused))) +{ + ttt += 1; + return (ttt == ISCSI_RESERVED_TAG) ? ++ttt : ttt; +} + static struct iscsi_key login_keys[] = { {"InitiatorName",}, {"InitiatorAlias",}, @@ -81,36 +89,91 @@ return key; } +static struct buf_segment * conn_alloc_buf_segment(struct connection *conn, + size_t sz) +{ + struct buf_segment *seg = malloc(sizeof *seg + sz); + + if (seg) { + seg->len = 0; + memset(seg->data, 0x0, sz); + list_add_tail(&seg->entry, &conn->rsp_buf_list); + log_debug(2, "alloc'ed new buf_segment"); + } + + return seg; +} + + void text_key_add(struct connection *conn, char *key, char *value) { + struct buf_segment *seg; int keylen = strlen(key); int valuelen = strlen(value); int len = keylen + valuelen + 2; - char *buffer; - - if (!conn->rsp.datasize) { - if (!conn->rsp_buffer) { - conn->rsp_buffer = malloc(INCOMING_BUFSIZE); - if (!conn->rsp_buffer) { - log_error("Failed to alloc send buffer"); - return; + int off = 0; + int sz = 0; + int stage = 0; + size_t data_sz; + + data_sz = (conn->state == STATE_FULL) ? + conn->session_param[key_max_xmit_data_length].val : + INCOMING_BUFSIZE; + + seg = list_empty(&conn->rsp_buf_list) ? NULL : + list_entry(conn->rsp_buf_list.q_back, struct buf_segment, + entry); + + while (len) { + if (!seg || seg->len == data_sz) { + seg = conn_alloc_buf_segment(conn, data_sz); + if (!seg) { + log_error("Failed to alloc text buf segment\n"); + conn_free_rsp_buf_list(conn); + break; } } - conn->rsp.data = conn->rsp_buffer; - } - if (conn->rsp.datasize + len > INCOMING_BUFSIZE) { - log_warning("Dropping key (%s=%s)", key, value); - return; - } + switch (stage) { + case 0: + sz = min_t(int, data_sz - seg->len, keylen - off); + strncpy(seg->data + seg->len, key + off, sz); + if (sz == data_sz - seg->len) { + off += sz; + if (keylen - off == 0) { + off = 0; + stage++; + } + } else { + off = 0; + stage++; + } + break; + case 1: + seg->data[seg->len] = '='; + off = 0; + sz = 1; + stage++; + break; + case 2: + sz = min_t(int, data_sz - seg->len, valuelen - off); + strncpy(seg->data + seg->len, value + off, sz); + off += sz; + if (valuelen - off == 0) { + off = 0; + stage++; + } + break; + case 3: + seg->data[seg->len] = 0; + sz = 1; + break; + } + + log_debug(1, "wrote: %s", seg->data + seg->len); - buffer = conn->rsp_buffer; - buffer += conn->rsp.datasize; - conn->rsp.datasize += len; - - strcpy(buffer, key); - buffer += keylen; - *buffer++ = '='; - strcpy(buffer, value); + seg->len += sz; + len -= sz; + } } static void text_key_add_reject(struct connection *conn, char *key) @@ -323,26 +386,36 @@ return cnt; } +static void login_rsp_ini_err(struct connection *conn, int status_detail) +{ + struct iscsi_login_rsp_hdr * const rsp = + (struct iscsi_login_rsp_hdr * const)&conn->rsp.bhs; + + rsp->status_class = ISCSI_STATUS_INITIATOR_ERR; + rsp->status_detail = status_detail; + conn->state = STATE_EXIT; +} + static void login_start(struct connection *conn) { struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs; - struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs; + char *name, *alias, *session_type, *target_name; + struct sockaddr_storage ss; + socklen_t slen = sizeof(struct sockaddr_storage); + + memset(&ss, 0, sizeof(ss)); conn->cid = be16_to_cpu(req->cid); conn->sid.id64 = req->sid.id64; if (!conn->sid.id64) { - rsp->status_class = ISCSI_STATUS_INITIATOR_ERR; - rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS; - conn->state = STATE_EXIT; + login_rsp_ini_err(conn, ISCSI_STATUS_MISSING_FIELDS); return; } name = text_key_find(conn, "InitiatorName"); if (!name) { - rsp->status_class = ISCSI_STATUS_INITIATOR_ERR; - rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS; - conn->state = STATE_EXIT; + login_rsp_ini_err(conn, ISCSI_STATUS_MISSING_FIELDS); return; } conn->initiator = strdup(name); @@ -353,49 +426,48 @@ conn->auth_method = -1; conn->session_type = SESSION_NORMAL; + getsockname(conn->fd, (struct sockaddr *) &ss, &slen); + if (session_type) { if (!strcmp(session_type, "Discovery")) conn->session_type = SESSION_DISCOVERY; 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; + login_rsp_ini_err(conn, ISCSI_STATUS_INV_SESSION_TYPE); return; } } if (conn->session_type == SESSION_NORMAL) { if (!target_name) { - rsp->status_class = ISCSI_STATUS_INITIATOR_ERR; - rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS; - conn->state = STATE_EXIT; + login_rsp_ini_err(conn, ISCSI_STATUS_MISSING_FIELDS); return; } - if (!(conn->tid = target_find_by_name(target_name)) || - cops->initiator_access(conn->tid, conn->fd) || - isns_scn_access(conn->tid, conn->fd, name)) { - rsp->status_class = ISCSI_STATUS_INITIATOR_ERR; - rsp->status_detail = ISCSI_STATUS_TGT_NOT_FOUND; - conn->state = STATE_EXIT; + struct target * const target = + target_find_by_name(target_name); + + if (!target + || !cops->initiator_allow(target->tid, conn->fd, name) + || !cops->target_allow(target->tid, (struct sockaddr *) &ss) + || !isns_scn_allow(target->tid, name)) { + login_rsp_ini_err(conn, ISCSI_STATUS_TGT_NOT_FOUND); return; } -/* if (conn->target->max_sessions && */ -/* (++conn->target->session_cnt > conn->target->max_sessions)) { */ -/* conn->target->session_cnt--; */ -/* rsp->status_class = ISCSI_STATUS_INITIATOR_ERR; */ -/* rsp->status_detail = ISCSI_STATUS_TOO_MANY_CONN; */ -/* conn->state = STATE_EXIT; */ -/* return; */ -/* } */ + conn->tid = target->tid; - if (ki->param_get(conn->tid, 0, key_session, - conn->session_param)) { - rsp->status_class = ISCSI_STATUS_TARGET_ERROR; - rsp->status_detail = ISCSI_STATUS_SVC_UNAVAILABLE; - conn->state = STATE_EXIT; + if (target->max_nr_sessions && + (++target->nr_sessions > target->max_nr_sessions)) { + --target->nr_sessions; + log_debug(1, "rejecting session for target '%s': " + "too many sessions", target_name); + login_rsp_ini_err(conn, ISCSI_STATUS_TOO_MANY_CONN); + return; } + + if (ki->param_get(conn->tid, 0, key_session, + conn->session_param)) + login_rsp_ini_err(conn, ISCSI_STATUS_SVC_UNAVAILABLE); } conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn); log_debug(1, "exp_cmd_sn: %d,%d", conn->exp_cmd_sn, req->cmd_sn); @@ -417,6 +489,36 @@ } } +static void cmnd_reject(struct connection *conn, u8 reason) +{ + struct iscsi_reject_hdr *rej = + (struct iscsi_reject_hdr *)&conn->rsp.bhs; + size_t data_sz = sizeof(struct iscsi_hdr); + struct buf_segment *seg; + + conn_free_rsp_buf_list(conn); + seg = conn_alloc_buf_segment(conn, data_sz); + + memset(rej, 0x0, sizeof *rej); + rej->opcode = ISCSI_OP_REJECT_MSG; + rej->reason = reason; + rej->ffffffff = ISCSI_RESERVED_TAG; + rej->flags |= ISCSI_FLG_FINAL; + + rej->stat_sn = cpu_to_be32(conn->stat_sn++); + rej->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn); + conn->max_cmd_sn = conn->exp_cmd_sn + 1; + rej->max_cmd_sn = cpu_to_be32(conn->max_cmd_sn); + + if (!seg) { + log_error("Failed to alloc data segment for Reject PDU\n"); + return; + } + + memcpy(seg->data, &conn->req.bhs, data_sz); + seg->len = data_sz; +} + static int cmnd_exec_auth(struct connection *conn) { int res; @@ -445,7 +547,8 @@ memset(rsp, 0, BHS_SIZE); if ((req->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD || !(req->opcode & ISCSI_OP_IMMEDIATE)) { - //reject + cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR); + return; } rsp->opcode = ISCSI_OP_LOGIN_RSP; @@ -579,6 +682,17 @@ rsp->flags |= nsg | (stay ? 0 : ISCSI_FLG_TRANSIT); } + /* + * TODO: support Logical Text Data Segments > INCOMING_BUFSIZE (i.e. + * key=value pairs spanning several PDUs) during login phase + */ + if (!list_empty(&conn->rsp_buf_list) && + !list_length_is_one(&conn->rsp_buf_list)) { + log_error("Target error: \'key=value\' pairs spanning several " + "Login PDUs are not implemented, yet\n"); + goto target_err; + } + rsp->sid = conn->sid; rsp->stat_sn = cpu_to_be32(conn->stat_sn++); rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn); @@ -597,6 +711,12 @@ rsp->status_detail = ISCSI_STATUS_AUTH_FAILED; conn->state = STATE_EXIT; return; + target_err: + rsp->flags = 0; + rsp->status_class = ISCSI_STATUS_TARGET_ERR; + rsp->status_detail = ISCSI_STATUS_TARGET_ERROR; + conn->state = STATE_EXIT; + return; } static void text_scan_text(struct connection *conn) @@ -609,34 +729,10 @@ while ((key = next_key(&data, &datasize, &value))) { if (!strcmp(key, "SendTargets")) { - struct sockaddr_storage ss; - socklen_t slen, blen; - char *p, buf[NI_MAXHOST + 128]; - if (value[0] == 0) continue; - p = buf; - blen = sizeof(buf); - - slen = sizeof(ss); - getsockname(conn->fd, (struct sockaddr *) &ss, &slen); - if (ss.ss_family == AF_INET6) { - *p++ = '['; - blen--; - } - - slen = sizeof(ss); - getnameinfo((struct sockaddr *) &ss, slen, p, blen, - NULL, 0, NI_NUMERICHOST); - - p = buf + strlen(buf); - - if (ss.ss_family == AF_INET6) - *p++ = ']'; - - sprintf(p, ":%d,1", server_port); - target_list_build(conn, buf, + target_list_build(conn, strcmp(value, "All") ? value : NULL); } else text_key_add(conn, key, "NotUnderstood"); @@ -650,23 +746,37 @@ memset(rsp, 0, BHS_SIZE); - if (be32_to_cpu(req->ttt) != 0xffffffff) { - /* reject */; - } rsp->opcode = ISCSI_OP_TEXT_RSP; rsp->itt = req->itt; - //rsp->ttt = rsp->ttt; - rsp->ttt = 0xffffffff; conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn); if (!(req->opcode & ISCSI_OP_IMMEDIATE)) conn->exp_cmd_sn++; log_debug(1, "Text request: %d", conn->state); - text_scan_text(conn); - if (req->flags & ISCSI_FLG_FINAL) + if (req->ttt == ISCSI_RESERVED_TAG) { + conn_free_rsp_buf_list(conn); + text_scan_text(conn); + if (!list_empty(&conn->rsp_buf_list) && + !list_length_is_one(&conn->rsp_buf_list)) + conn->ttt = get_next_ttt(conn); + else + conn->ttt = ISCSI_RESERVED_TAG; + } else if (list_empty(&conn->rsp_buf_list) || conn->ttt != req->ttt) { + log_error("Rejecting unexpected text request. TTT recv %#x, " + "expected %#x; %stext segments queued\n", + req->ttt, conn->ttt, list_empty(&conn->rsp_buf_list) ? + "no " : ""); + cmnd_reject(conn, ISCSI_REASON_INVALID_PDU_FIELD); + return; + } + + if (list_empty(&conn->rsp_buf_list) || + list_length_is_one(&conn->rsp_buf_list)) rsp->flags = ISCSI_FLG_FINAL; + rsp->ttt = conn->ttt; + rsp->stat_sn = cpu_to_be32(conn->stat_sn++); rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn); conn->max_cmd_sn = conn->exp_cmd_sn + 1; @@ -694,47 +804,68 @@ int cmnd_execute(struct connection *conn) { - int res = 1; + struct buf_segment *seg; + struct iscsi_login_rsp_hdr *login_rsp; switch (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) { case ISCSI_OP_LOGIN_CMD: - //if conn->state == STATE_FULL -> reject + if (conn->state == STATE_FULL) { + cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR); + break; + } cmnd_exec_login(conn); - conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4; - conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16; - conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8; - conn->rsp.bhs.datalength[2] = conn->rsp.datasize; - log_pdu(2, &conn->rsp); + login_rsp = (struct iscsi_login_rsp_hdr *) &conn->rsp.bhs; + if (login_rsp->status_class) + conn_free_rsp_buf_list(conn); break; case ISCSI_OP_TEXT_CMD: - //if conn->state != STATE_FULL -> reject - cmnd_exec_text(conn); - conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4; - conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16; - conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8; - conn->rsp.bhs.datalength[2] = conn->rsp.datasize; - log_pdu(2, &conn->rsp); + if (conn->state != STATE_FULL) + cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR); + else + cmnd_exec_text(conn); break; case ISCSI_OP_LOGOUT_CMD: - //if conn->state != STATE_FULL -> reject - cmnd_exec_logout(conn); - conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4; - conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16; - conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8; - conn->rsp.bhs.datalength[2] = conn->rsp.datasize; - log_pdu(2, &conn->rsp); + if (conn->state != STATE_FULL) + cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR); + else + cmnd_exec_logout(conn); break; default: - //reject - res = 0; - break; + cmnd_reject(conn, ISCSI_REASON_UNSUPPORTED_COMMAND); + return 0; } - return res; + if (!list_empty(&conn->rsp_buf_list)) { + seg = list_entry(conn->rsp_buf_list.q_forw, + struct buf_segment, entry); + list_del_init(&seg->entry); + conn->rsp.datasize = seg->len; + conn->rsp.data = seg->data; + } else { + conn->rsp.datasize = 0; + conn->rsp.data = NULL; + } + + conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4; + conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16; + conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8; + conn->rsp.bhs.datalength[2] = conn->rsp.datasize; + log_pdu(2, &conn->rsp); + + return 1; } void cmnd_finish(struct connection *conn) { + struct buf_segment *seg; + + if (conn->rsp.data) { + seg = container_of(conn->rsp.data, struct buf_segment, data); + list_del(&seg->entry); + free(seg); + conn->rsp.data = NULL; + } + switch (conn->state) { case STATE_EXIT: conn->state = STATE_CLOSE; diff -Nru iscsitarget-0.4.16+svn162/usr/iscsid.h iscsitarget-1.4.19+svn275/usr/iscsid.h --- iscsitarget-0.4.16+svn162/usr/iscsid.h 2008-06-29 21:49:49.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/iscsid.h 2009-12-09 18:08:56.000000000 +0000 @@ -8,6 +8,7 @@ #define ISCSID_H #include +#include #include #include "types.h" @@ -19,6 +20,13 @@ #define PROC_SESSION "/proc/net/iet/session" +struct buf_segment { + struct __qelem entry; + + unsigned int len; + char data[0]; +}; + struct PDU { struct iscsi_hdr bhs; void *ahs; @@ -54,7 +62,7 @@ char *initiator; union iscsi_sid sid; u16 cid; - u16 pad; + int session_type; int auth_method; @@ -64,11 +72,13 @@ u32 cmd_sn; u32 exp_cmd_sn; u32 max_cmd_sn; + u32 ttt; struct PDU req; void *req_buffer; struct PDU rsp; - void *rsp_buffer; + struct __qelem rsp_buf_list; + unsigned char *buffer; int rwsize; @@ -121,6 +131,20 @@ #define INCOMING_BUFSIZE 8192 +#define LISTEN_MAX 8 +#define INCOMING_MAX 32 + +enum { + POLL_LISTEN, + POLL_IPC = POLL_LISTEN + LISTEN_MAX, + POLL_NL, + POLL_ISNS, + POLL_SCN_LISTEN, + POLL_SCN, + POLL_INCOMING, + POLL_MAX = POLL_INCOMING + INCOMING_MAX, +}; + struct target { struct __qelem tlist; @@ -147,6 +171,7 @@ extern void conn_read_pdu(struct connection *conn); extern void conn_write_pdu(struct connection *conn); extern void conn_free_pdu(struct connection *conn); +extern void conn_free_rsp_buf_list(struct connection *conn); /* ietd.c */ extern uint16_t server_port; @@ -183,9 +208,9 @@ extern struct __qelem targets_list; extern int target_add(u32 *, char *); extern int target_del(u32); -extern u32 target_find_by_name(const char *name); -struct target * target_find_by_id(u32); -extern void target_list_build(struct connection *, char *, char *); +extern struct target * target_find_by_name(const char *name); +extern struct target * target_find_by_id(u32); +extern void target_list_build(struct connection *, char *); /* message.c */ extern int ietadm_request_listen(void); @@ -223,7 +248,7 @@ extern int isns_init(char *addr, int isns_ac); extern int isns_handle(int is_timeout, int *timeout); extern int isns_scn_handle(int accept); -extern int isns_scn_access(u32 tid, int fd, char *name); +extern int isns_scn_allow(u32 tid, char *name); extern int isns_target_register(char *name); extern int isns_target_deregister(char *name); extern void isns_exit(void); Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/iscsid.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/iscsid.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/isns.c iscsitarget-1.4.19+svn275/usr/isns.c --- iscsitarget-0.4.16+svn162/usr/isns.c 2008-06-29 21:49:49.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/isns.c 2009-12-09 18:08:56.000000000 +0000 @@ -63,22 +63,22 @@ static uint8_t ip[16]; /* IET supoprts only one portal */ static struct sockaddr_storage ss; -int isns_scn_access(uint32_t tid, int fd, char *name) +int isns_scn_allow(uint32_t tid, char *name) { struct isns_initiator *ini; struct target *target = target_find_by_id(tid); if (!use_isns || !use_isns_ac) - return 0; + return 1; if (!target) - return -EPERM; + return 0; list_for_each_entry(ini, &target->isns_head, ilist) { if (!strcmp(ini->name, name)) - return 0; + return 1; } - return -EPERM; + return 0; } static int isns_get_ip(int fd) @@ -199,8 +199,10 @@ memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; - length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); - length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); + length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name) + 1, + name); + length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name) + 1, + name); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_SCN_DEREG, length, flags, @@ -249,9 +251,9 @@ target = list_entry(targets_list.q_forw, struct target, tlist); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, - strlen(target->name), target->name); + strlen(target->name) + 1, target->name); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, - strlen(target->name), target->name); + strlen(target->name) + 1, target->name); length += isns_tlv_set(&tlv, 0, 0, 0); scn_flags = ISNS_SCN_FLAG_INITIATOR | ISNS_SCN_FLAG_OBJECT_REMOVE | @@ -299,14 +301,15 @@ tlv = (struct isns_tlv *) hdr->pdu; if (name) - snprintf(mgmt->name, sizeof(mgmt->name), name); + snprintf(mgmt->name, sizeof(mgmt->name), "%s", name); else { mgmt->name[0] = '\0'; target = list_entry(targets_list.q_forw, struct target, tlist); name = target->name; } - length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); + length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name) + 1, + name); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE, sizeof(node), &node); length += isns_tlv_set(&tlv, 0, 0, 0); @@ -348,10 +351,10 @@ target = list_entry(targets_list.q_forw, struct target, tlist); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, - strlen(target->name), target->name); + strlen(target->name) + 1, target->name); length += isns_tlv_set(&tlv, 0, 0, 0); length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER, - strlen(eid), eid); + strlen(eid) + 1, eid); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_DEV_DEREG, length, flags, @@ -369,7 +372,7 @@ uint16_t flags = 0, length = 0; struct isns_hdr *hdr = (struct isns_hdr *) buf; struct isns_tlv *tlv; - uint32_t port = htonl(ISCSI_LISTEN_PORT); + uint32_t port = htonl(server_port); uint32_t node = htonl(ISNS_NODE_TARGET); uint32_t type = htonl(2); struct target *target; @@ -387,14 +390,14 @@ target = list_entry(targets_list.q_back, struct target, tlist); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, - strlen(target->name), target->name); + strlen(target->name) + 1, target->name); length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER, - strlen(eid), eid); + strlen(eid) + 1, eid); length += isns_tlv_set(&tlv, 0, 0, 0); length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER, - strlen(eid), eid); + strlen(eid) + 1, eid); if (initial) { length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_PROTOCOL, sizeof(type), &type); @@ -411,7 +414,8 @@ } } - length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); + length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name) + 1, + name); length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NODE_TYPE, sizeof(node), &node); @@ -441,16 +445,6 @@ } } -static struct target *target_lookup_by_name(char *name) -{ - uint32_t tid; - - tid = target_find_by_name(name); - if (!tid) - return NULL; - return target_find_by_id(tid); -} - int isns_target_deregister(char *name) { char buf[4096]; @@ -460,7 +454,7 @@ int err, last = list_empty(&targets_list); struct target *target; - target = target_lookup_by_name(name); + target = target_find_by_name(name); if (target) free_all_acl(target); @@ -476,14 +470,15 @@ memset(buf, 0, sizeof(buf)); tlv = (struct isns_tlv *) hdr->pdu; - length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); + length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name) + 1, + name); length += isns_tlv_set(&tlv, 0, 0, 0); if (last) length += isns_tlv_set(&tlv, ISNS_ATTR_ENTITY_IDENTIFIER, - strlen(eid), eid); + strlen(eid) + 1, eid); else length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, - strlen(name), name); + strlen(name) + 1, name); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_DEV_DEREG, length, flags, @@ -660,7 +655,7 @@ goto free_qry_mgmt; } - target = target_lookup_by_name(mgmt->name); + target = target_find_by_name(mgmt->name); if (!target) { log_error("%s %d: invalid tid %s", __FUNCTION__, __LINE__, mgmt->name); @@ -687,7 +682,8 @@ ini = malloc(sizeof(*ini)); if (!ini) goto free_qry_mgmt; - snprintf(ini->name, sizeof(ini->name), name); + snprintf(ini->name, sizeof(ini->name), "%s", + name); insque(&ini->ilist, &target->isns_head); } else name = NULL; @@ -795,7 +791,8 @@ tlv = (struct isns_tlv *) ((char *) hdr->pdu + 4); length +=4; - length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name), name); + length += isns_tlv_set(&tlv, ISNS_ATTR_ISCSI_NAME, strlen(name) + 1, + name); flags = ISNS_FLAG_CLIENT | ISNS_FLAG_LAST_PDU | ISNS_FLAG_FIRST_PDU; isns_hdr_init(hdr, ISNS_FUNC_SCN_RSP, length, flags, transaction, 0); Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/isns.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/isns.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/log.c iscsitarget-1.4.19+svn275/usr/log.c --- iscsitarget-0.4.16+svn162/usr/log.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/log.c 2009-12-09 18:08:56.000000000 +0000 @@ -54,7 +54,7 @@ void log_debug(int level, const char *fmt, ...) { - if (log_level > level) { + if (log_level >= level) { va_list ap; va_start(ap, fmt); dolog(LOG_DEBUG, fmt, ap); @@ -62,15 +62,24 @@ } } +/* Definition for log_pdu buffer */ +#define BUFFER_SIZE 16 + +/* + * size required for a hex dump of BUFFER_SIZE bytes (' ' + 2 chars = 3 chars + * per byte) with a ' |' separator each 4th byte: + */ +#define LINE_SIZE (BUFFER_SIZE * 3 + BUFFER_SIZE / 4 * 2 + 1) + static void __dump_line(int level, unsigned char *buf, int *cp) { - char line[16*3+5], *lp = line; + char line[LINE_SIZE], *lp = line; int i, cnt; cnt = *cp; if (!cnt) return; - for (i = 0; i < 16; i++) { + for (i = 0; i < BUFFER_SIZE; i++) { if (i < cnt) lp += sprintf(lp, " %02x", buf[i]); else @@ -80,7 +89,9 @@ if (i >= cnt || !isprint(buf[i])) buf[i] = ' '; } - log_debug(level, "%s %.16s |", line, buf); + + /* buf is not \0-terminated! */ + log_debug(level, "%s %.*s |", line, BUFFER_SIZE, buf); *cp = 0; } @@ -89,7 +100,7 @@ int cnt = (*cp)++; buf[cnt] = ch; - if (cnt == 15) + if (cnt == BUFFER_SIZE - 1) __dump_line(level, buf, cp); } @@ -98,13 +109,12 @@ void log_pdu(int level, struct PDU *pdu) { - unsigned char char_buf[16]; + unsigned char char_buf[BUFFER_SIZE]; int char_cnt = 0; unsigned char *buf; int i; - return; - if (log_level <= level) + if (log_level < level) return; buf = (void *)&pdu->bhs; Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/log.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/log.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/message.c iscsitarget-1.4.19+svn275/usr/message.c --- iscsitarget-0.4.16+svn162/usr/message.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/message.c 2009-04-13 18:56:22.000000000 +0000 @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -37,7 +38,8 @@ return fd; } -static void ietadm_request_exec(struct ietadm_req *req, struct ietadm_rsp *rsp) +static void ietadm_request_exec(struct ietadm_req *req, struct ietadm_rsp *rsp, + void **rsp_data, size_t *rsp_data_sz) { int err = 0; @@ -99,14 +101,35 @@ break; case C_ACCT_NEW: - err = cops->account_add(req->tid, req->u.acnt.auth_dir, req->u.acnt.user, - req->u.acnt.pass); + err = cops->account_add(req->tid, req->u.acnt.auth_dir, + req->u.acnt.u.user.name, + req->u.acnt.u.user.pass); break; case C_ACCT_DEL: - err = cops->account_del(req->tid, req->u.acnt.auth_dir, req->u.acnt.user); + err = cops->account_del(req->tid, req->u.acnt.auth_dir, + req->u.acnt.u.user.name); + break; + case C_ACCT_LIST: + *rsp_data = malloc(req->u.acnt.u.list.alloc_len); + if (!*rsp_data) { + err = -ENOMEM; + break; + } + + *rsp_data_sz = req->u.acnt.u.list.alloc_len; + memset(*rsp_data, 0x0, *rsp_data_sz); + + err = cops->account_list(req->tid, req->u.acnt.auth_dir, + &req->u.acnt.u.list.count, + &req->u.acnt.u.list.overflow, + *rsp_data, *rsp_data_sz); break; case C_ACCT_UPDATE: + break; case C_ACCT_SHOW: + err = cops->account_query(req->tid, req->u.acnt.auth_dir, + req->u.acnt.u.user.name, + req->u.acnt.u.user.pass); break; case C_SYS_NEW: break; @@ -132,7 +155,9 @@ socklen_t len; struct ietadm_req req; struct ietadm_rsp rsp; - struct iovec iov[2]; + struct iovec iov[3]; + void *rsp_data = NULL; + size_t rsp_data_sz; memset(&rsp, 0, sizeof(rsp)); len = sizeof(addr); @@ -162,17 +187,22 @@ goto out; } - ietadm_request_exec(&req, &rsp); + ietadm_request_exec(&req, &rsp, &rsp_data, &rsp_data_sz); send: iov[0].iov_base = &req; iov[0].iov_len = sizeof(req); iov[1].iov_base = &rsp; iov[1].iov_len = sizeof(rsp); + iov[2].iov_base = rsp.err ? NULL : rsp_data; + iov[2].iov_len = iov[2].iov_base ? rsp_data_sz : 0; - err = writev(fd, iov, 2); + err = writev(fd, iov, 2 + !!iov[2].iov_len); out: if (fd > 0) close(fd); + if (rsp_data) + free(rsp_data); + return err; } Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/message.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/message.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/misc.h iscsitarget-1.4.19+svn275/usr/misc.h --- iscsitarget-0.4.16+svn162/usr/misc.h 2008-06-29 21:49:49.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/misc.h 2009-04-13 18:56:22.000000000 +0000 @@ -55,6 +55,41 @@ &pos->member != (head); \ pos = n, n = list_entry(n->member.q_forw, typeof(*n), member)) +#define list_del(elem) remque(elem) + +#define list_del_init(elem) do { \ + remque(elem); \ + INIT_LIST_HEAD(elem); \ + } while (0) + +#define list_add(new, head) insque (new, head) + +#define list_add_tail(new, head) insque(new, (head)->q_back) + +/* min()/max() that do strict type-checking. Lifted from the kernel. */ +#define min(x, y) ({ \ + typeof(x) _min1 = (x); \ + typeof(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) + +#define max(x, y) ({ \ + typeof(x) _max1 = (x); \ + typeof(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) + +/* ... and their non-checking counterparts, also taken from the kernel. */ +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1: __min2; }) + +#define max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1: __max2; }) + #ifndef IPV6_V6ONLY #define IPV6_V6ONLY 26 #endif diff -Nru iscsitarget-0.4.16+svn162/usr/param.c iscsitarget-1.4.19+svn275/usr/param.c --- iscsitarget-0.4.16+svn162/usr/param.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/param.c 2009-12-09 18:08:56.000000000 +0000 @@ -281,12 +281,14 @@ .set_val = marker_set_val, }; -#define SET_KEY_VALUES(x) DEFAULT_NR_##x,MIN_NR_##x, MAX_NR_##x +#define SET_KEY_VALUES(x) DEFAULT_##x,MIN_##x, MAX_##x struct iscsi_key target_keys[] = { - {"Wthreads", SET_KEY_VALUES(WTHREADS), &minimum_ops}, + {"Wthreads", SET_KEY_VALUES(NR_WTHREADS), &minimum_ops}, {"Type", 0, 0, 16, &minimum_ops}, - {"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), &minimum_ops}, + {"QueuedCommands", SET_KEY_VALUES(NR_QUEUED_CMNDS), &minimum_ops}, + {"NOPInterval", SET_KEY_VALUES(NOP_INTERVAL), &minimum_ops}, + {"NOPTimeout", SET_KEY_VALUES(NOP_TIMEOUT), &minimum_ops}, {NULL,}, }; Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/param.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/param.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/plain.c iscsitarget-1.4.19+svn275/usr/plain.c --- iscsitarget-0.4.16+svn162/usr/plain.c 2008-06-29 21:49:49.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/plain.c 2009-12-09 18:08:56.000000000 +0000 @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -23,8 +25,11 @@ #include "iscsid.h" #define BUFSIZE 4096 -#define CONFIG_FILE "/etc/ietd.conf" -#define ACCT_CONFIG_FILE CONFIG_FILE +#define CONFIG_FILE "ietd.conf" +#define CONFIG_DIR "/etc/iet/" +#define INI_ALLOW_FILE "initiators.allow" +#define INI_DENY_FILE "initiators.deny" +#define TGT_ALLOW_FILE "targets.allow" /* * Account configuration code @@ -85,43 +90,6 @@ return list; } -static int plain_account_init(char *filename) -{ - FILE *fp; - char buf[BUFSIZE], *p, *q; - u32 tid; - int idx; - - if (!(fp = fopen(filename, "r"))) - return -EIO; - - tid = 0; - while (fgets(buf, sizeof(buf), fp)) { - q = buf; - p = target_sep_string(&q); - if (!p || *p == '#') - continue; - - if (!strcasecmp(p, "Target")) { - tid = 0; - if (!(p = target_sep_string(&q))) - continue; - tid = target_find_by_name(p); - } else if (!((idx = param_index_by_name(p, user_keys)) < 0)) { - char *name, *pass; - name = target_sep_string(&q); - pass = target_sep_string(&q); - - if (cops->account_add(tid, idx, name, pass) < 0) - fprintf(stderr, "%s %s\n", name, pass); - } - } - - fclose(fp); - - return 0; -} - /* Return the first account if the length of name is zero */ static struct user *account_lookup_by_name(u32 tid, int dir, char *name) { @@ -156,6 +124,32 @@ return 0; } +static int plain_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow, + char *buf, size_t buf_sz) +{ + struct __qelem *list = account_list_get(tid, dir); + struct user *user; + + *cnt = *overflow = 0; + + if (!list) + return -ENOENT; + + list_for_each_entry(user, list, ulist) { + if (user->tid != tid) + continue; + if (buf_sz >= ISCSI_NAME_LEN) { + strncpy(buf, user->name, ISCSI_NAME_LEN); + buf_sz -= ISCSI_NAME_LEN; + buf += ISCSI_NAME_LEN; + *cnt += 1; + } else + *overflow += 1; + } + + return 0; +} + static void account_destroy(struct user *user) { if (!user) @@ -213,15 +207,16 @@ user->tid = tid; list = account_list_get(tid, dir); - - if (dir == AUTH_DIR_OUTGOING && !list_empty(list)) { - struct user *old; - log_warning("Only one outgoing %s account is supported." - " Replacing the old one.\n", - tid ? "target" : "discovery"); - - old = list_entry(list->q_forw, struct user, ulist); - account_destroy(old); + if (dir == AUTH_DIR_OUTGOING) { + struct user *old, *tmp; + list_for_each_entry_safe(old, tmp, list, ulist) { + if (tid != old->tid) + continue; + log_warning("Only one outgoing %s account is supported." + " Replacing the old one.\n", + tid ? "target" : "discovery"); + account_destroy(old); + } } insque(user, list); @@ -314,25 +309,49 @@ return 0; } -static int __initiator_match(int fd, char *str) +static int initiator_match(char *initiator, char *p) { - struct sockaddr_storage from; - struct addrinfo hints, *res; - socklen_t len; - char *p, *q; - int err = 0; + int match = 0; + char pattern[strlen(p) + 3]; + regex_t re; + + snprintf(pattern, sizeof(pattern), "^%s$", p); - len = sizeof(from); - if (getpeername(fd, (struct sockaddr *) &from, &len) < 0) + if (regcomp(&re, pattern, REG_NOSUB)) return 0; + match = !regexec(&re, initiator, (size_t) 0, NULL, 0); + + regfree(&re); + + return match; +} + +static int __match(struct sockaddr *sa, char *initiator, char *str) +{ + struct addrinfo hints, *res; + char *p, *q; + int match = 0; + while ((p = strsep(&str, ","))) { while (isspace(*p)) p++; + if (!*p) + continue; + + q = p + (strlen(p) - 1); + + while (isspace(*q)) + *(q--) = '\0'; + if (!strcmp(p, "ALL")) return 1; + if (initiator) + if (initiator_match(initiator, p)) + return 1; + if (*p == '[') { p++; if (!(q = strchr(p, ']'))) @@ -348,55 +367,70 @@ hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(p, NULL, &hints, &res) < 0) - return 0; + if (getaddrinfo(p, NULL, &hints, &res) == 0) { + if (q) + match = netmask_match(res->ai_addr, sa, q); + else + match = address_match(res->ai_addr, sa); - if (q) - err = netmask_match(res->ai_addr, - (struct sockaddr *) &from, q); - else - err = address_match(res->ai_addr, - (struct sockaddr *) &from); - - freeaddrinfo(res); + freeaddrinfo(res); + } - if (err) + if (match) break; } - return err; + return match; } -static int initiator_match(u32 tid, int fd, char *filename) +static int match(u32 tid, struct sockaddr *sa, char *initiator, char *filename) { - int err = 0; + int err = -EPERM; FILE *fp; - char buf[BUFSIZE], *p; + char buf[BUFSIZE], fname[PATH_MAX], *p, *q; - if (!(fp = fopen(filename, "r"))) - return err; + snprintf(fname, sizeof(fname), "%s%s", CONFIG_DIR, filename); + if (!(fp = fopen(fname, "r"))) { + if (errno != ENOENT) + return -errno; + + snprintf(fname, sizeof(fname), "%s%s", "/etc/", filename); + fp = fopen(fname, "r"); + if (!fp) + return -errno; + } /* * Every time we are called, we read the file. So we don't need to * implement 'reload feature'. It's slow, however, it doesn't matter. */ while ((p = fgets(buf, sizeof(buf), fp))) { - if (!p || *p == '#') - continue; + struct target *target; - p = &buf[strlen(buf) - 1]; - if (*p != '\n') - continue; - *p = '\0'; + q = &buf[strlen(buf) - 1]; - if (!(p = strchr(buf, ' '))) + if (*q != '\n') continue; - *(p++) = '\0'; + else + *q = '\0'; + + q = p; - if (target_find_by_name(buf) != tid && strcmp(buf, "ALL")) + p = target_sep_string(&q); + + if (!p || *p == '#') continue; - err = __initiator_match(fd, p); + if (strcmp(p, "ALL")) { + if (!(target = target_find_by_name(p))) + continue; + if (target->tid != tid) + continue; + } + + if (__match(sa, initiator, q)) + err = 0; + break; } @@ -404,13 +438,38 @@ return err; } -static int plain_initiator_access(u32 tid, int fd) +static int plain_initiator_allow(u32 tid, int fd, char *initiator) { - if (initiator_match(tid, fd, "/etc/initiators.deny") && - !initiator_match(tid, fd, "/etc/initiators.allow")) - return -EPERM; - else - return 0; + struct sockaddr_storage ss; + socklen_t slen = sizeof(struct sockaddr_storage); + int allow, deny; + + memset(&ss, 0, sizeof(ss)); + + getpeername(fd, (struct sockaddr *) &ss, &slen); + + allow = match(tid, (struct sockaddr *) &ss, initiator, + INI_ALLOW_FILE); + deny = match(tid, (struct sockaddr *) &ss, initiator, + INI_DENY_FILE); + + if (deny != -ENOENT) { + if (!deny && allow) + return 0; + else + return 1; + } + + return (allow == -ENOENT) ? 1 : !allow; +} + +static int plain_target_allow(u32 tid, struct sockaddr *sa) +{ + int allow; + + allow = match(tid, sa, NULL, TGT_ALLOW_FILE); + + return (allow == -ENOENT) ? 1 : !allow; } /* @@ -504,24 +563,46 @@ else param = target_param; + memset(param, 0x0, (type == key_session) ? + sizeof(session_param) : + sizeof(target_param)); + param[key].val = val; return __plain_param_set(tid, sid, type, 1 << key, param, 0); } -static int plain_main_init(char *filename) +static void plain_portal_init(FILE *fp, char **isns, int *isns_ac) +{ + char buf[BUFSIZE]; + char *p, *q; + + while (fgets(buf, BUFSIZE, fp)) { + q = buf; + p = target_sep_string(&q); + if (!p || *p == '#') + continue; + if (!strcasecmp(p, "iSNSServer")) { + *isns = strdup(target_sep_string(&q)); + } else if (!strcasecmp(p, "iSNSAccessControl")) { + char *str = target_sep_string(&q); + if (!strcasecmp(str, "Yes")) + *isns_ac = 1; + } + } + + return; +} + +static void plain_target_init(FILE *fp) { - FILE *config; char buf[BUFSIZE]; char *p, *q; int idx; u32 tid, val; - if (!(config = fopen(filename, "r"))) - return -errno; - tid = 0; - while (fgets(buf, BUFSIZE, config)) { + while (fgets(buf, BUFSIZE, fp)) { q = buf; p = target_sep_string(&q); if (!p || *p == '#') @@ -530,12 +611,16 @@ tid = 0; if (!(p = target_sep_string(&q))) continue; - if (__plain_target_create(&tid, p, 0)) - log_debug(1, "creating target %s", p); + __plain_target_create(&tid, p, 0); } else if (!strcasecmp(p, "Alias") && tid) { ; } else if (!strcasecmp(p, "MaxSessions") && tid) { - /* target->max_sessions = strtol(q, &q, 0); */ + struct target * const target = + target_find_by_id(tid); + if (target) + target->max_nr_sessions = strtol(q, &q, 0); + else + log_warning("Target '%s' not found", q); } else if (!strcasecmp(p, "Lun") && tid) { u32 lun = strtol(q, &q, 10); __plain_lunit_create(tid, lun, q, 0); @@ -554,61 +639,91 @@ } } - fclose(config); - return 0; + return; } -static int plain_default_load(char *params) +static void plain_account_init(FILE *fp) { - int i, err; + char buf[BUFSIZE], *p, *q; + u32 tid; + int idx; - for (i = 0; i < 1 << HASH_ORDER; i++) { - INIT_LIST_HEAD(&trgt_acct_in[i]); - INIT_LIST_HEAD(&trgt_acct_out[i]); - } + tid = 0; + while (fgets(buf, sizeof(buf), fp)) { + q = buf; + p = target_sep_string(&q); + if (!p || *p == '#') + continue; - /* First, we must finish the main configuration. */ - if ((err = plain_main_init(params ? params : CONFIG_FILE))) - return err; + if (!strcasecmp(p, "Target")) { + struct target *target; + tid = 0; + if (!(p = target_sep_string(&q))) + continue; - if ((err = plain_account_init(ACCT_CONFIG_FILE)) < 0) - return err; + target = target_find_by_name(p); + if (target) + tid = target->tid; + } else if (!((idx = param_index_by_name(p, user_keys)) < 0)) { + char *name, *pass; + name = target_sep_string(&q); + pass = target_sep_string(&q); - /* TODO: error handling */ + if (plain_account_add(tid, idx, name, pass) < 0) + fprintf(stderr, "%s %s\n", name, pass); + } + } - return err; + return; } -static int plain_init(char *params, char **isns, int *isns_ac) +static void plain_init(char *params, char **isns, int *isns_ac) { - FILE *config; - char buf[BUFSIZE]; - char *p, *q; + FILE *fp; + struct stat st; + char file1[PATH_MAX], file2[PATH_MAX]; + int i; - if (!(config = fopen(params ? : CONFIG_FILE, "r"))) - return -errno; + for (i = 0; i < 1 << HASH_ORDER; i++) { + INIT_LIST_HEAD(&trgt_acct_in[i]); + INIT_LIST_HEAD(&trgt_acct_out[i]); + } - while (fgets(buf, BUFSIZE, config)) { - q = buf; - p = target_sep_string(&q); - if (!p || *p == '#') - continue; - if (!strcasecmp(p, "iSNSServer")) { - *isns = strdup(target_sep_string(&q)); - } else if (!strcasecmp(p, "iSNSAccessControl")) { - char *str = target_sep_string(&q); - if (!strcasecmp(str, "Yes")) - *isns_ac = 1; + snprintf(file1, sizeof(file1), "%s%s", CONFIG_DIR, INI_DENY_FILE); + snprintf(file2, sizeof(file2), "/etc/%s", INI_DENY_FILE); + + if (!stat(file1, &st) || !stat(file2, &st)) + log_warning("%s is depreciated and will be obsoleted in the next release, please see README.initiators for more information", INI_DENY_FILE); + + snprintf(file1, sizeof(file1), "%s%s", CONFIG_DIR, CONFIG_FILE); + snprintf(file2, sizeof(file2), "/etc/%s", CONFIG_FILE); + + if (!(fp = fopen(params ? params : file1, "r"))) { + if ((fp = fopen(file2, "r"))) + log_warning("%s's location is depreciated and will be moved in the next release to %s", file2, file1); + else { + log_warning("%s not found, configure through ietadm", CONFIG_FILE); + return; } } - fclose(config); - return 0; + plain_portal_init(fp, isns, isns_ac); + + rewind(fp); + + plain_target_init(fp); + + rewind(fp); + + plain_account_init(fp); + + fclose(fp); + + return; } struct config_operations plain_ops = { .init = plain_init, - .default_load = plain_default_load, .target_add = plain_target_create, .target_del = plain_target_destroy, .lunit_add = plain_lunit_create, @@ -617,5 +732,7 @@ .account_add = plain_account_add, .account_del = plain_account_del, .account_query = plain_account_query, - .initiator_access = plain_initiator_access, + .account_list = plain_account_list, + .initiator_allow = plain_initiator_allow, + .target_allow = plain_target_allow, }; Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/plain.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/plain.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/session.c iscsitarget-1.4.19+svn275/usr/session.c --- iscsitarget-0.4.16+svn162/usr/session.c 2007-11-02 11:54:38.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/session.c 2009-12-09 18:08:56.000000000 +0000 @@ -153,12 +153,11 @@ { log_debug(1, "session_remove: %#" PRIx64, session->sid.id64); - if (!session->sid.id.tsih) - ki->session_destroy(session->target->tid, session->sid.id64); + ki->session_destroy(session->target->tid, session->sid.id64); if (session->target) { remque(&session->slist); -/* session->target->nr_sessions--; */ + --session->target->nr_sessions; } free(session->initiator); Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/session.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/session.o differ diff -Nru iscsitarget-0.4.16+svn162/usr/target.c iscsitarget-1.4.19+svn275/usr/target.c --- iscsitarget-0.4.16+svn162/usr/target.c 2008-06-29 21:49:49.000000000 +0000 +++ iscsitarget-1.4.19+svn275/usr/target.c 2009-12-09 18:08:56.000000000 +0000 @@ -10,38 +10,170 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include +#include #include "iscsid.h" struct __qelem targets_list = LIST_HEAD_INIT(targets_list); -void target_list_build(struct connection *conn, char *addr, char *name) +extern struct pollfd poll_array[POLL_MAX]; + +static int is_addr_loopback(char *addr) +{ + struct in_addr ia; + struct in6_addr ia6; + + if (inet_pton(AF_INET, addr, &ia) == 1) + return !strncmp(addr, "127.", 4); + + if (inet_pton(AF_INET6, addr, &ia6) == 1) + return IN6_IS_ADDR_LOOPBACK(&ia6); + + return 0; +} + +static int is_addr_unspecified(char *addr) +{ + struct in_addr ia; + struct in6_addr ia6; + + if (inet_pton(AF_INET, addr, &ia) == 1) + return (ia.s_addr == 0); + + if (inet_pton(AF_INET6, addr, &ia6) == 1) + return IN6_IS_ADDR_UNSPECIFIED(&ia6); + + return 0; +} + +static void target_print_addr(struct connection *conn, char *addr, int family) +{ + char taddr[NI_MAXHOST + NI_MAXSERV + 5]; + + snprintf(taddr, sizeof(taddr), + (family == AF_INET) ? "%s:%d,1" : "[%s]:%d,1", + addr, server_port); + + text_key_add(conn, "TargetAddress", taddr); +} + +void target_list_build_ifaddrs(struct connection *conn, u32 tid, char *addr, + int family) +{ + struct ifaddrs *ifaddr, *ifa; + char if_addr[NI_MAXHOST]; + + getifaddrs(&ifaddr); + + ifa = ifaddr; + + while (ifa) { + if (!ifa->ifa_addr) + continue; + + int sa_family = ifa->ifa_addr->sa_family; + + if (sa_family == family) { + if (getnameinfo(ifa->ifa_addr, (family == AF_INET) ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6), + if_addr, sizeof(if_addr), + NULL, 0, NI_NUMERICHOST)) + continue; + + if (strcmp(addr, if_addr) && !is_addr_loopback(if_addr) + && cops->target_allow(tid, ifa->ifa_addr)) + target_print_addr(conn, if_addr, family); + } + + ifa = ifa->ifa_next; + } + + freeifaddrs(ifaddr); +} + +void target_list_build(struct connection *conn, char *name) { struct target *target; + struct sockaddr_storage ss1, ss2; + socklen_t slen = sizeof(struct sockaddr_storage); + char addr1[NI_MAXHOST], addr2[NI_MAXHOST]; + int ret, family, i; + + if (getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) { + log_error("getsockname failed: %m"); + return; + } + + ret = getnameinfo((struct sockaddr *) &ss1, slen, addr1, + sizeof(addr1), NULL, 0, NI_NUMERICHOST); + if (ret) { + log_error("getnameinfo failed: %s", + (ret == EAI_SYSTEM) ? strerror(errno) : + gai_strerror(ret)); + return; + } + + family = ss1.ss_family; list_for_each_entry(target, &targets_list, tlist) { if (name && strcmp(target->name, name)) continue; - if (cops->initiator_access(target->tid, conn->fd) || - isns_scn_access(target->tid, conn->fd, conn->initiator)) + + if (!isns_scn_allow(target->tid, conn->initiator) + || !cops->initiator_allow(target->tid, conn->fd, + conn->initiator) + || !cops->target_allow(target->tid, + (struct sockaddr *) &ss1)) continue; text_key_add(conn, "TargetName", target->name); - text_key_add(conn, "TargetAddress", addr); + + target_print_addr(conn, addr1, family); + + for (i = 0; i < LISTEN_MAX && poll_array[i].fd; i++) { + slen = sizeof(struct sockaddr_storage); + + if (getsockname(poll_array[i].fd, + (struct sockaddr *) &ss2, &slen)) + continue; + + if (getnameinfo((struct sockaddr *) &ss2, slen, addr2, + sizeof(addr2), NULL, 0, NI_NUMERICHOST)) + continue; + + if (ss2.ss_family != family) + continue; + + if (is_addr_unspecified(addr2)) + target_list_build_ifaddrs(conn, target->tid, + addr1, family); + else if (strcmp(addr1, addr2) + && !is_addr_loopback(addr2) + && cops->target_allow(target->tid, + (struct sockaddr *) &ss2)) + target_print_addr(conn, addr2, family); + } } } -u32 target_find_by_name(const char *name) +struct target* target_find_by_name(const char *name) { struct target *target; list_for_each_entry(target, &targets_list, tlist) { if (!strcasecmp(target->name, name)) - return target->tid; + return target; } - return 0; + return NULL; } struct target* target_find_by_id(u32 tid) @@ -71,22 +203,23 @@ int target_del(u32 tid) { - int err; - struct target* target; - - if (!(target = target_find_by_id(tid))) - return -ENOENT; + struct target *target = target_find_by_id(tid); + int err = ki->target_destroy(tid); - if (target->nr_sessions) - return -EBUSY; + if (err < 0 && errno != ENOENT) + return -errno; + else if (!err && !target) + /* A leftover kernel object was cleaned up - don't complain. */ + return 0; - if ((err = ki->target_destroy(tid)) < 0) - return err; + if (!target) + return -ENOENT; remque(&target->tlist); if (!list_empty(&target->sessions_list)) { - fprintf(stderr, "%s still have sessions %d\n", __FUNCTION__, tid); + log_error("%s: target %u still has sessions\n", __FUNCTION__, + tid); exit(-1); } @@ -126,6 +259,8 @@ isns_target_register(name); + log_debug(1, "created target %s", name); + return 0; out: free(target); Binary files /tmp/wUuX0dzZkI/iscsitarget-0.4.16+svn162/usr/target.o and /tmp/Z6Rj7g19hN/iscsitarget-1.4.19+svn275/usr/target.o differ