mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-17 12:46:27 +00:00
Merged revisions 5246-5256,5260,5264,5266-5277,5281-5296,5300-5312,5315-5316,5320 via svnmerge from
svn+ssh://yanb123@svn.code.sf.net/p/scst/svn/trunk
........
r5246 | vlnb | 2014-01-29 05:30:24 +0200 (Wed, 29 Jan 2014) | 3 lines
Put CDB control byte parsing in one place
........
r5247 | vlnb | 2014-01-29 06:16:58 +0200 (Wed, 29 Jan 2014) | 3 lines
Better version of the previous patch
........
r5248 | vlnb | 2014-01-30 03:40:48 +0200 (Thu, 30 Jan 2014) | 7 lines
[PATCH 1/2] scst_sysfs: Make it easier to add new target sysfs attributes
This patch does not change any functionality.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5249 | vlnb | 2014-01-30 03:41:54 +0200 (Thu, 30 Jan 2014) | 10 lines
[PATCH 2/2] scst_sysfs: Add I/O statistics per target
Although it is possible to obtain these statistics by iterating over
all sessions and by computing the sum of the per-target statistics,
make per-target statistics directly available such that these can be
retrieved easily.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5250 | vlnb | 2014-01-30 04:32:44 +0200 (Thu, 30 Jan 2014) | 3 lines
Update for 3.13 kernels
........
r5251 | bvassche | 2014-01-30 11:16:27 +0200 (Thu, 30 Jan 2014) | 1 line
nightly build: Add kernel 3.13 build infrastructure
........
r5252 | bvassche | 2014-01-30 11:30:18 +0200 (Thu, 30 Jan 2014) | 1 line
scripts/kernel-functions: Add a bug fix for the kernel 3.13 series that is not yet present in the kernel 3.13 stable series
........
r5253 | bvassche | 2014-01-30 11:31:32 +0200 (Thu, 30 Jan 2014) | 1 line
nightly build: Add kernel version 3.13.1
........
r5254 | vlnb | 2014-01-31 04:32:02 +0200 (Fri, 31 Jan 2014) | 10 lines
scst_pres: Simplify PR locking
Since the time during which a PR read or write lock is held is short,
use a mutex to implement PR read and write locking. So although this
patch excludes multiple simultaneous readers that shouldn't affect the
time needed to process a PR operation measurably.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5255 | vlnb | 2014-01-31 04:33:11 +0200 (Fri, 31 Jan 2014) | 5 lines
scst_vdisk: Check that "filename" is specified at most once
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5256 | vlnb | 2014-01-31 04:35:20 +0200 (Fri, 31 Jan 2014) | 5 lines
scst_vdisk: Sort "add_device_parameters" alphabetically
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5260 | bvassche | 2014-02-03 11:03:03 +0200 (Mon, 03 Feb 2014) | 1 line
scripts/list-source-files: Handle Mercurial subdirectories properly
........
r5264 | bvassche | 2014-02-06 14:46:51 +0200 (Thu, 06 Feb 2014) | 9 lines
scst_local: Fix a kernel oops for kernel versions < 2.6.37
Avoid that scst_local triggers "BUG: unable to handle kernel NULL
pointer dereference" on kernel versions before 2.6.37. This patch
fixes a regression introduced via patch "scst_local: Avoid
deadlock during module removal with kernel 3.6" (trunk r4566).
Reported-by: Sebastian Herbszt <herbszt@gmx.de>
........
r5266 | bvassche | 2014-02-06 15:30:06 +0200 (Thu, 06 Feb 2014) | 14 lines
Hush Coverity warning of scst_ws_push_single_write() uninitialized pointer
Coverity warns that sgv may be used uninitialized. The warning
applies to WRITE SAME commands with LBDATA == PBDATA == 0 (replicate
a single block of user data into the specified LBA range).
The warning appears to be spurious - when LBDATA == PBDATA == 0,
scst_ws_write_cmd_finished() will not use the uninitialized value
saved by scst_ws_push_single_write().
Move initialization of sgv earlier in the function to quiesce the warning.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
r5267 | bvassche | 2014-02-06 15:38:28 +0200 (Thu, 06 Feb 2014) | 7 lines
qla2x00t: Re-sync help text with the code
The ql2xfdmienable module parameter defaults to 1, but the help text
claims it defaults to zero.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
r5268 | bvassche | 2014-02-06 16:17:49 +0200 (Thu, 06 Feb 2014) | 6 lines
ib_srpt: Avoid that disabling a target triggers a race condition
Avoid that disabling a target triggers a race condition with
SRP relogin. At least in theory this race condition could result
in a kernel crash.
........
r5269 | bvassche | 2014-02-07 09:31:38 +0200 (Fri, 07 Feb 2014) | 9 lines
scst_sysfs: Fix a build failure on kernels 2.6.2[678]
The sysfs API is supported from kernel 2.6.26 on and uses the swap()
macro while the swap() macro was introduced in kernel 2.6.29. Hence
provide a definition of the swap() macro for kernels before 2.6.29.
Signed-off-by: Sebastian Herbszt <herbszt@gmx.de>
[bvanassche: Moved swap() definition a few lines down and added #ifndef/#endif]
........
r5270 | bvassche | 2014-02-07 09:45:15 +0200 (Fri, 07 Feb 2014) | 2 lines
regression tests: Run the 2.6.26..2.6.32 tests on the sysfs code instead of procfs
........
r5271 | bvassche | 2014-02-07 10:11:28 +0200 (Fri, 07 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5272 | bvassche | 2014-02-07 14:43:25 +0200 (Fri, 07 Feb 2014) | 16 lines
scst_user, rt: Wake command processing thread when needed
In a fully-preemptible realtime kernel (CONFIG_PREEMPT_RT_FULL=y),
SCSI commands from an initiator time out because the userland target
application is never woken to process them.
This is because in a fully-preemptible realtime kernel, soft-IRQ
(tasklet) execution always occurs in a ksoftirqd thread and
preempt_count is not manipulated on soft-IRQ processing entry/exit.
This makes in_interrupt() useless for determining whether soft-IRQ
processing is occurring; instead, in_serving_softirq() should be
used for that purpose.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
[bvanassche: Elaborated source code comment]
........
r5273 | bvassche | 2014-02-07 14:46:39 +0200 (Fri, 07 Feb 2014) | 9 lines
scst_vdisk: Build fix for kernels 2.6.27..2.6.30
add_to_page_cache_lru and __lock_page_killable are exported since
kernel version 2.6.30. See also patch "Staging: pohmelfs: kconfig/makefile
and vfs changes" (commit 18bc0bbd162e3eb3e7ea2953c315ad4113a57164;
included in kernel v2.6.30).
Signed-off-by: Sebastian Herbszt <herbszt@gmx.de>
........
r5274 | vlnb | 2014-02-08 03:04:27 +0200 (Sat, 08 Feb 2014) | 9 lines
scst_user: Convert sgv_purge_interval to jiffies before use
The sgv_purge_interval from userland is passed down without conversion to
jiffies. Yet, if it is zero, the default value is (60 * HZ).
Convert to jiffies before passing down.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
r5275 | vlnb | 2014-02-08 03:52:03 +0200 (Sat, 08 Feb 2014) | 19 lines
Fix spurious BUG when parse_type != SCST_USER_PARSE_STANDARD
Changeset 4224 introduced EXTRACHECKS for valid lba/data_len and state
at the end of the parsing phase of command processing.
However, the checks do not account for deferral of parsing to userland,
as occurs when SCST_USER_PARSE_CALL or SCST_USER_PARSE_EXCEPTION are specified.
In such cases the checks report errors on commands that userland has not yet
had an opportunity to parse.
NOTE: this includes a refactoring of the EXTRACHECKS to improve clarity.
The rework is not exactly equivalent to the original code, but does
conform to the comments describing the original code.
Specifically, the original code would not trap an illegal command state
unless there was also an illegal lba or data_len.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
with some improvements
........
r5276 | bvassche | 2014-02-08 10:24:28 +0200 (Sat, 08 Feb 2014) | 1 line
scst: Build fix for kernel versions before 2.6.37
........
r5277 | bvassche | 2014-02-09 18:50:10 +0200 (Sun, 09 Feb 2014) | 1 line
scst_debug.h: Avoid that the sBUG() and sBUG_ON() definitions confuse the smatch static code checker
........
r5281 | vlnb | 2014-02-13 06:02:56 +0200 (Thu, 13 Feb 2014) | 8 lines
iscsi-scst: fix offset calculation
Fixed a subtle bug in iSCSI-SCST with incorrectly calculated offsets
for non-page aligned transfers. Originally discovered, investigated and
fix suggested by Кирилл Тюшев, then Shahar Salzman tested and proved it.
See http://sourceforge.net/mailarchive/message.php?msg_id=31924078
........
r5282 | vlnb | 2014-02-13 06:15:31 +0200 (Thu, 13 Feb 2014) | 3 lines
Web update
........
r5283 | bvassche | 2014-02-14 15:05:55 +0200 (Fri, 14 Feb 2014) | 7 lines
Makefiles: remove redundant 'depmod' invocations
Running 'make modules_install' already triggers invocation of depmod,
hence leave it out from those Makefiles that use 'make modules_install'.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
r5284 | bvassche | 2014-02-14 15:48:54 +0200 (Fri, 14 Feb 2014) | 2 lines
Makefiles: Convert from "install" to "make modules_install"
........
r5285 | bvassche | 2014-02-14 16:46:11 +0200 (Fri, 14 Feb 2014) | 1 line
mvsas_tgt/Makefile: Remove trailing whitespace
........
r5286 | bvassche | 2014-02-14 17:52:10 +0200 (Fri, 14 Feb 2014) | 18 lines
Makefiles: calculate KVER properly
When deriving the kernel version (KVER) from KDIR, the file
$(KDIR)/include/config/kernel.release should be preferred over
'make kernelversion'.
For example, the Ubuntu 3.2.0-23-generic kernel has a kernel.release
file containing '3.2.0-23-generic', but 'make kernelversion' returns
3.2.14. Since the modules are stored under /lib/modules/3.2.0-23-generic,
the value in kernel.release is the correct one to use.
Also:
- Evaluate KVER only once
- All depmod commands must include KVER
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
[bvanassche: Split long lines / removed trailing whitespace]
........
r5287 | bvassche | 2014-02-14 21:27:09 +0200 (Fri, 14 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5288 | bvassche | 2014-02-18 10:31:44 +0200 (Tue, 18 Feb 2014) | 22 lines
scst, qla2x00t: Prevent inappropriate sleeping with a real-time kernel
With a realtime kernel with full preemption (CONFIG_PREEMPT_RT_FULL),
spinlocks can sleep, interrupt handlers run in thread context, and
the standard local_irq functions manipulate preemptibility, not HW
interruptibility. Under these conditions, most calls to local_irq
functions should be replaced by no-ops. The CONFIG_PREEMPT_RT patch
defines _nort versions of local_irq functions that compile away
under CONFIG_PREEMPT_RT_FULL and compile to their "normal"
equivalents otherwise.
Define _nort equivalents to support compilation against both
"normal" and RT-patched kernels, and use the _nort local_irq
functons in cases where spinlocks are taken within a
local_irq_save() or local_irq_disable() block. Without these
changes, runtime warnings about "sleeping function called from
invalid context" occur.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
[bvanassche: Edited patch description and comment in scst_priv.h]
........
r5289 | bvassche | 2014-02-18 10:40:36 +0200 (Tue, 18 Feb 2014) | 13 lines
Makefiles: respect DESTDIR when specified
Not all SCST components handle DESTDIR properly, or at all.
In particular:
* INSTALL_MOD_PATH should account for DESTDIR when 'make modules_install'
is invoked, so the kernel make infrastructure deploys the modules
and runs depmod against the proper directory tree.
* depmods must include a '-b' option to reference the proper directory tree.
* Drop special ISCSI_DESTDIR.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
r5290 | bvassche | 2014-02-18 10:41:30 +0200 (Tue, 18 Feb 2014) | 7 lines
Makefiles: 'uninstall' target fixes
Some components don't have 'uninstall' targets although the top-level
Makefile references them. Some others don't remove the proper file.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
r5291 | vlnb | 2014-02-19 05:45:48 +0200 (Wed, 19 Feb 2014) | 8 lines
Fix incorrect start and length calculation for issuing block discard requests
Block layer always expects start and length in 512 byte blocks, so they
should be corrected for non-512b SCST devices.
Original patch from Ken Raeburn <raeburn@permabit.com>
........
r5292 | vlnb | 2014-02-19 06:06:10 +0200 (Wed, 19 Feb 2014) | 3 lines
Cleanups
........
r5293 | vlnb | 2014-02-19 06:21:00 +0200 (Wed, 19 Feb 2014) | 12 lines
scst_user: Complete "Preparing" / "finished" symmetry
Add some TRACE statements so events sent to userland are bracketed by
"Preparing" and "finished". This makes it a little easier to find the
boundaries between the various stages of command processing in trace output.
Note, this patch does not implement a 'finished' message for TM events;
there is already a "TM reply" message that can serve that purpose.
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
r5294 | bvassche | 2014-02-19 09:38:57 +0200 (Wed, 19 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5295 | bvassche | 2014-02-19 10:51:35 +0200 (Wed, 19 Feb 2014) | 1 line
scripts/blockdev-perftest: Fix bashisms
........
r5296 | vlnb | 2014-02-20 07:54:49 +0200 (Thu, 20 Feb 2014) | 3 lines
put_page_callback patch for 3.13.3+ kernels
........
r5300 | vlnb | 2014-02-21 04:08:05 +0200 (Fri, 21 Feb 2014) | 3 lines
Docs update
........
r5301 | bvassche | 2014-02-21 09:44:55 +0200 (Fri, 21 Feb 2014) | 1 line
nightly build: Add support for the put_page_callback-3.13.3 patch
........
r5302 | bvassche | 2014-02-21 09:48:21 +0200 (Fri, 21 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5303 | bvassche | 2014-02-21 12:02:11 +0200 (Fri, 21 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5304 | bvassche | 2014-02-21 12:09:45 +0200 (Fri, 21 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5305 | bvassche | 2014-02-24 08:56:05 +0200 (Mon, 24 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5306 | bvassche | 2014-02-24 08:56:44 +0200 (Mon, 24 Feb 2014) | 1 line
Spelling fix: initator -> initiator
........
r5307 | bvassche | 2014-02-24 09:30:50 +0200 (Mon, 24 Feb 2014) | 1 line
make rpm: Do not remove rpmbuilddir
........
r5308 | bvassche | 2014-02-24 09:39:45 +0200 (Mon, 24 Feb 2014) | 5 lines
scst_local: Add newline to sysfs output
Signed-off-by: Sebastian Herbszt <herbszt@gmx.de>
[bvanassche: Reduced source code line length to 80 columns]
........
r5309 | bvassche | 2014-02-25 12:55:36 +0200 (Tue, 25 Feb 2014) | 1 line
put_page_callback-3.12.11.patch: Add
........
r5310 | bvassche | 2014-02-25 12:57:27 +0200 (Tue, 25 Feb 2014) | 1 line
put_page_callback-3.10.30.patch: Add
........
r5311 | bvassche | 2014-02-25 12:58:08 +0200 (Tue, 25 Feb 2014) | 1 line
nightly build: Add support for kernels >= 3.10.30 and >= 3.12.11
........
r5312 | bvassche | 2014-02-25 12:59:54 +0200 (Tue, 25 Feb 2014) | 1 line
nightly build: Update kernel versions
........
r5315 | vlnb | 2014-02-26 04:32:39 +0200 (Wed, 26 Feb 2014) | 3 lines
Make internal memory layout more cache friendly
........
r5316 | vlnb | 2014-02-26 04:49:38 +0200 (Wed, 26 Feb 2014) | 5 lines
scst_vdisk: Make vendor, product ID and related fields configurable via sysfs
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5320 | bvassche | 2014-03-02 10:49:50 +0200 (Sun, 02 Mar 2014) | 1 line
Documentation spelling fix: change INQUERY into INQUIRY
........
git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5321 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -19,19 +19,21 @@
|
||||
SHELL = /bin/bash
|
||||
|
||||
# Define the location to the kernel src. Can be defined here or on
|
||||
# the command line during the build process. If KDIR is defined,
|
||||
# we will set an appropriate value for KVER by running "make
|
||||
# kernelversion" in the kernel source tree. KVER can still be
|
||||
# overrode by the user via the command line or by defining it in
|
||||
# this Makefile. If KDIR and KVER are not defined by the user,
|
||||
# the current running kernel version is used to define KVER.
|
||||
# the command line during the build process. If KDIR is defined,
|
||||
# we will determine an appropriate value for KVER from the kernel
|
||||
# source tree. KVER can still be overridden by the user via the
|
||||
# command line or by defining it in this Makefile. If KDIR and KVER
|
||||
# are not defined by the user, the current running kernel version is
|
||||
# used to define KVER.
|
||||
|
||||
#export KDIR=/usr/src/linux-2.6
|
||||
#export KVER=2.6.x
|
||||
|
||||
ifdef KDIR
|
||||
ifndef KVER
|
||||
export KVER = $(strip $(shell make -s -C $(KDIR) kernelversion))
|
||||
export KVER = $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -49,7 +51,6 @@ MVSAS_DIR=mvsas_tgt
|
||||
FCST_DIR=fcst
|
||||
|
||||
ISCSI_DIR=iscsi-scst
|
||||
#ISCSI_DESTDIR=../../../iscsi_scst_inst
|
||||
|
||||
VERSION = $(shell echo -n "$$(sed -n 's/^\#define[[:blank:]]SCST_VERSION_NAME[[:blank:]]*\"\([^-]*\).*\"/\1/p' scst/include/scst_const.h)."; \
|
||||
if svn info >/dev/null 2>&1; \
|
||||
@@ -153,7 +154,7 @@ install:
|
||||
# @if [ -d $(QLA_ISP_DIR) ]; then cd $(QLA_ISP_DIR) && $(MAKE) $@; fi
|
||||
# @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi
|
||||
# @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) DESTDIR=$(ISCSI_DESTDIR) $@; fi
|
||||
@if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
|
||||
|
||||
@@ -271,7 +272,7 @@ iscsi:
|
||||
cd $(ISCSI_DIR) && $(MAKE) all
|
||||
|
||||
iscsi_install:
|
||||
cd $(ISCSI_DIR) && $(MAKE) DESTDIR=$(ISCSI_DESTDIR) install
|
||||
cd $(ISCSI_DIR) && $(MAKE) install
|
||||
|
||||
iscsi_uninstall:
|
||||
cd $(ISCSI_DIR) && $(MAKE) uninstall
|
||||
@@ -388,7 +389,6 @@ scst-rpm:
|
||||
rpmtopdir="$$(if [ $$(id -u) = 0 ]; then echo /usr/src/packages;\
|
||||
else echo $$PWD/rpmbuilddir; fi)" && \
|
||||
$(MAKE) scst-dist-gzip && \
|
||||
rm -rf $${rpmtopdir} && \
|
||||
for d in BUILD RPMS SOURCES SPECS SRPMS; do \
|
||||
mkdir -p $${rpmtopdir}/$$d; \
|
||||
done && \
|
||||
|
||||
+30
-19
@@ -26,19 +26,6 @@
|
||||
# - install and uninstall must be made as root
|
||||
#
|
||||
|
||||
ifndef PREFIX
|
||||
PREFIX=/usr/local
|
||||
endif
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
export PWD := $(shell pwd)
|
||||
export CONFIG_FCST := m
|
||||
|
||||
@@ -55,16 +42,39 @@ EXTRA_CFLAGS += -I$(SCST_INC_DIR) $(FCSTFLAGS$(BUILDMODE))
|
||||
|
||||
MODULE_NAME = fcst
|
||||
|
||||
INSTALL_DIR := /lib/modules/$(KVER)/extra
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
include $(SUBDIRS)/Makefile_in-tree
|
||||
else
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
ifndef PREFIX
|
||||
PREFIX=/usr/local
|
||||
endif
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \
|
||||
then echo "$$PWD/../scst/include"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
SCST_DIR := $(shell if [ -e "$$PWD/../scst" ]; then echo "$$PWD/../scst/src"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
|
||||
all: Modules.symvers Module.symvers
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
@@ -77,7 +87,6 @@ tgt: Modules.symvers Module.symvers
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
SCST_INC_DIR=$(SCST_INC_DIR) modules_install
|
||||
-depmod -a $(KVER)
|
||||
|
||||
ins:
|
||||
./config
|
||||
@@ -102,7 +111,9 @@ endif
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/$(MODULE_NAME).ko
|
||||
-/sbin/depmod -a $(KVER)
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
+21
-9
@@ -7,15 +7,27 @@ SUBDIRS := $(shell pwd)
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER = $$KERNELRELEASE
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
else
|
||||
KVER := $(KERNELRELEASE)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
# The file Modules.symvers has been renamed in the 2.6.18 kernel to
|
||||
# Module.symvers. Find out which name to use by looking in $(KDIR).
|
||||
MODULE_SYMVERS:=$(shell if [ -e $(KDIR)/Module.symvers ]; then \
|
||||
@@ -26,11 +38,11 @@ all: src/$(MODULE_SYMVERS)
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src modules
|
||||
|
||||
install: all src/ibmvstgt.ko
|
||||
@eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KDIR)/include/linux/version.h $(KDIR)/include/linux/utsrelease.h 2>/dev/null`; \
|
||||
for m in libsrp.ko ibmvstgt.ko; do \
|
||||
install -vD -m 644 src/$$m \
|
||||
$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/$$m; done
|
||||
-/sbin/depmod -aq $(KVER)
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src modules_install
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/libsrp.ko $(INSTALL_DIR)/ibmvstgt.ko
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
src/Module.symvers src/Modules.symvers: $(SCST_DIR)/$(MODULE_SYMVERS)
|
||||
cp $< $@;
|
||||
|
||||
@@ -32,6 +32,17 @@ more information):
|
||||
2:0:0:0 ram000 ram001 ram002 ram003 ram004 ram005 ram006 ram007
|
||||
ram008 ram009 ram010 ram011 ram012 ram013 ram014 ram015
|
||||
|
||||
Next, set the vendor ID, product ID etc. fields via sysfs. These fields
|
||||
must be set to the following values to allow AIX initiators to recognize
|
||||
SCST devices:
|
||||
* The Vendor ID (t10_vend_id) must be set to "IBM".
|
||||
* The Product ID (prod_id) must be set either to "VDASD blkdev" for SCSI disks
|
||||
or "VOPTA blkdev" for a SCSI CD-ROM.
|
||||
* The Product Revision Level (prod_rev_lvl) must be set to "0001".
|
||||
* The Vendor Specific Information in the INQUIRY response (inq_vend_specific)
|
||||
must be set to the serial number. The serial number is available in the
|
||||
"usn" sysfs attribute.
|
||||
|
||||
After this step a LUN has to be assigned to each exported SCSI device. Some
|
||||
non-Linux initiator operating systems only accept LUN numbes that are
|
||||
multiples of 256 and require that the LUN addressing method is used.
|
||||
|
||||
@@ -1069,28 +1069,6 @@ static void handle_crq(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
static void ibmvstgt_get_product_id(const struct scst_tgt_dev *tgt_dev,
|
||||
char *buf, const int size)
|
||||
{
|
||||
WARN_ON(size != 16);
|
||||
|
||||
/*
|
||||
* AIX uses hardcoded device names. The AIX SCSI initiator even won't
|
||||
* work unless we use the names VDASD and VOPTA.
|
||||
*/
|
||||
switch (tgt_dev->dev->type) {
|
||||
case TYPE_DISK:
|
||||
memcpy(buf, "VDASD blkdev ", 16);
|
||||
break;
|
||||
case TYPE_ROM:
|
||||
memcpy(buf, "VOPTA blkdev ", 16);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, size, "(devtype %d) ", tgt_dev->dev->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract target, bus and LUN information from a 64-bit LUN in CPU-order.
|
||||
*/
|
||||
@@ -1236,12 +1214,8 @@ static struct scst_tgt_template ibmvstgt_template = {
|
||||
#else
|
||||
.sg_tablesize = SCSI_MAX_SG_SEGMENTS,
|
||||
#endif
|
||||
.vendor = "IBM ",
|
||||
.revision = "0001",
|
||||
.fake_aca = true,
|
||||
.get_product_id = ibmvstgt_get_product_id,
|
||||
.get_serial = ibmvstgt_get_serial,
|
||||
.get_vend_specific = ibmvstgt_get_serial,
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = DEFAULT_IBMVSTGT_TRACE_FLAGS,
|
||||
|
||||
+32
-12
@@ -15,9 +15,9 @@ SUBDIRS := $(shell pwd)
|
||||
|
||||
SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \
|
||||
then echo "$$PWD/../scst/include"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
SCST_DIR := $(shell if [ -e "$$PWD/../scst" ]; then echo "$$PWD/../scst/src"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
SBINDIR := $(PREFIX)/sbin
|
||||
INITDIR := /etc/init.d
|
||||
RCDIR := /etc/rc.d
|
||||
@@ -28,15 +28,27 @@ ISERTMOD := $(KMOD)/isert-scst
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER = $$KERNELRELEASE
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
else
|
||||
KVER := $(KERNELRELEASE)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
all: include/iscsi_scst_itf_ver.h progs mods
|
||||
|
||||
ISER_SYMVERS:=$(KMOD)/Module.symvers
|
||||
@@ -99,12 +111,20 @@ install: all
|
||||
@install -vD -m 644 doc/manpages/iscsi-scstd.8 $(DESTDIR)$(MANDIR)/man8/iscsi-scstd.8
|
||||
@install -vD -m 755 usr/iscsi-scst-adm $(DESTDIR)$(SBINDIR)/iscsi-scst-adm
|
||||
@install -vD -m 644 doc/manpages/iscsi-scst-adm.8 $(DESTDIR)$(MANDIR)/man8/iscsi-scst-adm.8
|
||||
@eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KDIR)/include/linux/version.h $(KDIR)/include/linux/utsrelease.h 2>/dev/null`; \
|
||||
install -vD -m 644 kernel/iscsi-scst.ko \
|
||||
$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/iscsi-scst.ko
|
||||
install -vD -m 644 kernel/isert-scst/isert-scst.ko \
|
||||
$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/isert-scst.ko
|
||||
-/sbin/depmod -aq $(KVER)
|
||||
$(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(KMOD) \
|
||||
modules_install
|
||||
$(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(ISERTMOD) \
|
||||
modules_install
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(SBINDIR)/iscsi-scstd \
|
||||
$(DESTDIR)$(MANDIR)/man5/iscsi-scstd.conf.5 \
|
||||
$(DESTDIR)$(MANDIR)/man8/iscsi-scstd.8 \
|
||||
$(DESTDIR)$(SBINDIR)/iscsi-scst-adm \
|
||||
$(DESTDIR)$(MANDIR)/man8/iscsi-scst-adm.8 \
|
||||
$(INSTALL_DIR)/iscsi-scst.ko \
|
||||
$(INSTALL_DIR)/isert-scst.ko
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null)
|
||||
ifneq ($(SCST_MOD_VERS),)
|
||||
|
||||
@@ -1584,6 +1584,8 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn,
|
||||
|
||||
buff_offs = offset;
|
||||
idx = (offset + sg[0].offset) >> PAGE_SHIFT;
|
||||
if (offset + sg[0].offset >= PAGE_SIZE)
|
||||
offset += sg[0].offset;
|
||||
offset &= ~PAGE_MASK;
|
||||
|
||||
conn->read_msg.msg_iov = conn->read_iov;
|
||||
|
||||
@@ -1403,6 +1403,8 @@ retry:
|
||||
if (sg != write_cmnd->rsp_sg) {
|
||||
offset = conn->write_offset + sg[0].offset;
|
||||
idx = offset >> PAGE_SHIFT;
|
||||
if (offset + sg[0].offset >= PAGE_SIZE)
|
||||
offset += sg[0].offset;
|
||||
offset &= ~PAGE_MASK;
|
||||
length = min(size, (int)PAGE_SIZE - offset);
|
||||
TRACE_WRITE("write_offset %d, sg_size %d, idx %d, offset %d, "
|
||||
|
||||
@@ -0,0 +1,420 @@
|
||||
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
|
||||
index 4222aff..0d2ac7d 100644
|
||||
--- a/drivers/block/drbd/drbd_receiver.c
|
||||
+++ b/drivers/block/drbd/drbd_receiver.c
|
||||
@@ -130,7 +130,7 @@ static int page_chain_free(struct page *page)
|
||||
struct page *tmp;
|
||||
int i = 0;
|
||||
page_chain_for_each_safe(page, tmp) {
|
||||
- put_page(page);
|
||||
+ net_put_page(page);
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
|
||||
index 9e56eb4..74fe728 100644
|
||||
--- a/drivers/net/macvtap.c
|
||||
+++ b/drivers/net/macvtap.c
|
||||
@@ -527,7 +527,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
|
||||
int j;
|
||||
|
||||
for (j = 0; j < num_pages; j++)
|
||||
- put_page(page[i + j]);
|
||||
+ net_put_page(page[i + j]);
|
||||
return -EFAULT;
|
||||
}
|
||||
truesize = size * PAGE_SIZE;
|
||||
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
|
||||
index 5824971..83e0eaa 100644
|
||||
--- a/drivers/net/tun.c
|
||||
+++ b/drivers/net/tun.c
|
||||
@@ -1013,7 +1013,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
|
||||
int j;
|
||||
|
||||
for (j = 0; j < num_pages; j++)
|
||||
- put_page(page[i + j]);
|
||||
+ net_put_page(page[i + j]);
|
||||
return -EFAULT;
|
||||
}
|
||||
truesize = size * PAGE_SIZE;
|
||||
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
|
||||
index 55a62ca..dcb9fdf 100644
|
||||
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
|
||||
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
|
||||
@@ -1360,7 +1360,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
|
||||
rq->buf_info[ring_idx][i].page) {
|
||||
pci_unmap_page(adapter->pdev, rxd->addr,
|
||||
rxd->len, PCI_DMA_FROMDEVICE);
|
||||
- put_page(rq->buf_info[ring_idx][i].page);
|
||||
+ net_put_page(rq->buf_info[ring_idx][i].page);
|
||||
rq->buf_info[ring_idx][i].page = NULL;
|
||||
}
|
||||
}
|
||||
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
|
||||
index 36efb41..019681c 100644
|
||||
--- a/drivers/net/xen-netback/netback.c
|
||||
+++ b/drivers/net/xen-netback/netback.c
|
||||
@@ -1292,7 +1292,7 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
|
||||
skb->truesize += txp->size;
|
||||
|
||||
/* Take an extra reference to offset xen_netbk_idx_release */
|
||||
- get_page(netbk->mmap_pages[pending_idx]);
|
||||
+ net_get_page(netbk->mmap_pages[pending_idx]);
|
||||
xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
|
||||
}
|
||||
}
|
||||
@@ -1774,7 +1774,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
|
||||
} while (!pending_tx_is_head(netbk, peek));
|
||||
|
||||
netbk->mmap_pages[pending_idx]->mapping = 0;
|
||||
- put_page(netbk->mmap_pages[pending_idx]);
|
||||
+ net_put_page(netbk->mmap_pages[pending_idx]);
|
||||
netbk->mmap_pages[pending_idx] = NULL;
|
||||
}
|
||||
|
||||
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
|
||||
index 10a9a17..1a01f46 100644
|
||||
--- a/include/linux/mm_types.h
|
||||
+++ b/include/linux/mm_types.h
|
||||
@@ -177,6 +177,17 @@ struct page {
|
||||
#ifdef LAST_NID_NOT_IN_PAGE_FLAGS
|
||||
int _last_nid;
|
||||
#endif
|
||||
+
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+ /*
|
||||
+ * Used to implement support for notification on zero-copy TCP transfer
|
||||
+ * completion. It might look as not good to have this field here and
|
||||
+ * it's better to have it in struct sk_buff, but it would make the code
|
||||
+ * much more complicated and fragile, since all skb then would have to
|
||||
+ * contain only pages with the same value in this field.
|
||||
+ */
|
||||
+ void *net_priv;
|
||||
+#endif
|
||||
}
|
||||
/*
|
||||
* The struct page can be forced to be double word aligned so that atomic ops
|
||||
diff --git a/include/linux/net.h b/include/linux/net.h
|
||||
index 65545ac..288d185 100644
|
||||
--- a/include/linux/net.h
|
||||
+++ b/include/linux/net.h
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _LINUX_NET_H
|
||||
|
||||
#include <linux/stringify.h>
|
||||
+#include <linux/mm.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
|
||||
@@ -278,6 +279,45 @@ extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
|
||||
extern int kernel_sock_shutdown(struct socket *sock,
|
||||
enum sock_shutdown_cmd how);
|
||||
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+/* Support for notification on zero-copy TCP transfer completion */
|
||||
+typedef void (*net_get_page_callback_t)(struct page *page);
|
||||
+typedef void (*net_put_page_callback_t)(struct page *page);
|
||||
+
|
||||
+extern net_get_page_callback_t net_get_page_callback;
|
||||
+extern net_put_page_callback_t net_put_page_callback;
|
||||
+
|
||||
+extern int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback);
|
||||
+
|
||||
+/*
|
||||
+ * See comment for net_set_get_put_page_callbacks() why those functions
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_get_page_callback(page);
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_put_page_callback(page);
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#else
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
|
||||
+
|
||||
#define MODULE_ALIAS_NETPROTO(proto) \
|
||||
MODULE_ALIAS("net-pf-" __stringify(proto))
|
||||
|
||||
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
||||
index ded45ec..b5c6dda 100644
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -2075,7 +2075,7 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag)
|
||||
*/
|
||||
static inline void __skb_frag_ref(skb_frag_t *frag)
|
||||
{
|
||||
- get_page(skb_frag_page(frag));
|
||||
+ net_get_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2098,7 +2098,7 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f)
|
||||
*/
|
||||
static inline void __skb_frag_unref(skb_frag_t *frag)
|
||||
{
|
||||
- put_page(skb_frag_page(frag));
|
||||
+ net_put_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/net/Kconfig b/net/Kconfig
|
||||
index 2ddc904..ec9bfbd 100644
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -74,6 +74,18 @@ config INET
|
||||
|
||||
Short answer: say Y.
|
||||
|
||||
+config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
+ bool "TCP/IP zero-copy transfer completion notification"
|
||||
+ depends on INET
|
||||
+ default SCST_ISCSI
|
||||
+ ---help---
|
||||
+ Adds support for sending a notification upon completion of a
|
||||
+ zero-copy TCP/IP transfer. This can speed up certain TCP/IP
|
||||
+ software. Currently this is only used by the iSCSI target driver
|
||||
+ iSCSI-SCST.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
if INET
|
||||
source "net/ipv4/Kconfig"
|
||||
source "net/ipv6/Kconfig"
|
||||
diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c
|
||||
index 815a224..f53c802 100644
|
||||
--- a/net/ceph/pagevec.c
|
||||
+++ b/net/ceph/pagevec.c
|
||||
@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
if (dirty)
|
||||
set_page_dirty_lock(pages[i]);
|
||||
- put_page(pages[i]);
|
||||
+ net_put_page(pages[i]);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
|
||||
index 20ee14d..e3734cf 100644
|
||||
--- a/net/core/skbuff.c
|
||||
+++ b/net/core/skbuff.c
|
||||
@@ -427,7 +427,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
|
||||
if (likely(data)) {
|
||||
skb = build_skb(data, fragsz);
|
||||
if (unlikely(!skb))
|
||||
- put_page(virt_to_head_page(data));
|
||||
+ net_put_page(virt_to_head_page(data));
|
||||
}
|
||||
} else {
|
||||
skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask,
|
||||
@@ -473,7 +473,7 @@ static void skb_clone_fraglist(struct sk_buff *skb)
|
||||
static void skb_free_head(struct sk_buff *skb)
|
||||
{
|
||||
if (skb->head_frag)
|
||||
- put_page(virt_to_head_page(skb->head));
|
||||
+ net_put_page(virt_to_head_page(skb->head));
|
||||
else
|
||||
kfree(skb->head);
|
||||
}
|
||||
@@ -793,7 +793,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
|
||||
if (!page) {
|
||||
while (head) {
|
||||
struct page *next = (struct page *)head->private;
|
||||
- put_page(head);
|
||||
+ net_put_page(head);
|
||||
head = next;
|
||||
}
|
||||
return -ENOMEM;
|
||||
@@ -1629,7 +1629,7 @@ EXPORT_SYMBOL(skb_copy_bits);
|
||||
*/
|
||||
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
|
||||
{
|
||||
- put_page(spd->pages[i]);
|
||||
+ net_put_page(spd->pages[i]);
|
||||
}
|
||||
|
||||
static struct page *linear_to_page(struct page *page, unsigned int *len,
|
||||
@@ -1682,7 +1682,7 @@ static bool spd_fill_page(struct splice_pipe_desc *spd,
|
||||
spd->partial[spd->nr_pages - 1].len += *len;
|
||||
return false;
|
||||
}
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
spd->pages[spd->nr_pages] = page;
|
||||
spd->partial[spd->nr_pages].len = *len;
|
||||
spd->partial[spd->nr_pages].offset = offset;
|
||||
@@ -2681,7 +2681,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
|
||||
copy);
|
||||
frg_cnt++;
|
||||
pfrag->offset += copy;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
|
||||
skb->truesize += copy;
|
||||
atomic_add(copy, &sk->sk_wmem_alloc);
|
||||
diff --git a/net/core/sock.c b/net/core/sock.c
|
||||
index 50a345e..f9fba8e 100644
|
||||
--- a/net/core/sock.c
|
||||
+++ b/net/core/sock.c
|
||||
@@ -1804,7 +1804,7 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag)
|
||||
}
|
||||
if (pfrag->offset < pfrag->size)
|
||||
return true;
|
||||
- put_page(pfrag->page);
|
||||
+ net_put_page(pfrag->page);
|
||||
}
|
||||
|
||||
/* We restrict high order allocations to users that can afford to wait */
|
||||
@@ -2505,7 +2505,7 @@ void sk_common_release(struct sock *sk)
|
||||
sk_refcnt_debug_release(sk);
|
||||
|
||||
if (sk->sk_frag.page) {
|
||||
- put_page(sk->sk_frag.page);
|
||||
+ net_put_page(sk->sk_frag.page);
|
||||
sk->sk_frag.page = NULL;
|
||||
}
|
||||
|
||||
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
|
||||
index 089cb9f..bc38b0e 100644
|
||||
--- a/net/ipv4/Makefile
|
||||
+++ b/net/ipv4/Makefile
|
||||
@@ -52,6 +52,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
|
||||
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
|
||||
obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
|
||||
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
|
||||
+obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o
|
||||
|
||||
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
|
||||
xfrm4_output.o
|
||||
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
|
||||
index 6ca5873..014503d2 100644
|
||||
--- a/net/ipv4/ip_output.c
|
||||
+++ b/net/ipv4/ip_output.c
|
||||
@@ -1006,7 +1006,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
@@ -1227,7 +1227,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
|
||||
if (skb_can_coalesce(skb, i, page, offset)) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
|
||||
} else if (i < MAX_SKB_FRAGS) {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, len);
|
||||
} else {
|
||||
err = -EMSGSIZE;
|
||||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
||||
index 1a2e249..b512ddc 100644
|
||||
--- a/net/ipv4/tcp.c
|
||||
+++ b/net/ipv4/tcp.c
|
||||
@@ -897,7 +897,7 @@ new_segment:
|
||||
if (can_coalesce) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
|
||||
} else {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, copy);
|
||||
}
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
|
||||
@@ -1193,7 +1193,7 @@ new_segment:
|
||||
} else {
|
||||
skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, copy);
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
pfrag->offset += copy;
|
||||
}
|
||||
diff --git a/net/ipv4/tcp_zero_copy.c b/net/ipv4/tcp_zero_copy.c
|
||||
new file mode 100644
|
||||
index 0000000..99d41fa
|
||||
--- /dev/null
|
||||
+++ b/net/ipv4/tcp_zero_copy.c
|
||||
@@ -0,0 +1,50 @@
|
||||
+/*
|
||||
+ * Support routines for TCP zero copy transmit
|
||||
+ *
|
||||
+ * Created by Vladislav Bolkhovitin
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+
|
||||
+net_get_page_callback_t net_get_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_get_page_callback);
|
||||
+
|
||||
+net_put_page_callback_t net_put_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_put_page_callback);
|
||||
+
|
||||
+/*
|
||||
+ * Caller of this function must ensure that at the moment when it's called
|
||||
+ * there are no pages in the system with net_priv field set to non-zero
|
||||
+ * value. Hence, this function, as well as net_get_page() and net_put_page(),
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback)
|
||||
+{
|
||||
+ int res = 0;
|
||||
+
|
||||
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
|
||||
+ (net_get_page_callback != get_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
|
||||
+ (net_put_page_callback != put_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ net_get_page_callback = get_callback;
|
||||
+ net_put_page_callback = put_callback;
|
||||
+
|
||||
+out:
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(net_set_get_put_page_callbacks);
|
||||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
|
||||
index b98b8e0..2df0fda 100644
|
||||
--- a/net/ipv6/ip6_output.c
|
||||
+++ b/net/ipv6/ip6_output.c
|
||||
@@ -1432,7 +1432,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
--
|
||||
1.8.4.5
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
|
||||
index cc29cd3..ba34c70 100644
|
||||
--- a/drivers/block/drbd/drbd_receiver.c
|
||||
+++ b/drivers/block/drbd/drbd_receiver.c
|
||||
@@ -130,7 +130,7 @@ static int page_chain_free(struct page *page)
|
||||
struct page *tmp;
|
||||
int i = 0;
|
||||
page_chain_for_each_safe(page, tmp) {
|
||||
- put_page(page);
|
||||
+ net_put_page(page);
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
|
||||
index 7e2788c..70d390c 100644
|
||||
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
|
||||
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
|
||||
@@ -1369,7 +1369,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
|
||||
rq->buf_info[ring_idx][i].page) {
|
||||
dma_unmap_page(&adapter->pdev->dev, rxd->addr,
|
||||
rxd->len, PCI_DMA_FROMDEVICE);
|
||||
- put_page(rq->buf_info[ring_idx][i].page);
|
||||
+ net_put_page(rq->buf_info[ring_idx][i].page);
|
||||
rq->buf_info[ring_idx][i].page = NULL;
|
||||
}
|
||||
}
|
||||
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
|
||||
index 6255850..12a6f14 100644
|
||||
--- a/drivers/net/xen-netback/netback.c
|
||||
+++ b/drivers/net/xen-netback/netback.c
|
||||
@@ -1055,7 +1055,7 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
|
||||
skb->truesize += txp->size;
|
||||
|
||||
/* Take an extra reference to offset xenvif_idx_release */
|
||||
- get_page(vif->mmap_pages[pending_idx]);
|
||||
+ net_get_page(vif->mmap_pages[pending_idx]);
|
||||
xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
|
||||
}
|
||||
}
|
||||
@@ -1525,7 +1525,7 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
|
||||
|
||||
} while (!pending_tx_is_head(vif, peek));
|
||||
|
||||
- put_page(vif->mmap_pages[pending_idx]);
|
||||
+ net_put_page(vif->mmap_pages[pending_idx]);
|
||||
vif->mmap_pages[pending_idx] = NULL;
|
||||
}
|
||||
|
||||
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
|
||||
index 8e082f1..15f10c8 100644
|
||||
--- a/include/linux/mm_types.h
|
||||
+++ b/include/linux/mm_types.h
|
||||
@@ -177,6 +177,17 @@ struct page {
|
||||
#ifdef LAST_NID_NOT_IN_PAGE_FLAGS
|
||||
int _last_nid;
|
||||
#endif
|
||||
+
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+ /*
|
||||
+ * Used to implement support for notification on zero-copy TCP transfer
|
||||
+ * completion. It might look as not good to have this field here and
|
||||
+ * it's better to have it in struct sk_buff, but it would make the code
|
||||
+ * much more complicated and fragile, since all skb then would have to
|
||||
+ * contain only pages with the same value in this field.
|
||||
+ */
|
||||
+ void *net_priv;
|
||||
+#endif
|
||||
}
|
||||
/*
|
||||
* The struct page can be forced to be double word aligned so that atomic ops
|
||||
diff --git a/include/linux/net.h b/include/linux/net.h
|
||||
index 41103f8..54c2bffb 100644
|
||||
--- a/include/linux/net.h
|
||||
+++ b/include/linux/net.h
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _LINUX_NET_H
|
||||
|
||||
#include <linux/stringify.h>
|
||||
+#include <linux/mm.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
|
||||
@@ -278,6 +279,45 @@ extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
|
||||
extern int kernel_sock_shutdown(struct socket *sock,
|
||||
enum sock_shutdown_cmd how);
|
||||
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+/* Support for notification on zero-copy TCP transfer completion */
|
||||
+typedef void (*net_get_page_callback_t)(struct page *page);
|
||||
+typedef void (*net_put_page_callback_t)(struct page *page);
|
||||
+
|
||||
+extern net_get_page_callback_t net_get_page_callback;
|
||||
+extern net_put_page_callback_t net_put_page_callback;
|
||||
+
|
||||
+extern int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback);
|
||||
+
|
||||
+/*
|
||||
+ * See comment for net_set_get_put_page_callbacks() why those functions
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_get_page_callback(page);
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_put_page_callback(page);
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#else
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
|
||||
+
|
||||
#define MODULE_ALIAS_NETPROTO(proto) \
|
||||
MODULE_ALIAS("net-pf-" __stringify(proto))
|
||||
|
||||
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
||||
index efa1649..5efff79 100644
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -1975,7 +1975,7 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag)
|
||||
*/
|
||||
static inline void __skb_frag_ref(skb_frag_t *frag)
|
||||
{
|
||||
- get_page(skb_frag_page(frag));
|
||||
+ net_get_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1998,7 +1998,7 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f)
|
||||
*/
|
||||
static inline void __skb_frag_unref(skb_frag_t *frag)
|
||||
{
|
||||
- put_page(skb_frag_page(frag));
|
||||
+ net_put_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/net/Kconfig b/net/Kconfig
|
||||
index b50dacc..88ed9df 100644
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -75,6 +75,18 @@ config INET
|
||||
|
||||
Short answer: say Y.
|
||||
|
||||
+config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
+ bool "TCP/IP zero-copy transfer completion notification"
|
||||
+ depends on INET
|
||||
+ default SCST_ISCSI
|
||||
+ ---help---
|
||||
+ Adds support for sending a notification upon completion of a
|
||||
+ zero-copy TCP/IP transfer. This can speed up certain TCP/IP
|
||||
+ software. Currently this is only used by the iSCSI target driver
|
||||
+ iSCSI-SCST.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
if INET
|
||||
source "net/ipv4/Kconfig"
|
||||
source "net/ipv6/Kconfig"
|
||||
diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c
|
||||
index 815a224..f53c802 100644
|
||||
--- a/net/ceph/pagevec.c
|
||||
+++ b/net/ceph/pagevec.c
|
||||
@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
if (dirty)
|
||||
set_page_dirty_lock(pages[i]);
|
||||
- put_page(pages[i]);
|
||||
+ net_put_page(pages[i]);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
|
||||
index 2c7baa8..3196557 100644
|
||||
--- a/net/core/skbuff.c
|
||||
+++ b/net/core/skbuff.c
|
||||
@@ -422,7 +422,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
|
||||
if (likely(data)) {
|
||||
skb = build_skb(data, fragsz);
|
||||
if (unlikely(!skb))
|
||||
- put_page(virt_to_head_page(data));
|
||||
+ net_put_page(virt_to_head_page(data));
|
||||
}
|
||||
} else {
|
||||
skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask,
|
||||
@@ -468,7 +468,7 @@ static void skb_clone_fraglist(struct sk_buff *skb)
|
||||
static void skb_free_head(struct sk_buff *skb)
|
||||
{
|
||||
if (skb->head_frag)
|
||||
- put_page(virt_to_head_page(skb->head));
|
||||
+ net_put_page(virt_to_head_page(skb->head));
|
||||
else
|
||||
kfree(skb->head);
|
||||
}
|
||||
@@ -793,7 +793,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
|
||||
if (!page) {
|
||||
while (head) {
|
||||
struct page *next = (struct page *)page_private(head);
|
||||
- put_page(head);
|
||||
+ net_put_page(head);
|
||||
head = next;
|
||||
}
|
||||
return -ENOMEM;
|
||||
@@ -1618,7 +1618,7 @@ EXPORT_SYMBOL(skb_copy_bits);
|
||||
*/
|
||||
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
|
||||
{
|
||||
- put_page(spd->pages[i]);
|
||||
+ net_put_page(spd->pages[i]);
|
||||
}
|
||||
|
||||
static struct page *linear_to_page(struct page *page, unsigned int *len,
|
||||
@@ -1671,7 +1671,7 @@ static bool spd_fill_page(struct splice_pipe_desc *spd,
|
||||
spd->partial[spd->nr_pages - 1].len += *len;
|
||||
return false;
|
||||
}
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
spd->pages[spd->nr_pages] = page;
|
||||
spd->partial[spd->nr_pages].len = *len;
|
||||
spd->partial[spd->nr_pages].offset = offset;
|
||||
@@ -2675,7 +2675,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
|
||||
copy);
|
||||
frg_cnt++;
|
||||
pfrag->offset += copy;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
|
||||
skb->truesize += copy;
|
||||
atomic_add(copy, &sk->sk_wmem_alloc);
|
||||
diff --git a/net/core/sock.c b/net/core/sock.c
|
||||
index 5cec994..c756279 100644
|
||||
--- a/net/core/sock.c
|
||||
+++ b/net/core/sock.c
|
||||
@@ -1847,7 +1847,7 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag)
|
||||
}
|
||||
if (pfrag->offset < pfrag->size)
|
||||
return true;
|
||||
- put_page(pfrag->page);
|
||||
+ net_put_page(pfrag->page);
|
||||
}
|
||||
|
||||
/* We restrict high order allocations to users that can afford to wait */
|
||||
@@ -2599,7 +2599,7 @@ void sk_common_release(struct sock *sk)
|
||||
sk_refcnt_debug_release(sk);
|
||||
|
||||
if (sk->sk_frag.page) {
|
||||
- put_page(sk->sk_frag.page);
|
||||
+ net_put_page(sk->sk_frag.page);
|
||||
sk->sk_frag.page = NULL;
|
||||
}
|
||||
|
||||
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
|
||||
index 4b81e91..b88113f 100644
|
||||
--- a/net/ipv4/Makefile
|
||||
+++ b/net/ipv4/Makefile
|
||||
@@ -53,6 +53,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
|
||||
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
|
||||
obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
|
||||
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
|
||||
+obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o
|
||||
|
||||
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
|
||||
xfrm4_output.o
|
||||
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
|
||||
index 3982eab..d37f078 100644
|
||||
--- a/net/ipv4/ip_output.c
|
||||
+++ b/net/ipv4/ip_output.c
|
||||
@@ -1003,7 +1003,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
@@ -1224,7 +1224,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
|
||||
if (skb_can_coalesce(skb, i, page, offset)) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
|
||||
} else if (i < MAX_SKB_FRAGS) {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, len);
|
||||
} else {
|
||||
err = -EMSGSIZE;
|
||||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
||||
index be5246e..a349ddd 100644
|
||||
--- a/net/ipv4/tcp.c
|
||||
+++ b/net/ipv4/tcp.c
|
||||
@@ -896,7 +896,7 @@ new_segment:
|
||||
if (can_coalesce) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
|
||||
} else {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, copy);
|
||||
}
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
|
||||
@@ -1192,7 +1192,7 @@ new_segment:
|
||||
} else {
|
||||
skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, copy);
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
pfrag->offset += copy;
|
||||
}
|
||||
diff --git a/net/ipv4/tcp_zero_copy.c b/net/ipv4/tcp_zero_copy.c
|
||||
new file mode 100644
|
||||
index 0000000..430147e
|
||||
--- /dev/null
|
||||
+++ b/net/ipv4/tcp_zero_copy.c
|
||||
@@ -0,0 +1,50 @@
|
||||
+/*
|
||||
+ * Support routines for TCP zero copy transmit
|
||||
+ *
|
||||
+ * Created by Vladislav Bolkhovitin
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+
|
||||
+net_get_page_callback_t net_get_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_get_page_callback);
|
||||
+
|
||||
+net_put_page_callback_t net_put_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_put_page_callback);
|
||||
+
|
||||
+/*
|
||||
+ * Caller of this function must ensure that at the moment when it's called
|
||||
+ * there are no pages in the system with net_priv field set to non-zero
|
||||
+ * value. Hence, this function, as well as net_get_page() and net_put_page(),
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback)
|
||||
+{
|
||||
+ int res = 0;
|
||||
+
|
||||
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
|
||||
+ (net_get_page_callback != get_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
|
||||
+ (net_put_page_callback != put_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ net_get_page_callback = get_callback;
|
||||
+ net_put_page_callback = put_callback;
|
||||
+
|
||||
+out:
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(net_set_get_put_page_callbacks);
|
||||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
|
||||
index b6fa35e..b6f3389 100644
|
||||
--- a/net/ipv6/ip6_output.c
|
||||
+++ b/net/ipv6/ip6_output.c
|
||||
@@ -1413,7 +1413,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
|
||||
index ae2e5c1..2ad9e87 100644
|
||||
--- a/net/netfilter/nfnetlink_queue_core.c
|
||||
+++ b/net/netfilter/nfnetlink_queue_core.c
|
||||
@@ -258,7 +258,7 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
|
||||
page = virt_to_head_page(from->head);
|
||||
offset = from->data - (unsigned char *)page_address(page);
|
||||
__skb_fill_page_desc(to, 0, page, offset, plen);
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
j = 1;
|
||||
len -= plen;
|
||||
}
|
||||
--
|
||||
1.8.4.5
|
||||
|
||||
@@ -0,0 +1,403 @@
|
||||
=== modified file 'drivers/block/drbd/drbd_receiver.c'
|
||||
--- old/drivers/block/drbd/drbd_receiver.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/drivers/block/drbd/drbd_receiver.c 2014-02-20 05:35:42 +0000
|
||||
@@ -130,7 +130,7 @@ static int page_chain_free(struct page *
|
||||
struct page *tmp;
|
||||
int i = 0;
|
||||
page_chain_for_each_safe(page, tmp) {
|
||||
- put_page(page);
|
||||
+ net_put_page(page);
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
|
||||
=== modified file 'drivers/net/vmxnet3/vmxnet3_drv.c'
|
||||
--- old/drivers/net/vmxnet3/vmxnet3_drv.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/drivers/net/vmxnet3/vmxnet3_drv.c 2014-02-20 05:35:42 +0000
|
||||
@@ -1369,7 +1369,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_que
|
||||
rq->buf_info[ring_idx][i].page) {
|
||||
dma_unmap_page(&adapter->pdev->dev, rxd->addr,
|
||||
rxd->len, PCI_DMA_FROMDEVICE);
|
||||
- put_page(rq->buf_info[ring_idx][i].page);
|
||||
+ net_put_page(rq->buf_info[ring_idx][i].page);
|
||||
rq->buf_info[ring_idx][i].page = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
=== modified file 'drivers/net/xen-netback/netback.c'
|
||||
--- old/drivers/net/xen-netback/netback.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/drivers/net/xen-netback/netback.c 2014-02-20 05:35:42 +0000
|
||||
@@ -1080,7 +1080,7 @@ static void xenvif_fill_frags(struct xen
|
||||
skb->truesize += txp->size;
|
||||
|
||||
/* Take an extra reference to offset xenvif_idx_release */
|
||||
- get_page(vif->mmap_pages[pending_idx]);
|
||||
+ net_get_page(vif->mmap_pages[pending_idx]);
|
||||
xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
|
||||
}
|
||||
}
|
||||
@@ -1760,7 +1760,7 @@ static void xenvif_idx_release(struct xe
|
||||
|
||||
} while (!pending_tx_is_head(vif, peek));
|
||||
|
||||
- put_page(vif->mmap_pages[pending_idx]);
|
||||
+ net_put_page(vif->mmap_pages[pending_idx]);
|
||||
vif->mmap_pages[pending_idx] = NULL;
|
||||
}
|
||||
|
||||
|
||||
=== modified file 'include/linux/mm_types.h'
|
||||
--- old/include/linux/mm_types.h 2014-02-20 05:26:12 +0000
|
||||
+++ new/include/linux/mm_types.h 2014-02-20 05:35:42 +0000
|
||||
@@ -195,6 +195,17 @@ struct page {
|
||||
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
|
||||
int _last_cpupid;
|
||||
#endif
|
||||
+
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+ /*
|
||||
+ * Used to implement support for notification on zero-copy TCP transfer
|
||||
+ * completion. It might look as not good to have this field here and
|
||||
+ * it's better to have it in struct sk_buff, but it would make the code
|
||||
+ * much more complicated and fragile, since all skb then would have to
|
||||
+ * contain only pages with the same value in this field.
|
||||
+ */
|
||||
+ void *net_priv;
|
||||
+#endif
|
||||
}
|
||||
/*
|
||||
* The struct page can be forced to be double word aligned so that atomic ops
|
||||
|
||||
=== modified file 'include/linux/net.h'
|
||||
--- old/include/linux/net.h 2014-02-20 05:26:12 +0000
|
||||
+++ new/include/linux/net.h 2014-02-20 05:35:42 +0000
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _LINUX_NET_H
|
||||
|
||||
#include <linux/stringify.h>
|
||||
+#include <linux/mm.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
|
||||
@@ -295,6 +296,45 @@ int kernel_sendpage(struct socket *sock,
|
||||
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
|
||||
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
|
||||
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+/* Support for notification on zero-copy TCP transfer completion */
|
||||
+typedef void (*net_get_page_callback_t)(struct page *page);
|
||||
+typedef void (*net_put_page_callback_t)(struct page *page);
|
||||
+
|
||||
+extern net_get_page_callback_t net_get_page_callback;
|
||||
+extern net_put_page_callback_t net_put_page_callback;
|
||||
+
|
||||
+extern int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback);
|
||||
+
|
||||
+/*
|
||||
+ * See comment for net_set_get_put_page_callbacks() why those functions
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_get_page_callback(page);
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_put_page_callback(page);
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#else
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
|
||||
+
|
||||
#define MODULE_ALIAS_NETPROTO(proto) \
|
||||
MODULE_ALIAS("net-pf-" __stringify(proto))
|
||||
|
||||
|
||||
=== modified file 'include/linux/skbuff.h'
|
||||
--- old/include/linux/skbuff.h 2014-02-20 05:26:12 +0000
|
||||
+++ new/include/linux/skbuff.h 2014-02-20 05:35:42 +0000
|
||||
@@ -1974,7 +1974,7 @@ static inline struct page *skb_frag_page
|
||||
*/
|
||||
static inline void __skb_frag_ref(skb_frag_t *frag)
|
||||
{
|
||||
- get_page(skb_frag_page(frag));
|
||||
+ net_get_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1997,7 +1997,7 @@ static inline void skb_frag_ref(struct s
|
||||
*/
|
||||
static inline void __skb_frag_unref(skb_frag_t *frag)
|
||||
{
|
||||
- put_page(skb_frag_page(frag));
|
||||
+ net_put_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
=== modified file 'net/Kconfig'
|
||||
--- old/net/Kconfig 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/Kconfig 2014-02-20 05:35:42 +0000
|
||||
@@ -75,6 +75,18 @@ config INET
|
||||
|
||||
Short answer: say Y.
|
||||
|
||||
+config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
+ bool "TCP/IP zero-copy transfer completion notification"
|
||||
+ depends on INET
|
||||
+ default SCST_ISCSI
|
||||
+ ---help---
|
||||
+ Adds support for sending a notification upon completion of a
|
||||
+ zero-copy TCP/IP transfer. This can speed up certain TCP/IP
|
||||
+ software. Currently this is only used by the iSCSI target driver
|
||||
+ iSCSI-SCST.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
if INET
|
||||
source "net/ipv4/Kconfig"
|
||||
source "net/ipv6/Kconfig"
|
||||
|
||||
=== modified file 'net/ceph/pagevec.c'
|
||||
--- old/net/ceph/pagevec.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/ceph/pagevec.c 2014-02-20 05:35:42 +0000
|
||||
@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
if (dirty)
|
||||
set_page_dirty_lock(pages[i]);
|
||||
- put_page(pages[i]);
|
||||
+ net_put_page(pages[i]);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
=== modified file 'net/core/skbuff.c'
|
||||
--- old/net/core/skbuff.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/core/skbuff.c 2014-02-20 05:35:42 +0000
|
||||
@@ -422,7 +422,7 @@ struct sk_buff *__netdev_alloc_skb(struc
|
||||
if (likely(data)) {
|
||||
skb = build_skb(data, fragsz);
|
||||
if (unlikely(!skb))
|
||||
- put_page(virt_to_head_page(data));
|
||||
+ net_put_page(virt_to_head_page(data));
|
||||
}
|
||||
} else {
|
||||
skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask,
|
||||
@@ -480,7 +480,7 @@ static void skb_clone_fraglist(struct sk
|
||||
static void skb_free_head(struct sk_buff *skb)
|
||||
{
|
||||
if (skb->head_frag)
|
||||
- put_page(virt_to_head_page(skb->head));
|
||||
+ net_put_page(virt_to_head_page(skb->head));
|
||||
else
|
||||
kfree(skb->head);
|
||||
}
|
||||
@@ -805,7 +805,7 @@ int skb_copy_ubufs(struct sk_buff *skb,
|
||||
if (!page) {
|
||||
while (head) {
|
||||
struct page *next = (struct page *)page_private(head);
|
||||
- put_page(head);
|
||||
+ net_put_page(head);
|
||||
head = next;
|
||||
}
|
||||
return -ENOMEM;
|
||||
@@ -1648,7 +1648,7 @@ EXPORT_SYMBOL(skb_copy_bits);
|
||||
*/
|
||||
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
|
||||
{
|
||||
- put_page(spd->pages[i]);
|
||||
+ net_put_page(spd->pages[i]);
|
||||
}
|
||||
|
||||
static struct page *linear_to_page(struct page *page, unsigned int *len,
|
||||
@@ -1701,7 +1701,7 @@ static bool spd_fill_page(struct splice_
|
||||
spd->partial[spd->nr_pages - 1].len += *len;
|
||||
return false;
|
||||
}
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
spd->pages[spd->nr_pages] = page;
|
||||
spd->partial[spd->nr_pages].len = *len;
|
||||
spd->partial[spd->nr_pages].offset = offset;
|
||||
@@ -2716,7 +2716,7 @@ int skb_append_datato_frags(struct sock
|
||||
copy);
|
||||
frg_cnt++;
|
||||
pfrag->offset += copy;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
|
||||
skb->truesize += copy;
|
||||
atomic_add(copy, &sk->sk_wmem_alloc);
|
||||
|
||||
=== modified file 'net/core/sock.c'
|
||||
--- old/net/core/sock.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/core/sock.c 2014-02-20 05:35:42 +0000
|
||||
@@ -1862,7 +1862,7 @@ bool skb_page_frag_refill(unsigned int s
|
||||
}
|
||||
if (pfrag->offset + sz <= pfrag->size)
|
||||
return true;
|
||||
- put_page(pfrag->page);
|
||||
+ net_put_page(pfrag->page);
|
||||
}
|
||||
|
||||
/* We restrict high order allocations to users that can afford to wait */
|
||||
@@ -2624,7 +2624,7 @@ void sk_common_release(struct sock *sk)
|
||||
sk_refcnt_debug_release(sk);
|
||||
|
||||
if (sk->sk_frag.page) {
|
||||
- put_page(sk->sk_frag.page);
|
||||
+ net_put_page(sk->sk_frag.page);
|
||||
sk->sk_frag.page = NULL;
|
||||
}
|
||||
|
||||
|
||||
=== modified file 'net/ipv4/Makefile'
|
||||
--- old/net/ipv4/Makefile 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/ipv4/Makefile 2014-02-20 05:35:42 +0000
|
||||
@@ -53,6 +53,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.
|
||||
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
|
||||
obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
|
||||
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
|
||||
+obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o
|
||||
|
||||
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
|
||||
xfrm4_output.o
|
||||
|
||||
=== modified file 'net/ipv4/ip_output.c'
|
||||
--- old/net/ipv4/ip_output.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/ipv4/ip_output.c 2014-02-20 05:35:42 +0000
|
||||
@@ -1005,7 +1005,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
@@ -1231,7 +1231,7 @@ ssize_t ip_append_page(struct sock *sk,
|
||||
if (skb_can_coalesce(skb, i, page, offset)) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
|
||||
} else if (i < MAX_SKB_FRAGS) {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, len);
|
||||
} else {
|
||||
err = -EMSGSIZE;
|
||||
|
||||
=== modified file 'net/ipv4/tcp.c'
|
||||
--- old/net/ipv4/tcp.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/ipv4/tcp.c 2014-02-20 05:35:42 +0000
|
||||
@@ -898,7 +898,7 @@ new_segment:
|
||||
if (can_coalesce) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
|
||||
} else {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, copy);
|
||||
}
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
|
||||
@@ -1194,7 +1194,7 @@ new_segment:
|
||||
} else {
|
||||
skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, copy);
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
pfrag->offset += copy;
|
||||
}
|
||||
|
||||
=== added file 'net/ipv4/tcp_zero_copy.c'
|
||||
--- old/net/ipv4/tcp_zero_copy.c 1970-01-01 00:00:00 +0000
|
||||
+++ new/net/ipv4/tcp_zero_copy.c 2014-02-20 05:35:42 +0000
|
||||
@@ -0,0 +1,50 @@
|
||||
+/*
|
||||
+ * Support routines for TCP zero copy transmit
|
||||
+ *
|
||||
+ * Created by Vladislav Bolkhovitin
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+
|
||||
+net_get_page_callback_t net_get_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_get_page_callback);
|
||||
+
|
||||
+net_put_page_callback_t net_put_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_put_page_callback);
|
||||
+
|
||||
+/*
|
||||
+ * Caller of this function must ensure that at the moment when it's called
|
||||
+ * there are no pages in the system with net_priv field set to non-zero
|
||||
+ * value. Hence, this function, as well as net_get_page() and net_put_page(),
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback)
|
||||
+{
|
||||
+ int res = 0;
|
||||
+
|
||||
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
|
||||
+ (net_get_page_callback != get_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
|
||||
+ (net_put_page_callback != put_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ net_get_page_callback = get_callback;
|
||||
+ net_put_page_callback = put_callback;
|
||||
+
|
||||
+out:
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(net_set_get_put_page_callbacks);
|
||||
|
||||
=== modified file 'net/ipv6/ip6_output.c'
|
||||
--- old/net/ipv6/ip6_output.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/ipv6/ip6_output.c 2014-02-20 05:35:42 +0000
|
||||
@@ -1431,7 +1431,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
|
||||
=== modified file 'net/netfilter/nfnetlink_queue_core.c'
|
||||
--- old/net/netfilter/nfnetlink_queue_core.c 2014-02-20 05:26:12 +0000
|
||||
+++ new/net/netfilter/nfnetlink_queue_core.c 2014-02-20 05:35:42 +0000
|
||||
@@ -258,7 +258,7 @@ nfqnl_zcopy(struct sk_buff *to, const st
|
||||
page = virt_to_head_page(from->head);
|
||||
offset = from->data - (unsigned char *)page_address(page);
|
||||
__skb_fill_page_desc(to, 0, page, offset, plen);
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
j = 1;
|
||||
len -= plen;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
=== modified file 'drivers/block/drbd/drbd_receiver.c'
|
||||
--- old/drivers/block/drbd/drbd_receiver.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/drivers/block/drbd/drbd_receiver.c 2014-01-30 01:02:34 +0000
|
||||
@@ -130,7 +130,7 @@ static int page_chain_free(struct page *
|
||||
struct page *tmp;
|
||||
int i = 0;
|
||||
page_chain_for_each_safe(page, tmp) {
|
||||
- put_page(page);
|
||||
+ net_put_page(page);
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
|
||||
=== modified file 'drivers/net/vmxnet3/vmxnet3_drv.c'
|
||||
--- old/drivers/net/vmxnet3/vmxnet3_drv.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/drivers/net/vmxnet3/vmxnet3_drv.c 2014-01-30 01:02:34 +0000
|
||||
@@ -1369,7 +1369,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_que
|
||||
rq->buf_info[ring_idx][i].page) {
|
||||
dma_unmap_page(&adapter->pdev->dev, rxd->addr,
|
||||
rxd->len, PCI_DMA_FROMDEVICE);
|
||||
- put_page(rq->buf_info[ring_idx][i].page);
|
||||
+ net_put_page(rq->buf_info[ring_idx][i].page);
|
||||
rq->buf_info[ring_idx][i].page = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
=== modified file 'drivers/net/xen-netback/netback.c'
|
||||
--- old/drivers/net/xen-netback/netback.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/drivers/net/xen-netback/netback.c 2014-01-30 01:02:34 +0000
|
||||
@@ -1080,7 +1080,7 @@ static void xenvif_fill_frags(struct xen
|
||||
skb->truesize += txp->size;
|
||||
|
||||
/* Take an extra reference to offset xenvif_idx_release */
|
||||
- get_page(vif->mmap_pages[pending_idx]);
|
||||
+ net_get_page(vif->mmap_pages[pending_idx]);
|
||||
xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
|
||||
}
|
||||
}
|
||||
@@ -1760,7 +1760,7 @@ static void xenvif_idx_release(struct xe
|
||||
|
||||
} while (!pending_tx_is_head(vif, peek));
|
||||
|
||||
- put_page(vif->mmap_pages[pending_idx]);
|
||||
+ net_put_page(vif->mmap_pages[pending_idx]);
|
||||
vif->mmap_pages[pending_idx] = NULL;
|
||||
}
|
||||
|
||||
|
||||
=== modified file 'include/linux/mm_types.h'
|
||||
--- old/include/linux/mm_types.h 2014-01-30 00:25:53 +0000
|
||||
+++ new/include/linux/mm_types.h 2014-01-30 01:02:34 +0000
|
||||
@@ -195,6 +195,17 @@ struct page {
|
||||
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
|
||||
int _last_cpupid;
|
||||
#endif
|
||||
+
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+ /*
|
||||
+ * Used to implement support for notification on zero-copy TCP transfer
|
||||
+ * completion. It might look as not good to have this field here and
|
||||
+ * it's better to have it in struct sk_buff, but it would make the code
|
||||
+ * much more complicated and fragile, since all skb then would have to
|
||||
+ * contain only pages with the same value in this field.
|
||||
+ */
|
||||
+ void *net_priv;
|
||||
+#endif
|
||||
}
|
||||
/*
|
||||
* The struct page can be forced to be double word aligned so that atomic ops
|
||||
|
||||
=== modified file 'include/linux/net.h'
|
||||
--- old/include/linux/net.h 2014-01-30 00:25:53 +0000
|
||||
+++ new/include/linux/net.h 2014-01-30 01:02:34 +0000
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _LINUX_NET_H
|
||||
|
||||
#include <linux/stringify.h>
|
||||
+#include <linux/mm.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
|
||||
@@ -295,6 +296,45 @@ int kernel_sendpage(struct socket *sock,
|
||||
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
|
||||
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
|
||||
|
||||
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||
+/* Support for notification on zero-copy TCP transfer completion */
|
||||
+typedef void (*net_get_page_callback_t)(struct page *page);
|
||||
+typedef void (*net_put_page_callback_t)(struct page *page);
|
||||
+
|
||||
+extern net_get_page_callback_t net_get_page_callback;
|
||||
+extern net_put_page_callback_t net_put_page_callback;
|
||||
+
|
||||
+extern int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback);
|
||||
+
|
||||
+/*
|
||||
+ * See comment for net_set_get_put_page_callbacks() why those functions
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_get_page_callback(page);
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ if (page->net_priv != 0)
|
||||
+ net_put_page_callback(page);
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#else
|
||||
+static inline void net_get_page(struct page *page)
|
||||
+{
|
||||
+ get_page(page);
|
||||
+}
|
||||
+static inline void net_put_page(struct page *page)
|
||||
+{
|
||||
+ put_page(page);
|
||||
+}
|
||||
+#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
|
||||
+
|
||||
#define MODULE_ALIAS_NETPROTO(proto) \
|
||||
MODULE_ALIAS("net-pf-" __stringify(proto))
|
||||
|
||||
|
||||
=== modified file 'include/linux/skbuff.h'
|
||||
--- old/include/linux/skbuff.h 2014-01-30 00:25:53 +0000
|
||||
+++ new/include/linux/skbuff.h 2014-01-30 01:02:34 +0000
|
||||
@@ -1974,7 +1974,7 @@ static inline struct page *skb_frag_page
|
||||
*/
|
||||
static inline void __skb_frag_ref(skb_frag_t *frag)
|
||||
{
|
||||
- get_page(skb_frag_page(frag));
|
||||
+ net_get_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1997,7 +1997,7 @@ static inline void skb_frag_ref(struct s
|
||||
*/
|
||||
static inline void __skb_frag_unref(skb_frag_t *frag)
|
||||
{
|
||||
- put_page(skb_frag_page(frag));
|
||||
+ net_put_page(skb_frag_page(frag));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
=== modified file 'net/Kconfig'
|
||||
--- old/net/Kconfig 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/Kconfig 2014-01-30 01:02:34 +0000
|
||||
@@ -75,6 +75,18 @@ config INET
|
||||
|
||||
Short answer: say Y.
|
||||
|
||||
+config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
||||
+ bool "TCP/IP zero-copy transfer completion notification"
|
||||
+ depends on INET
|
||||
+ default SCST_ISCSI
|
||||
+ ---help---
|
||||
+ Adds support for sending a notification upon completion of a
|
||||
+ zero-copy TCP/IP transfer. This can speed up certain TCP/IP
|
||||
+ software. Currently this is only used by the iSCSI target driver
|
||||
+ iSCSI-SCST.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
if INET
|
||||
source "net/ipv4/Kconfig"
|
||||
source "net/ipv6/Kconfig"
|
||||
|
||||
=== modified file 'net/ceph/pagevec.c'
|
||||
--- old/net/ceph/pagevec.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/ceph/pagevec.c 2014-01-30 01:02:34 +0000
|
||||
@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
if (dirty)
|
||||
set_page_dirty_lock(pages[i]);
|
||||
- put_page(pages[i]);
|
||||
+ net_put_page(pages[i]);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
=== modified file 'net/core/skbuff.c'
|
||||
--- old/net/core/skbuff.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/core/skbuff.c 2014-01-30 01:02:34 +0000
|
||||
@@ -77,13 +77,13 @@ static struct kmem_cache *skbuff_fclone_
|
||||
static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
|
||||
struct pipe_buffer *buf)
|
||||
{
|
||||
- put_page(buf->page);
|
||||
+ net_put_page(buf->page);
|
||||
}
|
||||
|
||||
static void sock_pipe_buf_get(struct pipe_inode_info *pipe,
|
||||
struct pipe_buffer *buf)
|
||||
{
|
||||
- get_page(buf->page);
|
||||
+ net_get_page(buf->page);
|
||||
}
|
||||
|
||||
static int sock_pipe_buf_steal(struct pipe_inode_info *pipe,
|
||||
@@ -452,7 +452,7 @@ struct sk_buff *__netdev_alloc_skb(struc
|
||||
if (likely(data)) {
|
||||
skb = build_skb(data, fragsz);
|
||||
if (unlikely(!skb))
|
||||
- put_page(virt_to_head_page(data));
|
||||
+ net_put_page(virt_to_head_page(data));
|
||||
}
|
||||
} else {
|
||||
skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask,
|
||||
@@ -510,7 +510,7 @@ static void skb_clone_fraglist(struct sk
|
||||
static void skb_free_head(struct sk_buff *skb)
|
||||
{
|
||||
if (skb->head_frag)
|
||||
- put_page(virt_to_head_page(skb->head));
|
||||
+ net_put_page(virt_to_head_page(skb->head));
|
||||
else
|
||||
kfree(skb->head);
|
||||
}
|
||||
@@ -835,7 +835,7 @@ int skb_copy_ubufs(struct sk_buff *skb,
|
||||
if (!page) {
|
||||
while (head) {
|
||||
struct page *next = (struct page *)page_private(head);
|
||||
- put_page(head);
|
||||
+ net_put_page(head);
|
||||
head = next;
|
||||
}
|
||||
return -ENOMEM;
|
||||
@@ -1678,7 +1678,7 @@ EXPORT_SYMBOL(skb_copy_bits);
|
||||
*/
|
||||
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
|
||||
{
|
||||
- put_page(spd->pages[i]);
|
||||
+ net_put_page(spd->pages[i]);
|
||||
}
|
||||
|
||||
static struct page *linear_to_page(struct page *page, unsigned int *len,
|
||||
@@ -1731,7 +1731,7 @@ static bool spd_fill_page(struct splice_
|
||||
spd->partial[spd->nr_pages - 1].len += *len;
|
||||
return false;
|
||||
}
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
spd->pages[spd->nr_pages] = page;
|
||||
spd->partial[spd->nr_pages].len = *len;
|
||||
spd->partial[spd->nr_pages].offset = offset;
|
||||
@@ -2746,7 +2746,7 @@ int skb_append_datato_frags(struct sock
|
||||
copy);
|
||||
frg_cnt++;
|
||||
pfrag->offset += copy;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
|
||||
skb->truesize += copy;
|
||||
atomic_add(copy, &sk->sk_wmem_alloc);
|
||||
|
||||
=== modified file 'net/core/sock.c'
|
||||
--- old/net/core/sock.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/core/sock.c 2014-01-30 01:02:34 +0000
|
||||
@@ -1862,7 +1862,7 @@ bool skb_page_frag_refill(unsigned int s
|
||||
}
|
||||
if (pfrag->offset + sz <= pfrag->size)
|
||||
return true;
|
||||
- put_page(pfrag->page);
|
||||
+ net_put_page(pfrag->page);
|
||||
}
|
||||
|
||||
/* We restrict high order allocations to users that can afford to wait */
|
||||
@@ -2624,7 +2624,7 @@ void sk_common_release(struct sock *sk)
|
||||
sk_refcnt_debug_release(sk);
|
||||
|
||||
if (sk->sk_frag.page) {
|
||||
- put_page(sk->sk_frag.page);
|
||||
+ net_put_page(sk->sk_frag.page);
|
||||
sk->sk_frag.page = NULL;
|
||||
}
|
||||
|
||||
|
||||
=== modified file 'net/ipv4/Makefile'
|
||||
--- old/net/ipv4/Makefile 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/ipv4/Makefile 2014-01-30 01:02:34 +0000
|
||||
@@ -53,6 +53,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.
|
||||
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
|
||||
obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
|
||||
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
|
||||
+obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o
|
||||
|
||||
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
|
||||
xfrm4_output.o
|
||||
|
||||
=== modified file 'net/ipv4/ip_output.c'
|
||||
--- old/net/ipv4/ip_output.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/ipv4/ip_output.c 2014-01-30 01:02:34 +0000
|
||||
@@ -1005,7 +1005,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
@@ -1231,7 +1231,7 @@ ssize_t ip_append_page(struct sock *sk,
|
||||
if (skb_can_coalesce(skb, i, page, offset)) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
|
||||
} else if (i < MAX_SKB_FRAGS) {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, len);
|
||||
} else {
|
||||
err = -EMSGSIZE;
|
||||
|
||||
=== modified file 'net/ipv4/tcp.c'
|
||||
--- old/net/ipv4/tcp.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/ipv4/tcp.c 2014-01-30 01:02:34 +0000
|
||||
@@ -898,7 +898,7 @@ new_segment:
|
||||
if (can_coalesce) {
|
||||
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
|
||||
} else {
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
skb_fill_page_desc(skb, i, page, offset, copy);
|
||||
}
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
|
||||
@@ -1194,7 +1194,7 @@ new_segment:
|
||||
} else {
|
||||
skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, copy);
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
pfrag->offset += copy;
|
||||
}
|
||||
|
||||
=== added file 'net/ipv4/tcp_zero_copy.c'
|
||||
--- old/net/ipv4/tcp_zero_copy.c 1970-01-01 00:00:00 +0000
|
||||
+++ new/net/ipv4/tcp_zero_copy.c 2014-01-30 01:02:34 +0000
|
||||
@@ -0,0 +1,50 @@
|
||||
+/*
|
||||
+ * Support routines for TCP zero copy transmit
|
||||
+ *
|
||||
+ * Created by Vladislav Bolkhovitin
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+
|
||||
+net_get_page_callback_t net_get_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_get_page_callback);
|
||||
+
|
||||
+net_put_page_callback_t net_put_page_callback __read_mostly;
|
||||
+EXPORT_SYMBOL_GPL(net_put_page_callback);
|
||||
+
|
||||
+/*
|
||||
+ * Caller of this function must ensure that at the moment when it's called
|
||||
+ * there are no pages in the system with net_priv field set to non-zero
|
||||
+ * value. Hence, this function, as well as net_get_page() and net_put_page(),
|
||||
+ * don't need any protection.
|
||||
+ */
|
||||
+int net_set_get_put_page_callbacks(
|
||||
+ net_get_page_callback_t get_callback,
|
||||
+ net_put_page_callback_t put_callback)
|
||||
+{
|
||||
+ int res = 0;
|
||||
+
|
||||
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
|
||||
+ (net_get_page_callback != get_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
|
||||
+ (net_put_page_callback != put_callback)) {
|
||||
+ res = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ net_get_page_callback = get_callback;
|
||||
+ net_put_page_callback = put_callback;
|
||||
+
|
||||
+out:
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(net_set_get_put_page_callbacks);
|
||||
|
||||
=== modified file 'net/ipv6/ip6_output.c'
|
||||
--- old/net/ipv6/ip6_output.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/ipv6/ip6_output.c 2014-01-30 01:02:34 +0000
|
||||
@@ -1431,7 +1431,7 @@ alloc_new_skb:
|
||||
__skb_fill_page_desc(skb, i, pfrag->page,
|
||||
pfrag->offset, 0);
|
||||
skb_shinfo(skb)->nr_frags = ++i;
|
||||
- get_page(pfrag->page);
|
||||
+ net_get_page(pfrag->page);
|
||||
}
|
||||
copy = min_t(int, copy, pfrag->size - pfrag->offset);
|
||||
if (getfrag(from,
|
||||
|
||||
=== modified file 'net/netfilter/nfnetlink_queue_core.c'
|
||||
--- old/net/netfilter/nfnetlink_queue_core.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/net/netfilter/nfnetlink_queue_core.c 2014-01-30 01:02:34 +0000
|
||||
@@ -258,7 +258,7 @@ nfqnl_zcopy(struct sk_buff *to, const st
|
||||
page = virt_to_head_page(from->head);
|
||||
offset = from->data - (unsigned char *)page_address(page);
|
||||
__skb_fill_page_desc(to, 0, page, offset, plen);
|
||||
- get_page(page);
|
||||
+ net_get_page(page);
|
||||
j = 1;
|
||||
len -= plen;
|
||||
}
|
||||
|
||||
+19
-3
@@ -38,18 +38,33 @@ EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
else
|
||||
KVER := $(KERNELRELEASE)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
LSI_INC_DIR := $(KDIR)/drivers/message/fusion
|
||||
EXTRA_CFLAGS += -I$(LSI_INC_DIR)
|
||||
|
||||
ifneq ($(PATCHLEVEL),)
|
||||
obj-m += mpt_scst.o
|
||||
else
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
all: Modules.symvers Module.symvers
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m
|
||||
@@ -60,7 +75,6 @@ tgt: Modules.symvers Module.symvers
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
modules_install
|
||||
-/sbin/depmod -a
|
||||
|
||||
SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null)
|
||||
ifneq ($(SCST_MOD_VERS),)
|
||||
@@ -81,7 +95,9 @@ endif
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/mpt_scst.ko
|
||||
-/sbin/depmod -a
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
+21
-7
@@ -31,13 +31,25 @@ endif
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
else
|
||||
KVER := $(KERNELRELEASE)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
export PWD := $(shell pwd)
|
||||
export LIBSAS := m
|
||||
|
||||
@@ -49,11 +61,10 @@ SCST_DIR := $(shell pwd)/../scst/src
|
||||
EXTRA_CFLAGS += -I$(SCST_INC_DIR)
|
||||
|
||||
EXTRA_CFLAGS += -DSUPPORT_TARGET
|
||||
MODULE_NAME = mvsas_tgt
|
||||
|
||||
EXTRA_CFLAGS += -DMV_DEBUG
|
||||
|
||||
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
#EXTRA_CFLAGS += -DCONFIG_SCST_TRACING
|
||||
#EXTRA_CFLAGS += -DDEBUG_WORK_IN_THREAD
|
||||
@@ -68,6 +79,8 @@ mvsas-y := mv_init.o \
|
||||
mv_94xx.o \
|
||||
mv_spi.o
|
||||
else
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
all: Modules.symvers Module.symvers
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m
|
||||
|
||||
@@ -77,12 +90,11 @@ tgt: Modules.symvers Module.symvers
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
modules_install
|
||||
-depmod -a $(KVER)
|
||||
|
||||
ins:
|
||||
./config
|
||||
insmod mvsas.ko
|
||||
|
||||
|
||||
SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null)
|
||||
ifneq ($(SCST_MOD_VERS),)
|
||||
Modules.symvers: $(SCST_DIR)/Modules.symvers
|
||||
@@ -101,8 +113,10 @@ else
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/$(MODULE_NAME).ko
|
||||
-/sbin/depmod -a $(KVER)
|
||||
rm -f $(INSTALL_DIR)/mvsas.ko
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ note:
|
||||
2. In example "add 2:0:0:0 1" the '1' is the LUN in the target, LUN 0 must
|
||||
exist with a target.
|
||||
3. When one device is added to target disk group, target driver will notify
|
||||
initator the changing of the phy mode and arriving of the disk, but some
|
||||
initiator the changing of the phy mode and arriving of the disk, but some
|
||||
initiator driver don't support phy mode changing well, so 'rmmod' and
|
||||
'modprobe'/'insmod' the initiator driver is neccessary.
|
||||
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
ABT_DETAILS="x86_64"
|
||||
ABT_JOBS=5
|
||||
ABT_KERNELS=" \
|
||||
3.12.9 \
|
||||
3.13.5 \
|
||||
3.12.13-nc \
|
||||
3.11.10-nc \
|
||||
3.10.28-nc \
|
||||
3.10.32-nc \
|
||||
3.9.11-nc \
|
||||
3.8.13-nc \
|
||||
3.7.10-nc \
|
||||
3.6.11-nc \
|
||||
3.5.7-nc \
|
||||
3.4.77-nc \
|
||||
3.4.81-nc \
|
||||
3.3.8-nc \
|
||||
3.2.53-nc \
|
||||
3.1.10-nc \
|
||||
|
||||
+17
-4
@@ -16,6 +16,7 @@ extraclean: clean
|
||||
.PHONY: clean extraclean
|
||||
|
||||
else
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
@@ -32,12 +33,23 @@ endif
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
ifneq ($(PATCHLEVEL),)
|
||||
obj-m := qla2xxx_scst.o
|
||||
qla2xxx_scst-objs := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
|
||||
@@ -50,11 +62,12 @@ all:
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
modules_install
|
||||
-/sbin/depmod -aq $(KVER)
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/qla2xxxt.ko
|
||||
-/sbin/depmod -a $(KVER)
|
||||
rm -f $(INSTALL_DIR)/qla2xxx_scst.ko
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
@@ -159,7 +159,7 @@ Summary of changes between versions 0.9.3.4 and 0.9.3.5
|
||||
-------------------------------------------------------
|
||||
Patch vs: qla2xxx v8.01.03-k (in kernels 2.6.15.x)
|
||||
|
||||
- Reset chip when switching from initiator to initator/target and back
|
||||
- Reset chip when switching from initiator to initiator/target and back
|
||||
implemented
|
||||
|
||||
- Use 2K loop_id's for 23xx chips and thus change how sessions are
|
||||
|
||||
@@ -27,16 +27,10 @@
|
||||
# - install and uninstall must be made as root
|
||||
#
|
||||
|
||||
ifndef PREFIX
|
||||
PREFIX=/usr/local
|
||||
endif
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
EXTRA_CFLAGS += -I$(SCST_INC_DIR)
|
||||
|
||||
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
|
||||
|
||||
EXTRA_CFLAGS += -W -Wno-unused-parameter -Wno-missing-field-initializers
|
||||
|
||||
EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
|
||||
@@ -47,13 +41,25 @@ EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
else
|
||||
KVER := $(KERNELRELEASE)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_2X_MODULE),)
|
||||
QLA2XXX_INC_DIR := $(KDIR)/drivers/scsi/qla2xxx
|
||||
else
|
||||
@@ -69,13 +75,20 @@ ifneq ($(PATCHLEVEL),)
|
||||
obj-m := qla2x00tgt.o
|
||||
qla2x00tgt-objs := qla2x00t.o
|
||||
else
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
ifndef PREFIX
|
||||
PREFIX=/usr/local
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
SCST_INC_DIR := $(shell if [ -e "$$PWD/../../scst" ]; \
|
||||
then echo "$$PWD/../../scst/include"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
SCST_DIR := $(shell if [ -e "$$PWD/../../scst" ]; \
|
||||
then echo "$$PWD/../../scst/src"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
|
||||
ifneq ($(BUILD_2X_MODULE),)
|
||||
# We need to make qla2xxx_scst before Module.symvers
|
||||
@@ -93,14 +106,13 @@ ifneq ($(BUILD_2X_MODULE),)
|
||||
endif
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
SCST_INC_DIR=$(SCST_INC_DIR) modules_install
|
||||
-/sbin/depmod -a $(KVER)
|
||||
|
||||
uninstall:
|
||||
ifneq ($(BUILD_2X_MODULE),)
|
||||
$(MAKE) SUBDIRS=$(QLA2XXX_DIR) -C $(QLA2XXX_DIR) $@
|
||||
endif
|
||||
rm -f $(INSTALL_DIR)/qla2[23x]00tgt.ko
|
||||
-/sbin/depmod -a $(KVER)
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
ifneq ($(BUILD_2X_MODULE),)
|
||||
qla2xxx_scst:
|
||||
@@ -131,6 +143,7 @@ else
|
||||
.PHONY: Module.symvers
|
||||
endif
|
||||
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
ccflags-y += -Idrivers/scsi/qla2xxx
|
||||
|
||||
qla2x00tgt-y := qla2x00t.o
|
||||
|
||||
obj-$(CONFIG_SCST_QLA_TGT_ADDON) += qla2x00tgt.o
|
||||
@@ -36,9 +36,19 @@ qla2x00_poll(scsi_qla_host_t *ha)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CONFIG_PREEMPT_RT_FULL
|
||||
local_irq_save_nort(flags);
|
||||
#else
|
||||
local_irq_save(flags);
|
||||
#endif
|
||||
|
||||
ha->isp_ops->intr_handler(0, ha);
|
||||
|
||||
#ifdef CONFIG_PREEMPT_RT_FULL
|
||||
local_irq_restore_nort(flags);
|
||||
#else
|
||||
local_irq_restore(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline__ scsi_qla_host_t *
|
||||
|
||||
+2
-2
@@ -112,8 +112,8 @@ static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
|
||||
int ql2xfdmienable=1;
|
||||
module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
|
||||
MODULE_PARM_DESC(ql2xfdmienable,
|
||||
"Enables FDMI registratons "
|
||||
"Default is 0 - no FDMI. 1 - perfom FDMI.");
|
||||
"Enables FDMI registrations "
|
||||
"Default is 1 - perform FDMI. 0 - no FDMI.");
|
||||
|
||||
#define MAX_Q_DEPTH 32
|
||||
static int ql2xmaxqdepth = MAX_Q_DEPTH;
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ activating channels/LUNs in /proc/scsi_tgt/qla_isp/N .
|
||||
|
||||
The driver can also work as both a target and an initiator simultaneously, but
|
||||
this will probably only function for P2P connections. To make the driver work
|
||||
as a target/initator on one port with a FC switch, you can use N_PORT ID
|
||||
as a target/initiator on one port with a FC switch, you can use N_PORT ID
|
||||
virtualization, as seen below.
|
||||
|
||||
N_PORT ID VIRTUALIZATION
|
||||
|
||||
@@ -76,11 +76,11 @@ set_frequency_scaling() {
|
||||
if [ ! -e $syscpu/cpufreq ]; then
|
||||
return
|
||||
fi
|
||||
local governor=$(<$syscpu/cpu0/cpufreq/scaling_governor)
|
||||
local cpuinfo_min_freq=$(<$syscpu/cpu0/cpufreq/cpuinfo_min_freq)
|
||||
local cpuinfo_max_freq=$(<$syscpu/cpu0/cpufreq/cpuinfo_max_freq)
|
||||
local scaling_min_freq=$(<$syscpu/cpu0/cpufreq/scaling_min_freq)
|
||||
local scaling_max_freq=$(<$syscpu/cpu0/cpufreq/scaling_max_freq)
|
||||
local governor=$(cat $syscpu/cpu0/cpufreq/scaling_governor)
|
||||
local cpuinfo_min_freq=$(cat $syscpu/cpu0/cpufreq/cpuinfo_min_freq)
|
||||
local cpuinfo_max_freq=$(cat $syscpu/cpu0/cpufreq/cpuinfo_max_freq)
|
||||
local scaling_min_freq=$(cat $syscpu/cpu0/cpufreq/scaling_min_freq)
|
||||
local scaling_max_freq=$(cat $syscpu/cpu0/cpufreq/scaling_max_freq)
|
||||
if [ -w $syscpu/cpu0/cpufreq/scaling_governor ]; then
|
||||
for d in $syscpu/cpu*/cpufreq
|
||||
do
|
||||
@@ -210,7 +210,7 @@ if [ "${perform_write_test}" = "true" -a ! -w "${device}" ]; then
|
||||
fi
|
||||
|
||||
if [ "${perform_read_test}" = "true" -a \
|
||||
"$(($(</sys/class/block/$(basename $device)/size) * 512))" -lt $(pow2 $log2_io_size) ]
|
||||
"$(($(cat /sys/class/block/$(basename $device)/size) * 512))" -lt $(pow2 $log2_io_size) ]
|
||||
then
|
||||
echo "Error: device ${device} contains less than $(pow2 $log2_io_size) bytes."
|
||||
exit 1
|
||||
|
||||
@@ -224,7 +224,7 @@ else
|
||||
include_fcst="false"
|
||||
fi
|
||||
|
||||
# Make sure that for kernel 2.6.33 and later the line
|
||||
# Make sure that for kernel 2.6.26 and later the line
|
||||
# "#define CONFIG_SCST_PROC" is removed from scst/include/scst.h.
|
||||
if grep -qw scst_sysfs scst/kernel/in-tree/Makefile.scst-${kver} \
|
||||
|| [ "${generating_upstream_patch}" = "true" ];
|
||||
@@ -268,9 +268,17 @@ done
|
||||
scsi_exec_req_fifo_defined=0
|
||||
scst_io_context=0
|
||||
for p in scst/kernel/*-${kver}.patch \
|
||||
$(if [ ${kver} = 3.7 ] && [ "$1" = "3.7.10" -o "$1" ">" "3.7.10" ];
|
||||
then echo iscsi-scst/kernel/patches/*-3.7.10.patch;
|
||||
else echo iscsi-scst/kernel/patches/*-${kver}.patch; fi)
|
||||
$(if [ ${kver} = 3.7 ] && [ "${1#3.7.}" -ge 10 ]; then
|
||||
echo iscsi-scst/kernel/patches/*-3.7.10.patch;
|
||||
elif [ ${kver} = 3.10 ] && [ "${1#3.10.}" -ge 30 ]; then
|
||||
echo iscsi-scst/kernel/patches/*-3.10.30.patch;
|
||||
elif [ ${kver} = 3.12 ] && [ "${1#3.12.}" -ge 11 ]; then
|
||||
echo iscsi-scst/kernel/patches/*-3.12.11.patch;
|
||||
elif [ ${kver} = 3.13 ] && [ "${1#3.13.}" -ge 3 ]; then
|
||||
echo iscsi-scst/kernel/patches/*-3.13.3.patch;
|
||||
else
|
||||
echo iscsi-scst/kernel/patches/*-${kver}.patch;
|
||||
fi)
|
||||
do
|
||||
# Exclude the put_page_callback patch when command-line option -u has been
|
||||
# specified since the current approach is not considered acceptable for
|
||||
|
||||
@@ -172,6 +172,45 @@ Get rid of sparse errors on sk_buff.protocol.
|
||||
|
||||
void (*destructor)(struct sk_buff *skb);
|
||||
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
||||
EOF
|
||||
fi
|
||||
if [ "${1#3.13}" != "$1" ]; then
|
||||
patch -f -s -p1 <<'EOF'
|
||||
From 7b4ec8dd7d4ac467e9eee4d49f2c9574d773efbb Mon Sep 17 00:00:00 2001
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Thu, 16 Jan 2014 10:18:48 +1030
|
||||
Subject: [PATCH] export: declare ksymtab symbols
|
||||
|
||||
sparse complains about any __ksymtab symbols with the following:
|
||||
|
||||
warning: symbol '__ksymtab_...' was not declared. Should it be static?
|
||||
|
||||
due to Andi's patch making it non-static.
|
||||
|
||||
Mollify sparse by declaring the symbol extern, otherwise we get
|
||||
drowned in sparse warnings for anything that uses EXPORT_SYMBOL
|
||||
in the sources, making it easy to miss real warnings.
|
||||
|
||||
Fixes: e0f244c63fc9 ("asmlinkage, module: Make ksymtab [...] __visible")
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
Acked-by: Andi Kleen <ak@linux.intel.com>
|
||||
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
|
||||
---
|
||||
include/linux/export.h | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/include/linux/export.h b/include/linux/export.h
|
||||
index 3f2793d..96e45ea 100644
|
||||
--- a/include/linux/export.h
|
||||
+++ b/include/linux/export.h
|
||||
@@ -59,6 +59,7 @@ extern struct module __this_module;
|
||||
static const char __kstrtab_##sym[] \
|
||||
__attribute__((section("__ksymtab_strings"), aligned(1))) \
|
||||
= VMLINUX_SYMBOL_STR(sym); \
|
||||
+ extern const struct kernel_symbol __ksymtab_##sym; \
|
||||
__visible const struct kernel_symbol __ksymtab_##sym \
|
||||
__used \
|
||||
__attribute__((section("___ksymtab" sec "+" #sym), unused)) \
|
||||
EOF
|
||||
fi
|
||||
)
|
||||
|
||||
@@ -29,7 +29,13 @@ list_source_files() {
|
||||
echo "Ignored directory $1" >&2
|
||||
fi
|
||||
elif [ -e "$r/.hg" ]; then
|
||||
hg manifest
|
||||
subdir="${d#${r}}"
|
||||
if [ -n "${subdir}" ]; then
|
||||
subdir="${subdir#/}/"
|
||||
hg manifest | sed -n "s|^$subdir||p"
|
||||
else
|
||||
hg manifest
|
||||
fi
|
||||
else
|
||||
echo "Not under source control: $1 ?" >&2
|
||||
fi
|
||||
|
||||
+3
-3
@@ -71,11 +71,11 @@ done
|
||||
%install
|
||||
export KVER=%{kver} PREFIX=%{_prefix} MANDIR=%{_mandir}
|
||||
export BUILD_2X_MODULE=y CONFIG_SCSI_QLA_FC=y CONFIG_SCSI_QLA2XXX_TARGET=y
|
||||
for d in scst iscsi-scst srpt; do
|
||||
for d in scst; do
|
||||
DESTDIR=%{buildroot} %{make} -C $d install
|
||||
done
|
||||
for d in fcst qla2x00t/qla2x00-target scst_local; do
|
||||
INSTALL_MOD_PATH=%{buildroot} %{make} -C $d install
|
||||
for d in fcst iscsi-scst qla2x00t/qla2x00-target scst_local srpt; do
|
||||
DESTDIR=%{buildroot} INSTALL_MOD_PATH=%{buildroot} %{make} -C $d install
|
||||
done
|
||||
rm -f %{buildroot}/lib/modules/%{kver}/[Mm]odule*
|
||||
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ Summary of changes between versions 1.0.1 and 1.0.2
|
||||
- Automatic sessions reassignment implemented with corresponding atomic
|
||||
management commands added
|
||||
|
||||
- Generation of INQUERY DATA HAS CHANGED Unit Attention or AEN for
|
||||
- Generation of INQUIRY DATA HAS CHANGED Unit Attention or AEN for
|
||||
changed devices during automatic sessions reassignment added
|
||||
|
||||
- Requeue global Unit Attentions on delivery failure added
|
||||
|
||||
+18
@@ -953,8 +953,18 @@ Each vdisk_fileio's device has the following attributes in
|
||||
|
||||
- o_direct - contains O_DIRECT status of this virtual device.
|
||||
|
||||
- inq_vend_specific - Vendor specific data that will be reported via
|
||||
either bytes 36..55 or bytes 96..256 of the INQUIRY response, depending
|
||||
on whether this field is <= 20 or > 20 bytes long.
|
||||
|
||||
- nv_cache - contains NV_CACHE status of this virtual device.
|
||||
|
||||
- prod_id - PRODUCT IDENTIFICATION as reported via the INQUIRY response.
|
||||
The default value for this field is the SCST device name.
|
||||
|
||||
- prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY
|
||||
response. The default value for this field is " 300".
|
||||
|
||||
- thin_provisioned - contains thin provisioning status of this virtual
|
||||
device.
|
||||
|
||||
@@ -975,6 +985,10 @@ Each vdisk_fileio's device has the following attributes in
|
||||
that these first eight characters are unique or VMware will consider
|
||||
these devices as identical.
|
||||
|
||||
- t10_vend_id - Contents of the T10 VENDOR IDENTIFICATION field of the
|
||||
INQUIRY response. The default value for this field is "SCST_BIO" for
|
||||
vdisk_block devices and "SCST_FIO" for vdisk_fileio devices.
|
||||
|
||||
- usn - contains the virtual device's serial number of INQUIRY data. It
|
||||
is created at the device creation time based on the device name and
|
||||
scst_vdisk_ID scst_vdisk.ko module parameter for procfs (see below)
|
||||
@@ -986,6 +1000,10 @@ Each vdisk_fileio's device has the following attributes in
|
||||
rescan size of the backend file. It is useful if you changed it, for
|
||||
instance, if you resized it.
|
||||
|
||||
- vend_specific_id - Vendor specific ID as reported via the Device
|
||||
Identification VPD page (83h). The default value for this attribute
|
||||
is the value of the t10_dev_id attribute.
|
||||
|
||||
For example:
|
||||
|
||||
/sys/kernel/scst_tgt/devices/disk1
|
||||
|
||||
@@ -811,8 +811,18 @@ Each vdisk_fileio's device has the following attributes in
|
||||
|
||||
- o_direct - contains O_DIRECT status of this virtual device.
|
||||
|
||||
- inq_vend_specific - Vendor specific data that will be reported via
|
||||
either bytes 36..55 or bytes 96..256 of the INQUIRY response, depending
|
||||
on whether this field is <= 20 or > 20 bytes long.
|
||||
|
||||
- nv_cache - contains NV_CACHE status of this virtual device.
|
||||
|
||||
- prod_id - PRODUCT IDENTIFICATION as reported via the INQUIRY response.
|
||||
The default value for this field is the SCST device name.
|
||||
|
||||
- prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY
|
||||
response. The default value for this field is " 300".
|
||||
|
||||
- thin_provisioned - contains thin provisioning status of this virtual
|
||||
device.
|
||||
|
||||
@@ -828,6 +838,10 @@ Each vdisk_fileio's device has the following attributes in
|
||||
created device at creation time based on the device name and
|
||||
scst_vdisk_ID scst_vdisk.ko module parameter (see below).
|
||||
|
||||
- t10_vend_id - Contents of the T10 VENDOR IDENTIFICATION field of the
|
||||
INQUIRY response. The default value for this field is "SCST_BIO" for
|
||||
vdisk_block devices and "SCST_FIO" for vdisk_fileio devices.
|
||||
|
||||
- usn - contains the virtual device's serial number of INQUIRY data. It
|
||||
is created at the device creation time based on the device name and
|
||||
scst_vdisk_ID scst_vdisk.ko module parameter (see below).
|
||||
@@ -838,6 +852,10 @@ Each vdisk_fileio's device has the following attributes in
|
||||
rescan size of the backend file. It is useful if you changed it, for
|
||||
instance, if you resized it.
|
||||
|
||||
- vend_specific_id - Vendor specific ID as reported via the Device
|
||||
Identification VPD page (83h). The default value for this attribute
|
||||
is the value of the t10_dev_id attribute.
|
||||
|
||||
For example:
|
||||
|
||||
/sys/kernel/scst_tgt/devices/disk1
|
||||
|
||||
+5
-1
@@ -266,7 +266,11 @@ Identifier attribute.
|
||||
|
||||
To provide OPTIONAL force close session functionality target drivers
|
||||
MUST implement it using "force_close" write only session's attribute,
|
||||
which on write to it MUST close the corresponding session.
|
||||
which on write to it MUST close the corresponding session. The
|
||||
recommended way to implement it is to add close_session callback to the
|
||||
target driver's struct scst_tgt_template. This way allows SCST on
|
||||
initiators' security groups deletion to automatically force close
|
||||
sessions in those groups.
|
||||
|
||||
See SCST core's README for more info about those attributes.
|
||||
|
||||
|
||||
+41
-60
@@ -119,6 +119,13 @@ typedef _Bool bool;
|
||||
#define nr_cpumask_bits NR_CPUS
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
|
||||
#ifndef swap
|
||||
#define swap(a, b) \
|
||||
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* verify cpu argument to cpumask_* operators */
|
||||
static inline unsigned int cpumask_check(unsigned int cpu)
|
||||
{
|
||||
@@ -179,6 +186,16 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
|
||||
/*
|
||||
* See also patch "sched: Fix softirq time accounting" (commit ID
|
||||
* 75e1056f5c57050415b64cb761a3acc35d91f013).
|
||||
*/
|
||||
#ifndef in_serving_softirq
|
||||
#define in_serving_softirq() in_softirq()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __list_for_each
|
||||
/* ToDo: cleanup when both are the same for all relevant kernels */
|
||||
#define __list_for_each list_for_each
|
||||
@@ -1139,29 +1156,6 @@ struct scst_tgt_template {
|
||||
struct completion *tgtt_kobj_release_cmpl;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Optional vendor to be reported via the SCSI inquiry data. If NULL,
|
||||
* an SCST device handler specific default value will be used, e.g.
|
||||
* "SCST_FIO" for scst_vdisk file I/O.
|
||||
*/
|
||||
const char *vendor;
|
||||
|
||||
/*
|
||||
* Optional method that sets the product ID in [buf, buf+size) based
|
||||
* on the device type (byte 0 of the SCSI inquiry data, which contains
|
||||
* the peripheral qualifier in the highest three bits and the
|
||||
* peripheral device type in the lower five bits).
|
||||
*/
|
||||
void (*get_product_id)(const struct scst_tgt_dev *tgt_dev,
|
||||
char *buf, int size);
|
||||
|
||||
/*
|
||||
* Optional revision to be reported in the SCSI inquiry response. If
|
||||
* NULL, an SCST device handler specific default value will be used,
|
||||
* e.g. " 210" for scst_vdisk file I/O.
|
||||
*/
|
||||
const char *revision;
|
||||
|
||||
/*
|
||||
* Optional method that writes the serial number of a target device in
|
||||
* [buf, buf+size) and returns the number of bytes written.
|
||||
@@ -1175,13 +1169,6 @@ struct scst_tgt_template {
|
||||
*/
|
||||
int (*get_serial)(const struct scst_tgt_dev *tgt_dev, char *buf,
|
||||
int size);
|
||||
|
||||
/*
|
||||
* Optional method that writes the SCSI inquiry vendor-specific data in
|
||||
* [buf, buf+size) and returns the number of bytes written.
|
||||
*/
|
||||
int (*get_vend_specific)(const struct scst_tgt_dev *tgt_dev, char *buf,
|
||||
int size);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1942,15 +1929,15 @@ struct scst_cmd {
|
||||
/* Set if the device was blocked by scst_check_blocked_dev() */
|
||||
unsigned int unblock_dev:1;
|
||||
|
||||
/* Set if this cmd incremented dev->pr_readers_count */
|
||||
unsigned int dec_pr_readers_count_needed:1;
|
||||
|
||||
/* Set if scst_dec_on_dev_cmd() call is needed on the cmd's finish */
|
||||
unsigned int dec_on_dev_needed:1;
|
||||
|
||||
/* Set if cmd is queued as hw pending */
|
||||
unsigned int cmd_hw_pending:1;
|
||||
|
||||
/* Set if cmd has NACA bit set in CDB */
|
||||
unsigned int cmd_naca:1;
|
||||
|
||||
/*
|
||||
* Set if the target driver wants to alloc data buffers on its own.
|
||||
* In this case tgt_alloc_data_buf() must be provided in the target
|
||||
@@ -2030,6 +2017,9 @@ struct scst_cmd {
|
||||
/* Set if scst_cmd_set_write_not_received_data_len() was called */
|
||||
unsigned int write_not_received_set:1;
|
||||
|
||||
/* Set if cmd has LINK bit set in CDB */
|
||||
unsigned int cmd_linked:1;
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* cmd's async flags */
|
||||
@@ -2359,9 +2349,6 @@ struct scst_dev_registrant {
|
||||
struct scst_device {
|
||||
unsigned int type; /* SCSI type of the device */
|
||||
|
||||
/* Set if reserved via the SPC-2 SCSI RESERVE command. */
|
||||
struct scst_session *reserved_by;
|
||||
|
||||
/*************************************************************
|
||||
** Dev's flags. Updates serialized by dev_lock or suspended
|
||||
** activity
|
||||
@@ -2414,18 +2401,6 @@ struct scst_device {
|
||||
int block_size;
|
||||
int block_shift;
|
||||
|
||||
/*
|
||||
* Set if dev is persistently reserved. Protected by dev_pr_mutex.
|
||||
* Modified independently to the above field, hence the alignment.
|
||||
*/
|
||||
unsigned int pr_is_set:1 __aligned(sizeof(long));
|
||||
|
||||
/*
|
||||
* Set if there is a thread changing or going to change PR state(s).
|
||||
* Protected by dev_pr_mutex.
|
||||
*/
|
||||
unsigned int pr_writer_active:1;
|
||||
|
||||
struct scst_dev_type *handler; /* corresponding dev handler */
|
||||
|
||||
/* Used for storage of dev handler private stuff */
|
||||
@@ -2454,27 +2429,31 @@ struct scst_device {
|
||||
*/
|
||||
int on_dev_cmd_count;
|
||||
|
||||
/*
|
||||
* How many threads are checking commands for PR allowance.
|
||||
* Protected by dev_lock.
|
||||
*/
|
||||
int pr_readers_count;
|
||||
|
||||
/* Memory limits for this device */
|
||||
struct scst_mem_lim dev_mem_lim;
|
||||
|
||||
/* List of commands with lock, if dedicated threads are used */
|
||||
struct scst_cmd_threads dev_cmd_threads;
|
||||
|
||||
/*************************************************************
|
||||
** Persistent reservation fields. Protected by dev_pr_mutex.
|
||||
*************************************************************/
|
||||
/* Set if reserved via the SPC-2 SCSI RESERVE command. */
|
||||
struct scst_session *reserved_by;
|
||||
|
||||
/**********************************************************************
|
||||
* Persistent reservation fields. Protected as follows:
|
||||
* - Reading PR data must be protected via scst_pr_read_lock() /
|
||||
* scst_pr_read_unlock().
|
||||
* - Modifying PR data modifications must be protected via
|
||||
* scst_pr_write_lock() / scst_pr_write_unlock().
|
||||
**********************************************************************/
|
||||
|
||||
/*
|
||||
* True if persist through power loss is activated. Modified
|
||||
* independently to the above field, hence the alignment.
|
||||
* Set if dev is persistently reserved. Modified independently
|
||||
* to the above field, hence the alignment.
|
||||
*/
|
||||
unsigned short pr_aptpl:1 __aligned(sizeof(long));
|
||||
unsigned short pr_is_set:1 __aligned(sizeof(long));
|
||||
|
||||
/* True if persist through power loss is activated. */
|
||||
unsigned short pr_aptpl:1;
|
||||
|
||||
/* Persistent reservation type */
|
||||
uint8_t pr_type;
|
||||
@@ -2494,6 +2473,8 @@ struct scst_device {
|
||||
/* List of dev's registrants */
|
||||
struct list_head dev_registrants_list;
|
||||
|
||||
/* End of persistent reservation fields protected by dev_pr_mutex. */
|
||||
|
||||
/*
|
||||
* Count of connected tgt_devs from transports, which don't support
|
||||
* PRs, i.e. don't have get_initiator_port_transport_id(). Protected
|
||||
|
||||
@@ -80,6 +80,14 @@
|
||||
#if !defined(INSIDE_KERNEL_TREE)
|
||||
#ifdef CONFIG_SCST_DEBUG
|
||||
|
||||
#ifdef __CHECKER__
|
||||
/*
|
||||
* Avoid that the while (...) local_bh_enable() loop confuses the lock checking
|
||||
* code in smatch.
|
||||
*/
|
||||
#define sBUG() BUG()
|
||||
#define sBUG_ON(p) BUG_ON((p))
|
||||
#else
|
||||
#define sBUG() do { \
|
||||
pr_crit("BUG at %s:%d\n", __FILE__, __LINE__); \
|
||||
local_irq_enable(); \
|
||||
@@ -98,6 +106,7 @@
|
||||
BUG(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/drivers/Kconfig b/drivers/Kconfig
|
||||
index aa43b91..c96860e 100644
|
||||
--- a/drivers/Kconfig
|
||||
+++ b/drivers/Kconfig
|
||||
@@ -24,6 +24,8 @@ source "drivers/ide/Kconfig"
|
||||
|
||||
source "drivers/scsi/Kconfig"
|
||||
|
||||
+source "drivers/scst/Kconfig"
|
||||
+
|
||||
source "drivers/ata/Kconfig"
|
||||
|
||||
source "drivers/md/Kconfig"
|
||||
@@ -0,0 +1,14 @@
|
||||
ccflags-y += -Wno-unused-parameter
|
||||
|
||||
obj-m := scst_cdrom.o scst_changer.o scst_disk.o scst_modisk.o scst_tape.o \
|
||||
scst_vdisk.o scst_raid.o scst_processor.o scst_user.o
|
||||
|
||||
obj-$(CONFIG_SCST_DISK) += scst_disk.o
|
||||
obj-$(CONFIG_SCST_TAPE) += scst_tape.o
|
||||
obj-$(CONFIG_SCST_CDROM) += scst_cdrom.o
|
||||
obj-$(CONFIG_SCST_MODISK) += scst_modisk.o
|
||||
obj-$(CONFIG_SCST_CHANGER) += scst_changer.o
|
||||
obj-$(CONFIG_SCST_RAID) += scst_raid.o
|
||||
obj-$(CONFIG_SCST_PROCESSOR) += scst_processor.o
|
||||
obj-$(CONFIG_SCST_VDISK) += scst_vdisk.o
|
||||
obj-$(CONFIG_SCST_USER) += scst_user.o
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/drivers/Makefile b/drivers/Makefile
|
||||
index ab93de8..45077ec 100644
|
||||
--- a/drivers/Makefile
|
||||
+++ b/drivers/Makefile
|
||||
@@ -128,6 +128,7 @@ obj-$(CONFIG_SSB) += ssb/
|
||||
obj-$(CONFIG_BCMA) += bcma/
|
||||
obj-$(CONFIG_VHOST_RING) += vhost/
|
||||
obj-$(CONFIG_VLYNQ) += vlynq/
|
||||
+obj-$(CONFIG_SCST) += scst/
|
||||
obj-$(CONFIG_STAGING) += staging/
|
||||
obj-y += platform/
|
||||
#common clk code
|
||||
@@ -4,7 +4,7 @@ scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_proc.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
@@ -4,7 +4,7 @@ scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_proc.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
@@ -4,7 +4,7 @@ scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_proc.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
@@ -4,7 +4,7 @@ scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_proc.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
@@ -4,7 +4,7 @@ scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_proc.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
@@ -4,7 +4,7 @@ scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_proc.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
@@ -4,7 +4,7 @@ scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_proc.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
ccflags-y += -Wno-unused-parameter
|
||||
|
||||
scst-y += scst_main.o
|
||||
scst-y += scst_pres.o
|
||||
scst-y += scst_targ.o
|
||||
scst-y += scst_lib.o
|
||||
scst-y += scst_sysfs.o
|
||||
scst-y += scst_mem.o
|
||||
scst-y += scst_tg.o
|
||||
scst-y += scst_debug.o
|
||||
|
||||
obj-$(CONFIG_SCST) += scst.o dev_handlers/ fcst/ iscsi-scst/ qla2xxx-target/ \
|
||||
srpt/ scst_local/
|
||||
@@ -0,0 +1,528 @@
|
||||
=== modified file 'block/blk-map.c'
|
||||
--- old/block/blk-map.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/block/blk-map.c 2014-01-30 00:44:50 +0000
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/blkdev.h>
|
||||
+#include <linux/scatterlist.h>
|
||||
+#include <linux/slab.h>
|
||||
#include <scsi/sg.h> /* for struct sg_iovec */
|
||||
|
||||
#include "blk.h"
|
||||
@@ -275,6 +277,337 @@ int blk_rq_unmap_user(struct bio *bio)
|
||||
}
|
||||
EXPORT_SYMBOL(blk_rq_unmap_user);
|
||||
|
||||
+struct blk_kern_sg_work {
|
||||
+ atomic_t bios_inflight;
|
||||
+ struct sg_table sg_table;
|
||||
+ struct scatterlist *src_sgl;
|
||||
+};
|
||||
+
|
||||
+static void blk_free_kern_sg_work(struct blk_kern_sg_work *bw)
|
||||
+{
|
||||
+ struct sg_table *sgt = &bw->sg_table;
|
||||
+ struct scatterlist *sg;
|
||||
+ int i;
|
||||
+
|
||||
+ for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
|
||||
+ struct page *pg = sg_page(sg);
|
||||
+ if (pg == NULL)
|
||||
+ break;
|
||||
+ __free_page(pg);
|
||||
+ }
|
||||
+
|
||||
+ sg_free_table(sgt);
|
||||
+ kfree(bw);
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+static void blk_bio_map_kern_endio(struct bio *bio, int err)
|
||||
+{
|
||||
+ struct blk_kern_sg_work *bw = bio->bi_private;
|
||||
+
|
||||
+ if (bw != NULL) {
|
||||
+ /* Decrement the bios in processing and, if zero, free */
|
||||
+ BUG_ON(atomic_read(&bw->bios_inflight) <= 0);
|
||||
+ if (atomic_dec_and_test(&bw->bios_inflight)) {
|
||||
+ if ((bio_data_dir(bio) == READ) && (err == 0)) {
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ local_irq_save(flags); /* to protect KMs */
|
||||
+ sg_copy(bw->src_sgl, bw->sg_table.sgl, 0, 0);
|
||||
+ local_irq_restore(flags);
|
||||
+ }
|
||||
+ blk_free_kern_sg_work(bw);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ bio_put(bio);
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+static int blk_rq_copy_kern_sg(struct request *rq, struct scatterlist *sgl,
|
||||
+ int nents, struct blk_kern_sg_work **pbw,
|
||||
+ gfp_t gfp, gfp_t page_gfp)
|
||||
+{
|
||||
+ int res = 0, i;
|
||||
+ struct scatterlist *sg;
|
||||
+ struct scatterlist *new_sgl;
|
||||
+ int new_sgl_nents;
|
||||
+ size_t len = 0, to_copy;
|
||||
+ struct blk_kern_sg_work *bw;
|
||||
+
|
||||
+ bw = kzalloc(sizeof(*bw), gfp);
|
||||
+ if (bw == NULL)
|
||||
+ goto out;
|
||||
+
|
||||
+ bw->src_sgl = sgl;
|
||||
+
|
||||
+ for_each_sg(sgl, sg, nents, i)
|
||||
+ len += sg->length;
|
||||
+ to_copy = len;
|
||||
+
|
||||
+ new_sgl_nents = PFN_UP(len);
|
||||
+
|
||||
+ res = sg_alloc_table(&bw->sg_table, new_sgl_nents, gfp);
|
||||
+ if (res != 0)
|
||||
+ goto err_free;
|
||||
+
|
||||
+ new_sgl = bw->sg_table.sgl;
|
||||
+
|
||||
+ for_each_sg(new_sgl, sg, new_sgl_nents, i) {
|
||||
+ struct page *pg;
|
||||
+
|
||||
+ pg = alloc_page(page_gfp);
|
||||
+ if (pg == NULL)
|
||||
+ goto err_free;
|
||||
+
|
||||
+ sg_assign_page(sg, pg);
|
||||
+ sg->length = min_t(size_t, PAGE_SIZE, len);
|
||||
+
|
||||
+ len -= PAGE_SIZE;
|
||||
+ }
|
||||
+
|
||||
+ if (rq_data_dir(rq) == WRITE) {
|
||||
+ /*
|
||||
+ * We need to limit amount of copied data to to_copy, because
|
||||
+ * sgl might have the last element in sgl not marked as last in
|
||||
+ * SG chaining.
|
||||
+ */
|
||||
+ sg_copy(new_sgl, sgl, 0, to_copy);
|
||||
+ }
|
||||
+
|
||||
+ *pbw = bw;
|
||||
+ /*
|
||||
+ * REQ_COPY_USER name is misleading. It should be something like
|
||||
+ * REQ_HAS_TAIL_SPACE_FOR_PADDING.
|
||||
+ */
|
||||
+ rq->cmd_flags |= REQ_COPY_USER;
|
||||
+
|
||||
+out:
|
||||
+ return res;
|
||||
+
|
||||
+err_free:
|
||||
+ blk_free_kern_sg_work(bw);
|
||||
+ res = -ENOMEM;
|
||||
+ goto out;
|
||||
+}
|
||||
+
|
||||
+static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
|
||||
+ int nents, struct blk_kern_sg_work *bw, gfp_t gfp)
|
||||
+{
|
||||
+ int res;
|
||||
+ struct request_queue *q = rq->q;
|
||||
+ int rw = rq_data_dir(rq);
|
||||
+ int max_nr_vecs, i;
|
||||
+ size_t tot_len;
|
||||
+ bool need_new_bio;
|
||||
+ struct scatterlist *sg, *prev_sg = NULL;
|
||||
+ struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
|
||||
+ int bios;
|
||||
+
|
||||
+ if (unlikely((sgl == NULL) || (sgl->length == 0) || (nents <= 0))) {
|
||||
+ WARN_ON(1);
|
||||
+ res = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Let's keep each bio allocation inside a single page to decrease
|
||||
+ * probability of failure.
|
||||
+ */
|
||||
+ max_nr_vecs = min_t(size_t,
|
||||
+ ((PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec)),
|
||||
+ BIO_MAX_PAGES);
|
||||
+
|
||||
+ need_new_bio = true;
|
||||
+ tot_len = 0;
|
||||
+ bios = 0;
|
||||
+ for_each_sg(sgl, sg, nents, i) {
|
||||
+ struct page *page = sg_page(sg);
|
||||
+ void *page_addr = page_address(page);
|
||||
+ size_t len = sg->length, l;
|
||||
+ size_t offset = sg->offset;
|
||||
+
|
||||
+ tot_len += len;
|
||||
+ prev_sg = sg;
|
||||
+
|
||||
+ /*
|
||||
+ * Each segment must be aligned on DMA boundary and
|
||||
+ * not on stack. The last one may have unaligned
|
||||
+ * length as long as the total length is aligned to
|
||||
+ * DMA padding alignment.
|
||||
+ */
|
||||
+ if (i == nents - 1)
|
||||
+ l = 0;
|
||||
+ else
|
||||
+ l = len;
|
||||
+ if (((sg->offset | l) & queue_dma_alignment(q)) ||
|
||||
+ (page_addr && object_is_on_stack(page_addr + sg->offset))) {
|
||||
+ res = -EINVAL;
|
||||
+ goto out_free_bios;
|
||||
+ }
|
||||
+
|
||||
+ while (len > 0) {
|
||||
+ size_t bytes;
|
||||
+ int rc;
|
||||
+
|
||||
+ if (need_new_bio) {
|
||||
+ bio = bio_kmalloc(gfp, max_nr_vecs);
|
||||
+ if (bio == NULL) {
|
||||
+ res = -ENOMEM;
|
||||
+ goto out_free_bios;
|
||||
+ }
|
||||
+
|
||||
+ if (rw == WRITE)
|
||||
+ bio->bi_rw |= REQ_WRITE;
|
||||
+
|
||||
+ bios++;
|
||||
+ bio->bi_private = bw;
|
||||
+ bio->bi_end_io = blk_bio_map_kern_endio;
|
||||
+
|
||||
+ if (hbio == NULL)
|
||||
+ hbio = tbio = bio;
|
||||
+ else
|
||||
+ tbio = tbio->bi_next = bio;
|
||||
+ }
|
||||
+
|
||||
+ bytes = min_t(size_t, len, PAGE_SIZE - offset);
|
||||
+
|
||||
+ rc = bio_add_pc_page(q, bio, page, bytes, offset);
|
||||
+ if (rc < bytes) {
|
||||
+ if (unlikely(need_new_bio || (rc < 0))) {
|
||||
+ if (rc < 0)
|
||||
+ res = rc;
|
||||
+ else
|
||||
+ res = -EIO;
|
||||
+ goto out_free_bios;
|
||||
+ } else {
|
||||
+ need_new_bio = true;
|
||||
+ len -= rc;
|
||||
+ offset += rc;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ need_new_bio = false;
|
||||
+ offset = 0;
|
||||
+ len -= bytes;
|
||||
+ page = nth_page(page, 1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (hbio == NULL) {
|
||||
+ res = -EINVAL;
|
||||
+ goto out_free_bios;
|
||||
+ }
|
||||
+
|
||||
+ /* Total length must be aligned on DMA padding alignment */
|
||||
+ if ((tot_len & q->dma_pad_mask) &&
|
||||
+ !(rq->cmd_flags & REQ_COPY_USER)) {
|
||||
+ res = -EINVAL;
|
||||
+ goto out_free_bios;
|
||||
+ }
|
||||
+
|
||||
+ if (bw != NULL)
|
||||
+ atomic_set(&bw->bios_inflight, bios);
|
||||
+
|
||||
+ while (hbio != NULL) {
|
||||
+ bio = hbio;
|
||||
+ hbio = hbio->bi_next;
|
||||
+ bio->bi_next = NULL;
|
||||
+
|
||||
+ blk_queue_bounce(q, &bio);
|
||||
+
|
||||
+ res = blk_rq_append_bio(q, rq, bio);
|
||||
+ if (unlikely(res != 0)) {
|
||||
+ bio->bi_next = hbio;
|
||||
+ hbio = bio;
|
||||
+ /* We can have one or more bios bounced */
|
||||
+ goto out_unmap_bios;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ res = 0;
|
||||
+
|
||||
+ rq->buffer = NULL;
|
||||
+out:
|
||||
+ return res;
|
||||
+
|
||||
+out_unmap_bios:
|
||||
+ blk_rq_unmap_kern_sg(rq, res);
|
||||
+
|
||||
+out_free_bios:
|
||||
+ while (hbio != NULL) {
|
||||
+ bio = hbio;
|
||||
+ hbio = hbio->bi_next;
|
||||
+ bio_put(bio);
|
||||
+ }
|
||||
+ goto out;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * blk_rq_map_kern_sg - map kernel data to a request, for REQ_TYPE_BLOCK_PC
|
||||
+ * @rq: request to fill
|
||||
+ * @sgl: area to map
|
||||
+ * @nents: number of elements in @sgl
|
||||
+ * @gfp: memory allocation flags
|
||||
+ *
|
||||
+ * Description:
|
||||
+ * Data will be mapped directly if possible. Otherwise a bounce
|
||||
+ * buffer will be used.
|
||||
+ */
|
||||
+int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
|
||||
+ int nents, gfp_t gfp)
|
||||
+{
|
||||
+ int res;
|
||||
+
|
||||
+ res = __blk_rq_map_kern_sg(rq, sgl, nents, NULL, gfp);
|
||||
+ if (unlikely(res != 0)) {
|
||||
+ struct blk_kern_sg_work *bw = NULL;
|
||||
+
|
||||
+ res = blk_rq_copy_kern_sg(rq, sgl, nents, &bw,
|
||||
+ gfp, rq->q->bounce_gfp | gfp);
|
||||
+ if (unlikely(res != 0))
|
||||
+ goto out;
|
||||
+
|
||||
+ res = __blk_rq_map_kern_sg(rq, bw->sg_table.sgl,
|
||||
+ bw->sg_table.nents, bw, gfp);
|
||||
+ if (res != 0) {
|
||||
+ blk_free_kern_sg_work(bw);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ rq->buffer = NULL;
|
||||
+
|
||||
+out:
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL(blk_rq_map_kern_sg);
|
||||
+
|
||||
+/**
|
||||
+ * blk_rq_unmap_kern_sg - unmap a request with kernel sg
|
||||
+ * @rq: request to unmap
|
||||
+ * @err: non-zero error code
|
||||
+ *
|
||||
+ * Description:
|
||||
+ * Unmap a rq previously mapped by blk_rq_map_kern_sg(). Must be called
|
||||
+ * only in case of an error!
|
||||
+ */
|
||||
+void blk_rq_unmap_kern_sg(struct request *rq, int err)
|
||||
+{
|
||||
+ struct bio *bio = rq->bio;
|
||||
+
|
||||
+ while (bio) {
|
||||
+ struct bio *b = bio;
|
||||
+ bio = bio->bi_next;
|
||||
+ b->bi_end_io(b, err);
|
||||
+ }
|
||||
+ rq->bio = NULL;
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
+EXPORT_SYMBOL(blk_rq_unmap_kern_sg);
|
||||
+
|
||||
/**
|
||||
* blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage
|
||||
* @q: request queue where request should be inserted
|
||||
|
||||
=== modified file 'include/linux/blkdev.h'
|
||||
--- old/include/linux/blkdev.h 2014-01-30 00:25:53 +0000
|
||||
+++ new/include/linux/blkdev.h 2014-01-30 00:44:50 +0000
|
||||
@@ -712,6 +712,8 @@ extern unsigned long blk_max_low_pfn, bl
|
||||
#define BLK_DEFAULT_SG_TIMEOUT (60 * HZ)
|
||||
#define BLK_MIN_SG_TIMEOUT (7 * HZ)
|
||||
|
||||
+#define SCSI_EXEC_REQ_FIFO_DEFINED
|
||||
+
|
||||
#ifdef CONFIG_BOUNCE
|
||||
extern int init_emergency_isa_pool(void);
|
||||
extern void blk_queue_bounce(struct request_queue *q, struct bio **bio);
|
||||
@@ -831,6 +833,9 @@ extern int blk_rq_map_kern(struct reques
|
||||
extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
|
||||
struct rq_map_data *, struct sg_iovec *, int,
|
||||
unsigned int, gfp_t);
|
||||
+extern int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
|
||||
+ int nents, gfp_t gfp);
|
||||
+extern void blk_rq_unmap_kern_sg(struct request *rq, int err);
|
||||
extern int blk_execute_rq(struct request_queue *, struct gendisk *,
|
||||
struct request *, int);
|
||||
extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
|
||||
|
||||
=== modified file 'include/linux/scatterlist.h'
|
||||
--- old/include/linux/scatterlist.h 2014-01-30 00:25:53 +0000
|
||||
+++ new/include/linux/scatterlist.h 2014-01-30 00:44:50 +0000
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <asm/types.h>
|
||||
#include <asm/scatterlist.h>
|
||||
#include <asm/io.h>
|
||||
+#include <asm/kmap_types.h>
|
||||
|
||||
struct sg_table {
|
||||
struct scatterlist *sgl; /* the list */
|
||||
@@ -249,6 +250,9 @@ size_t sg_pcopy_from_buffer(struct scatt
|
||||
size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
|
||||
void *buf, size_t buflen, off_t skip);
|
||||
|
||||
+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
|
||||
+ int nents_to_copy, size_t copy_len);
|
||||
+
|
||||
/*
|
||||
* Maximum number of entries that will be allocated in one piece, if
|
||||
* a list larger than this is required then chaining will be utilized.
|
||||
|
||||
=== modified file 'lib/scatterlist.c'
|
||||
--- old/lib/scatterlist.c 2014-01-30 00:25:53 +0000
|
||||
+++ new/lib/scatterlist.c 2014-01-30 00:44:50 +0000
|
||||
@@ -717,3 +717,127 @@ size_t sg_pcopy_to_buffer(struct scatter
|
||||
return sg_copy_buffer(sgl, nents, buf, buflen, skip, true);
|
||||
}
|
||||
EXPORT_SYMBOL(sg_pcopy_to_buffer);
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Can switch to the next dst_sg element, so, to copy to strictly only
|
||||
+ * one dst_sg element, it must be either last in the chain, or
|
||||
+ * copy_len == dst_sg->length.
|
||||
+ */
|
||||
+static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len,
|
||||
+ size_t *pdst_offs, struct scatterlist *src_sg,
|
||||
+ size_t copy_len)
|
||||
+{
|
||||
+ int res = 0;
|
||||
+ struct scatterlist *dst_sg;
|
||||
+ size_t src_len, dst_len, src_offs, dst_offs;
|
||||
+ struct page *src_page, *dst_page;
|
||||
+
|
||||
+ dst_sg = *pdst_sg;
|
||||
+ dst_len = *pdst_len;
|
||||
+ dst_offs = *pdst_offs;
|
||||
+ dst_page = sg_page(dst_sg);
|
||||
+
|
||||
+ src_page = sg_page(src_sg);
|
||||
+ src_len = src_sg->length;
|
||||
+ src_offs = src_sg->offset;
|
||||
+
|
||||
+ do {
|
||||
+ void *saddr, *daddr;
|
||||
+ size_t n;
|
||||
+
|
||||
+ saddr = kmap_atomic(src_page + (src_offs >> PAGE_SHIFT)) +
|
||||
+ (src_offs & ~PAGE_MASK);
|
||||
+ daddr = kmap_atomic(dst_page + (dst_offs >> PAGE_SHIFT)) +
|
||||
+ (dst_offs & ~PAGE_MASK);
|
||||
+
|
||||
+ if (((src_offs & ~PAGE_MASK) == 0) &&
|
||||
+ ((dst_offs & ~PAGE_MASK) == 0) &&
|
||||
+ (src_len >= PAGE_SIZE) && (dst_len >= PAGE_SIZE) &&
|
||||
+ (copy_len >= PAGE_SIZE)) {
|
||||
+ copy_page(daddr, saddr);
|
||||
+ n = PAGE_SIZE;
|
||||
+ } else {
|
||||
+ n = min_t(size_t, PAGE_SIZE - (dst_offs & ~PAGE_MASK),
|
||||
+ PAGE_SIZE - (src_offs & ~PAGE_MASK));
|
||||
+ n = min(n, src_len);
|
||||
+ n = min(n, dst_len);
|
||||
+ n = min_t(size_t, n, copy_len);
|
||||
+ memcpy(daddr, saddr, n);
|
||||
+ }
|
||||
+ dst_offs += n;
|
||||
+ src_offs += n;
|
||||
+
|
||||
+ kunmap_atomic(saddr);
|
||||
+ kunmap_atomic(daddr);
|
||||
+
|
||||
+ res += n;
|
||||
+ copy_len -= n;
|
||||
+ if (copy_len == 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ src_len -= n;
|
||||
+ dst_len -= n;
|
||||
+ if (dst_len == 0) {
|
||||
+ dst_sg = sg_next(dst_sg);
|
||||
+ if (dst_sg == NULL)
|
||||
+ goto out;
|
||||
+ dst_page = sg_page(dst_sg);
|
||||
+ dst_len = dst_sg->length;
|
||||
+ dst_offs = dst_sg->offset;
|
||||
+ }
|
||||
+ } while (src_len > 0);
|
||||
+
|
||||
+out:
|
||||
+ *pdst_sg = dst_sg;
|
||||
+ *pdst_len = dst_len;
|
||||
+ *pdst_offs = dst_offs;
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * sg_copy - copy one SG vector to another
|
||||
+ * @dst_sg: destination SG
|
||||
+ * @src_sg: source SG
|
||||
+ * @nents_to_copy: maximum number of entries to copy
|
||||
+ * @copy_len: maximum amount of data to copy. If 0, then copy all.
|
||||
+ *
|
||||
+ * Description:
|
||||
+ * Data from the source SG vector will be copied to the destination SG
|
||||
+ * vector. End of the vectors will be determined by sg_next() returning
|
||||
+ * NULL. Returns number of bytes copied.
|
||||
+ */
|
||||
+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
|
||||
+ int nents_to_copy, size_t copy_len)
|
||||
+{
|
||||
+ int res = 0;
|
||||
+ size_t dst_len, dst_offs;
|
||||
+
|
||||
+ if (copy_len == 0)
|
||||
+ copy_len = 0x7FFFFFFF; /* copy all */
|
||||
+
|
||||
+ if (nents_to_copy == 0)
|
||||
+ nents_to_copy = 0x7FFFFFFF; /* copy all */
|
||||
+
|
||||
+ dst_len = dst_sg->length;
|
||||
+ dst_offs = dst_sg->offset;
|
||||
+
|
||||
+ do {
|
||||
+ int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs,
|
||||
+ src_sg, copy_len);
|
||||
+ copy_len -= copied;
|
||||
+ res += copied;
|
||||
+ if ((copy_len == 0) || (dst_sg == NULL))
|
||||
+ goto out;
|
||||
+
|
||||
+ nents_to_copy--;
|
||||
+ if (nents_to_copy == 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ src_sg = sg_next(src_sg);
|
||||
+ } while (src_sg != NULL);
|
||||
+
|
||||
+out:
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL(sg_copy);
|
||||
|
||||
+17
-9
@@ -54,15 +54,25 @@ obj-$(CONFIG_SCST) += scst.o dev_handlers/
|
||||
obj-$(BUILD_DEV) += $(DEV_HANDLERS_DIR)/
|
||||
|
||||
else
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_DEV=m
|
||||
|
||||
@@ -97,7 +107,7 @@ ifneq ($(MOD_VERS),)
|
||||
rm -f $(INSTALL_DIR_H)/Modules.symvers
|
||||
install -m 644 Module.symvers $(INSTALL_DIR_H)
|
||||
endif
|
||||
-/sbin/depmod -a $(KVER)
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
mkdir -p $(DESTDIR)/var/lib/scst/pr
|
||||
@echo "****************************************************************"
|
||||
@echo "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*"
|
||||
@@ -106,7 +116,7 @@ endif
|
||||
@echo "*!! target drivers, custom dev handlers and necessary user !!*"
|
||||
@echo "*!! space applications. Otherwise, because of the versions !!*"
|
||||
@echo "*!! mismatch, you could have many problems and crashes. !!*"
|
||||
@echo "*!! See IMPORTANT note in the \"Installation\" section of !!*"
|
||||
@echo "*!! See IMPORTANT note in the \"Installation\" section of !!*"
|
||||
@echo "*!! SCST's README file for more info. !!*"
|
||||
@echo "*!! !!*"
|
||||
@echo "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*"
|
||||
@@ -116,15 +126,13 @@ uninstall:
|
||||
cd $(DEV_HANDLERS_DIR) && $(MAKE) $@
|
||||
rm -f $(INSTALL_DIR)/scst.ko
|
||||
-rmdir $(INSTALL_DIR) 2>/dev/null
|
||||
-/sbin/depmod -a $(KVER)
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
rm -rf $(INSTALL_DIR_H)
|
||||
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
ifeq ($(KVER),)
|
||||
INSTALL_DIR := $(DESTDIR)/lib/modules/$(shell uname -r)/extra
|
||||
else
|
||||
INSTALL_DIR := $(DESTDIR)/lib/modules/$(KVER)/extra
|
||||
endif
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
INSTALL_DIR_H := $(DESTDIR)$(PREFIX)/include/scst
|
||||
|
||||
enable-Wextra = $(shell uname_r="$$(uname -r)"; if [ "$${uname_r%.el5}" = "$${uname_r}" ]; then echo "$(1)"; fi)
|
||||
|
||||
@@ -46,27 +46,38 @@ obj-$(CONFIG_SCST_VDISK) += scst_vdisk.o
|
||||
obj-$(CONFIG_SCST_USER) += scst_user.o
|
||||
|
||||
else
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)
|
||||
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) \
|
||||
modules_install
|
||||
-/sbin/depmod -a $(KVER)
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/dev_handlers/scst_*.ko
|
||||
endif
|
||||
|
||||
ifeq ($(KVER),)
|
||||
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
|
||||
else
|
||||
INSTALL_DIR := /lib/modules/$(KVER)/extra
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
enable-Wextra = $(shell uname_r="$$(uname -r)"; if [ "$${uname_r%.el5}" = "$${uname_r}" ]; then echo "$(1)"; fi)
|
||||
|
||||
@@ -691,6 +691,9 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd)
|
||||
ucmd->user_cmd.alloc_cmd.data_direction = cmd->data_direction;
|
||||
ucmd->user_cmd.alloc_cmd.sn = cmd->tgt_sn;
|
||||
|
||||
TRACE_DBG("Preparing ALLOC_MEM for user space (ucmd=%p, h=%d, "
|
||||
"alloc_len %d)", ucmd, ucmd->h, ucmd->user_cmd.alloc_cmd.alloc_len);
|
||||
|
||||
dev_user_add_to_ready(ucmd);
|
||||
|
||||
res = SCST_CMD_STATE_STOP;
|
||||
@@ -987,6 +990,7 @@ static void dev_user_on_free_cmd(struct scst_cmd *cmd)
|
||||
goto out_reply;
|
||||
}
|
||||
|
||||
TRACE_DBG("Preparing ON_FREE_CMD (pbuff 0x%lx)", ucmd->ubuff);
|
||||
ucmd->user_cmd_payload_len =
|
||||
offsetof(struct scst_user_get_cmd, on_free_cmd) +
|
||||
sizeof(ucmd->user_cmd.on_free_cmd);
|
||||
@@ -1129,7 +1133,12 @@ static void dev_user_add_to_ready(struct scst_user_cmd *ucmd)
|
||||
{
|
||||
struct scst_user_dev *dev = ucmd->dev;
|
||||
unsigned long flags;
|
||||
int do_wake = in_interrupt();
|
||||
/*
|
||||
* Note, a separate softIRQ check is required for real-time kernels
|
||||
* (CONFIG_PREEMPT_RT_FULL=y) since on such kernels softIRQ's are
|
||||
* served in thread context. See also http://lwn.net/Articles/302043/.
|
||||
*/
|
||||
int do_wake = in_interrupt() || in_serving_softirq();
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -1286,6 +1295,7 @@ out_process:
|
||||
scst_post_alloc_data_buf(cmd);
|
||||
scst_process_active_cmd(cmd, false);
|
||||
|
||||
TRACE_DBG("%s", "ALLOC_MEM finished");
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
@@ -1350,6 +1360,8 @@ static int dev_user_process_reply_parse(struct scst_user_cmd *ucmd,
|
||||
|
||||
out_process:
|
||||
scst_post_parse(cmd);
|
||||
TRACE_DBG("%s", "PARSE finished");
|
||||
|
||||
scst_process_active_cmd(cmd, false);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
@@ -1408,6 +1420,7 @@ static int dev_user_process_reply_on_free(struct scst_user_cmd *ucmd)
|
||||
dev_user_free_sgv(ucmd);
|
||||
ucmd_put(ucmd);
|
||||
|
||||
TRACE_DBG("%s", "ON_FREE_CMD finished");
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
@@ -1422,6 +1435,7 @@ static int dev_user_process_reply_on_cache_free(struct scst_user_cmd *ucmd)
|
||||
|
||||
ucmd_put(ucmd);
|
||||
|
||||
TRACE_MEM("%s", "ON_CACHED_MEM_FREE finished");
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
@@ -1535,6 +1549,7 @@ out_compl:
|
||||
/* !! At this point cmd can be already freed !! */
|
||||
|
||||
out:
|
||||
TRACE_DBG("%s", "EXEC finished");
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
@@ -2968,7 +2983,7 @@ static int dev_user_register_dev(struct file *file,
|
||||
dev->pool = sgv_pool_create(dev->devtype.name, sgv_no_clustering,
|
||||
dev_desc->sgv_single_alloc_pages,
|
||||
dev_desc->sgv_shared,
|
||||
dev_desc->sgv_purge_interval);
|
||||
dev_desc->sgv_purge_interval * HZ);
|
||||
if (dev->pool == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto out_deinit_threads;
|
||||
@@ -2985,7 +3000,7 @@ static int dev_user_register_dev(struct file *file,
|
||||
sgv_tail_clustering,
|
||||
dev_desc->sgv_single_alloc_pages,
|
||||
dev_desc->sgv_shared,
|
||||
dev_desc->sgv_purge_interval);
|
||||
dev_desc->sgv_purge_interval * HZ);
|
||||
if (dev->pool_clust == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto out_free0;
|
||||
|
||||
@@ -82,6 +82,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = {
|
||||
#define SCST_FIO_REV " 300"
|
||||
|
||||
#define MAX_USN_LEN (20+1) /* For '\0' */
|
||||
#define MAX_INQ_VEND_SPECIFIC_LEN (INQ_BUF_SZ - 96)
|
||||
|
||||
#define INQ_BUF_SZ 256
|
||||
#define EVPD 0x01
|
||||
@@ -175,11 +176,22 @@ struct scst_vdisk_dev {
|
||||
scst_mutex and suspended activities */
|
||||
uint16_t command_set_version;
|
||||
|
||||
/* All 4 protected by vdisk_serial_rwlock */
|
||||
/* All 14 protected by vdisk_serial_rwlock */
|
||||
unsigned int t10_vend_id_set:1; /* true if t10_vend_id manually set */
|
||||
/* true if vend_specific_id manually set */
|
||||
unsigned int vend_specific_id_set:1;
|
||||
unsigned int prod_id_set:1; /* true if prod_id manually set */
|
||||
unsigned int prod_rev_lvl_set:1; /* true if prod_rev_lvl manually set */
|
||||
unsigned int t10_dev_id_set:1; /* true if t10_dev_id manually set */
|
||||
unsigned int usn_set:1; /* true if usn manually set */
|
||||
char t10_vend_id[8 + 1];
|
||||
char vend_specific_id[32 + 1];
|
||||
char prod_id[16 + 1];
|
||||
char prod_rev_lvl[4 + 1];
|
||||
char t10_dev_id[16+8+2]; /* T10 device ID */
|
||||
char usn[MAX_USN_LEN];
|
||||
uint8_t inq_vend_specific[MAX_INQ_VEND_SPECIFIC_LEN];
|
||||
int inq_vend_specific_len;
|
||||
|
||||
struct scst_device *dev;
|
||||
struct list_head vdev_list_entry;
|
||||
@@ -319,6 +331,22 @@ static ssize_t vdev_sysfs_filename_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_t10_vend_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_t10_vend_id_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdev_sysfs_vend_specific_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_vend_specific_id_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdev_sysfs_prod_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_prod_id_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_t10_dev_id_show(struct kobject *kobj,
|
||||
@@ -327,6 +355,10 @@ static ssize_t vdev_sysfs_usn_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_usn_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdev_sysfs_inq_vend_specific_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count);
|
||||
static ssize_t vdev_sysfs_inq_vend_specific_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdev_zero_copy_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
|
||||
@@ -357,11 +389,28 @@ static struct kobj_attribute vdisk_filename_attr =
|
||||
__ATTR(filename, S_IRUGO, vdev_sysfs_filename_show, NULL);
|
||||
static struct kobj_attribute vdisk_resync_size_attr =
|
||||
__ATTR(resync_size, S_IWUSR, NULL, vdisk_sysfs_resync_size_store);
|
||||
static struct kobj_attribute vdev_t10_vend_id_attr =
|
||||
__ATTR(t10_vend_id, S_IWUSR|S_IRUGO, vdev_sysfs_t10_vend_id_show,
|
||||
vdev_sysfs_t10_vend_id_store);
|
||||
static struct kobj_attribute vdev_vend_specific_id_attr =
|
||||
__ATTR(vend_specific_id, S_IWUSR|S_IRUGO,
|
||||
vdev_sysfs_vend_specific_id_show,
|
||||
vdev_sysfs_vend_specific_id_store);
|
||||
static struct kobj_attribute vdev_prod_id_attr =
|
||||
__ATTR(prod_id, S_IWUSR|S_IRUGO, vdev_sysfs_prod_id_show,
|
||||
vdev_sysfs_prod_id_store);
|
||||
static struct kobj_attribute vdev_prod_rev_lvl_attr =
|
||||
__ATTR(prod_rev_lvl, S_IWUSR|S_IRUGO, vdev_sysfs_prod_rev_lvl_show,
|
||||
vdev_sysfs_prod_rev_lvl_store);
|
||||
static struct kobj_attribute vdev_t10_dev_id_attr =
|
||||
__ATTR(t10_dev_id, S_IWUSR|S_IRUGO, vdev_sysfs_t10_dev_id_show,
|
||||
vdev_sysfs_t10_dev_id_store);
|
||||
static struct kobj_attribute vdev_usn_attr =
|
||||
__ATTR(usn, S_IWUSR|S_IRUGO, vdev_sysfs_usn_show, vdev_sysfs_usn_store);
|
||||
static struct kobj_attribute vdev_inq_vend_specific_attr =
|
||||
__ATTR(inq_vend_specific, S_IWUSR|S_IRUGO,
|
||||
vdev_sysfs_inq_vend_specific_show,
|
||||
vdev_sysfs_inq_vend_specific_store);
|
||||
static struct kobj_attribute vdev_zero_copy_attr =
|
||||
__ATTR(zero_copy, S_IRUGO, vdev_zero_copy_show, NULL);
|
||||
|
||||
@@ -381,8 +430,13 @@ static const struct attribute *vdisk_fileio_attrs[] = {
|
||||
&vdisk_removable_attr.attr,
|
||||
&vdisk_filename_attr.attr,
|
||||
&vdisk_resync_size_attr.attr,
|
||||
&vdev_t10_vend_id_attr.attr,
|
||||
&vdev_vend_specific_id_attr.attr,
|
||||
&vdev_prod_id_attr.attr,
|
||||
&vdev_prod_rev_lvl_attr.attr,
|
||||
&vdev_t10_dev_id_attr.attr,
|
||||
&vdev_usn_attr.attr,
|
||||
&vdev_inq_vend_specific_attr.attr,
|
||||
&vdev_zero_copy_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
@@ -397,8 +451,13 @@ static const struct attribute *vdisk_blockio_attrs[] = {
|
||||
&vdisk_rotational_attr.attr,
|
||||
&vdisk_filename_attr.attr,
|
||||
&vdisk_resync_size_attr.attr,
|
||||
&vdev_t10_vend_id_attr.attr,
|
||||
&vdev_vend_specific_id_attr.attr,
|
||||
&vdev_prod_id_attr.attr,
|
||||
&vdev_prod_rev_lvl_attr.attr,
|
||||
&vdev_t10_dev_id_attr.attr,
|
||||
&vdev_usn_attr.attr,
|
||||
&vdev_inq_vend_specific_attr.attr,
|
||||
&vdisk_tp_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
@@ -409,8 +468,13 @@ static const struct attribute *vdisk_nullio_attrs[] = {
|
||||
&vdisk_rd_only_attr.attr,
|
||||
&vdev_dummy_attr.attr,
|
||||
&vdisk_removable_attr.attr,
|
||||
&vdev_t10_vend_id_attr.attr,
|
||||
&vdev_vend_specific_id_attr.attr,
|
||||
&vdev_prod_id_attr.attr,
|
||||
&vdev_prod_rev_lvl_attr.attr,
|
||||
&vdev_t10_dev_id_attr.attr,
|
||||
&vdev_usn_attr.attr,
|
||||
&vdev_inq_vend_specific_attr.attr,
|
||||
&vdisk_rotational_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
@@ -418,8 +482,13 @@ static const struct attribute *vdisk_nullio_attrs[] = {
|
||||
static const struct attribute *vcdrom_attrs[] = {
|
||||
&vdev_size_attr.attr,
|
||||
&vcdrom_filename_attr.attr,
|
||||
&vdev_t10_vend_id_attr.attr,
|
||||
&vdev_vend_specific_id_attr.attr,
|
||||
&vdev_prod_id_attr.attr,
|
||||
&vdev_prod_rev_lvl_attr.attr,
|
||||
&vdev_t10_dev_id_attr.attr,
|
||||
&vdev_usn_attr.attr,
|
||||
&vdev_inq_vend_specific_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -428,7 +497,10 @@ static const struct attribute *vcdrom_attrs[] = {
|
||||
/* Protects vdisks addition/deletion and related activities, like search */
|
||||
static DEFINE_MUTEX(scst_vdisk_mutex);
|
||||
|
||||
/* Protects devices t10_dev_id and usn */
|
||||
/*
|
||||
* Protects the device attributes t10_vend_id, vend_specific_id, prod_id,
|
||||
* prod_rev_lvl, t10_dev_id, usn and inq_vend_specific.
|
||||
*/
|
||||
static DEFINE_RWLOCK(vdisk_serial_rwlock);
|
||||
|
||||
/* Protected by scst_vdisk_mutex */
|
||||
@@ -469,9 +541,17 @@ static struct scst_dev_type vdisk_file_devtype = {
|
||||
.add_device = vdisk_add_fileio_device,
|
||||
.del_device = vdisk_del_device,
|
||||
.dev_attrs = vdisk_fileio_attrs,
|
||||
.add_device_parameters = "filename, blocksize, write_through, "
|
||||
"nv_cache, o_direct, read_only, removable, rotational, "
|
||||
"thin_provisioned, zero_copy",
|
||||
.add_device_parameters =
|
||||
"blocksize, "
|
||||
"filename, "
|
||||
"nv_cache, "
|
||||
"o_direct, "
|
||||
"read_only, "
|
||||
"removable, "
|
||||
"rotational, "
|
||||
"thin_provisioned, "
|
||||
"write_through, "
|
||||
"zero_copy",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -506,9 +586,15 @@ static struct scst_dev_type vdisk_blk_devtype = {
|
||||
.add_device = vdisk_add_blockio_device,
|
||||
.del_device = vdisk_del_device,
|
||||
.dev_attrs = vdisk_blockio_attrs,
|
||||
.add_device_parameters = "filename, blocksize, write_through, "
|
||||
"nv_cache, read_only, removable, rotational, "
|
||||
"thin_provisioned",
|
||||
.add_device_parameters =
|
||||
"blocksize, "
|
||||
"filename, "
|
||||
"nv_cache, "
|
||||
"read_only, "
|
||||
"removable, "
|
||||
"rotational, "
|
||||
"thin_provisioned, "
|
||||
"write_through",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -541,8 +627,12 @@ static struct scst_dev_type vdisk_null_devtype = {
|
||||
.add_device = vdisk_add_nullio_device,
|
||||
.del_device = vdisk_del_device,
|
||||
.dev_attrs = vdisk_nullio_attrs,
|
||||
.add_device_parameters = "blocksize, read_only, dummy, removable,"
|
||||
" rotational",
|
||||
.add_device_parameters =
|
||||
"blocksize, "
|
||||
"dummy, "
|
||||
"read_only, "
|
||||
"removable, "
|
||||
"rotational",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -1529,7 +1619,7 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
|
||||
/**
|
||||
* finish_read - Release the pages referenced by prepare_read().
|
||||
*/
|
||||
@@ -2125,21 +2215,23 @@ static int vdisk_unmap_range(struct scst_cmd *cmd,
|
||||
(unsigned long long)start_lba, (unsigned long long)blocks);
|
||||
|
||||
if (virt_dev->blockio) {
|
||||
sector_t start_sector = start_lba << (cmd->dev->block_shift - 9);
|
||||
sector_t nr_sects = blocks << (cmd->dev->block_shift - 9);
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)
|
||||
struct inode *inode = fd->f_dentry->d_inode;
|
||||
gfp_t gfp = cmd->cmd_gfp_mask;
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks, gfp);
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp);
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) \
|
||||
&& !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 34) \
|
||||
&& defined(CONFIG_SUSE_KERNEL))
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks,
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects,
|
||||
gfp, DISCARD_FL_WAIT);
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks,
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects,
|
||||
gfp, BLKDEV_IFL_WAIT);
|
||||
#else
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks, gfp, 0);
|
||||
err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp, 0);
|
||||
#endif
|
||||
if (unlikely(err != 0)) {
|
||||
PRINT_ERROR("blkdev_issue_discard() for "
|
||||
@@ -2215,6 +2307,28 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a zero-terminated string into a fixed-size byte array and fill the
|
||||
* trailing bytes with @fill_byte.
|
||||
*/
|
||||
static void scst_copy_and_fill_b(char *dst, const char *src, int len,
|
||||
uint8_t fill_byte)
|
||||
{
|
||||
int cpy_len = min_t(int, strlen(src), len);
|
||||
|
||||
memcpy(dst, src, cpy_len);
|
||||
memset(dst + cpy_len, fill_byte, len - cpy_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a zero-terminated string into a fixed-size char array and fill the
|
||||
* trailing characters with spaces.
|
||||
*/
|
||||
static void scst_copy_and_fill(char *dst, const char *src, int len)
|
||||
{
|
||||
scst_copy_and_fill_b(dst, src, len, ' ');
|
||||
}
|
||||
|
||||
static enum compl_status_e vdisk_exec_write_same(struct vdisk_cmd_params *p)
|
||||
{
|
||||
struct scst_cmd *cmd = p->cmd;
|
||||
@@ -2425,16 +2539,10 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
|
||||
/* T10 vendor identifier field format (faked) */
|
||||
buf[num + 0] = 0x2; /* ASCII */
|
||||
buf[num + 1] = 0x1; /* Vendor ID */
|
||||
if (cmd->tgtt->vendor)
|
||||
memcpy(&buf[num + 4], cmd->tgtt->vendor, 8);
|
||||
else if (virt_dev->blockio)
|
||||
memcpy(&buf[num + 4], SCST_BIO_VENDOR, 8);
|
||||
else
|
||||
memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8);
|
||||
|
||||
read_lock(&vdisk_serial_rwlock);
|
||||
i = strlen(virt_dev->t10_dev_id);
|
||||
memcpy(&buf[num + 12], virt_dev->t10_dev_id, i);
|
||||
scst_copy_and_fill(&buf[num + 4], virt_dev->t10_vend_id, 8);
|
||||
i = strlen(virt_dev->vend_specific_id);
|
||||
memcpy(&buf[num + 12], virt_dev->vend_specific_id, i);
|
||||
read_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
buf[num + 3] = 8 + i;
|
||||
@@ -2588,7 +2696,7 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
|
||||
goto out_put;
|
||||
}
|
||||
} else {
|
||||
int len, num;
|
||||
int num;
|
||||
|
||||
if (cmd->cdb[2] != 0) {
|
||||
TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]);
|
||||
@@ -2608,37 +2716,30 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
|
||||
buf[6] = 0x10; /* MultiP 1 */
|
||||
buf[7] = 2; /* CMDQUE 1, BQue 0 => commands queuing supported */
|
||||
|
||||
read_lock(&vdisk_serial_rwlock);
|
||||
|
||||
/*
|
||||
* 8 byte ASCII Vendor Identification of the target
|
||||
* - left aligned.
|
||||
*/
|
||||
if (cmd->tgtt->vendor)
|
||||
memcpy(&buf[8], cmd->tgtt->vendor, 8);
|
||||
else if (virt_dev->blockio)
|
||||
memcpy(&buf[8], SCST_BIO_VENDOR, 8);
|
||||
else
|
||||
memcpy(&buf[8], SCST_FIO_VENDOR, 8);
|
||||
scst_copy_and_fill(&buf[8], virt_dev->t10_vend_id, 8);
|
||||
|
||||
/*
|
||||
* 16 byte ASCII Product Identification of the target - left
|
||||
* aligned.
|
||||
*/
|
||||
memset(&buf[16], ' ', 16);
|
||||
if (cmd->tgtt->get_product_id)
|
||||
cmd->tgtt->get_product_id(cmd->tgt_dev, &buf[16], 16);
|
||||
else {
|
||||
len = min_t(size_t, strlen(virt_dev->name), 16);
|
||||
memcpy(&buf[16], virt_dev->name, len);
|
||||
}
|
||||
scst_copy_and_fill(&buf[16], virt_dev->prod_id, 16);
|
||||
|
||||
/*
|
||||
* 4 byte ASCII Product Revision Level of the target - left
|
||||
* aligned.
|
||||
*/
|
||||
if (cmd->tgtt->revision)
|
||||
memcpy(&buf[32], cmd->tgtt->revision, 4);
|
||||
else
|
||||
memcpy(&buf[32], SCST_FIO_REV, 4);
|
||||
scst_copy_and_fill(&buf[32], virt_dev->prod_rev_lvl, 4);
|
||||
|
||||
/* Vendor specific information. */
|
||||
if (virt_dev->inq_vend_specific_len <= 20)
|
||||
memcpy(&buf[36], virt_dev->inq_vend_specific,
|
||||
virt_dev->inq_vend_specific_len);
|
||||
|
||||
/** Version descriptors **/
|
||||
|
||||
@@ -2679,13 +2780,14 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
|
||||
}
|
||||
|
||||
/* Vendor specific information. */
|
||||
if (cmd->tgtt->get_vend_specific) {
|
||||
/* Skip to byte 96. */
|
||||
num = 96 - 58;
|
||||
num += cmd->tgtt->get_vend_specific(cmd->tgt_dev,
|
||||
&buf[96], INQ_BUF_SZ - 96);
|
||||
if (virt_dev->inq_vend_specific_len > 20) {
|
||||
memcpy(&buf[96], virt_dev->inq_vend_specific,
|
||||
virt_dev->inq_vend_specific_len);
|
||||
num = 96 - 58 + virt_dev->inq_vend_specific_len;
|
||||
}
|
||||
|
||||
read_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
buf[4] += num;
|
||||
resp_len = buf[4] + 5;
|
||||
}
|
||||
@@ -4620,6 +4722,20 @@ static int vdev_create(struct scst_dev_type *devt,
|
||||
"%llx-%s", dev_id_num, virt_dev->name);
|
||||
TRACE_DBG("t10_dev_id %s", virt_dev->t10_dev_id);
|
||||
|
||||
sprintf(virt_dev->t10_vend_id, "%.*s",
|
||||
(int)(sizeof(virt_dev->t10_vend_id) - 1),
|
||||
virt_dev->blockio ? SCST_BIO_VENDOR : SCST_FIO_VENDOR);
|
||||
|
||||
sprintf(virt_dev->vend_specific_id, "%.*s",
|
||||
(int)(sizeof(virt_dev->vend_specific_id) - 1),
|
||||
virt_dev->t10_dev_id);
|
||||
|
||||
sprintf(virt_dev->prod_id, "%.*s", (int)(sizeof(virt_dev->prod_id) - 1),
|
||||
virt_dev->name);
|
||||
|
||||
sprintf(virt_dev->prod_rev_lvl, "%.*s",
|
||||
(int)(sizeof(virt_dev->prod_rev_lvl) - 1), SCST_FIO_REV);
|
||||
|
||||
scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx", dev_id_num);
|
||||
TRACE_DBG("usn %s", virt_dev->usn);
|
||||
|
||||
@@ -4710,6 +4826,12 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
|
||||
}
|
||||
|
||||
if (!strcasecmp("filename", p)) {
|
||||
if (virt_dev->filename) {
|
||||
PRINT_ERROR("%s specified more than once"
|
||||
" (device %s)", p, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (*pp != '/') {
|
||||
PRINT_ERROR("Filename %s must be global "
|
||||
"(device %s)", pp, virt_dev->name);
|
||||
@@ -5713,6 +5835,239 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_t10_vend_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
char *p;
|
||||
int res, len;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
p = memchr(buf, '\n', count);
|
||||
len = p ? p - buf : count;
|
||||
|
||||
if (len >= sizeof(virt_dev->t10_vend_id)) {
|
||||
PRINT_ERROR("T10 vendor id is too long (max %zd characters)",
|
||||
sizeof(virt_dev->t10_vend_id));
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_lock(&vdisk_serial_rwlock);
|
||||
sprintf(virt_dev->t10_vend_id, "%.*s", len, buf);
|
||||
virt_dev->t10_vend_id_set = 1;
|
||||
write_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_t10_vend_id_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int pos;
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
read_lock(&vdisk_serial_rwlock);
|
||||
pos = sprintf(buf, "%s\n%s", virt_dev->t10_vend_id,
|
||||
virt_dev->t10_vend_id_set ? SCST_SYSFS_KEY_MARK "\n" :
|
||||
"");
|
||||
read_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_vend_specific_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
char *p;
|
||||
int res, len;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
p = memchr(buf, '\n', count);
|
||||
len = p ? p - buf : count;
|
||||
|
||||
if (len >= sizeof(virt_dev->vend_specific_id)) {
|
||||
PRINT_ERROR("Vendor specific id is too long (max %zd"
|
||||
" characters)",
|
||||
sizeof(virt_dev->vend_specific_id) - 1);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_lock(&vdisk_serial_rwlock);
|
||||
sprintf(virt_dev->vend_specific_id, "%.*s", len, buf);
|
||||
virt_dev->vend_specific_id_set = 1;
|
||||
write_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_vend_specific_id_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int pos;
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
read_lock(&vdisk_serial_rwlock);
|
||||
pos = sprintf(buf, "%s\n%s", virt_dev->vend_specific_id,
|
||||
virt_dev->vend_specific_id_set ?
|
||||
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
read_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_prod_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
char *p;
|
||||
int res, len;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
p = memchr(buf, '\n', count);
|
||||
len = p ? p - buf : count;
|
||||
|
||||
if (len >= sizeof(virt_dev->prod_id)) {
|
||||
PRINT_ERROR("Product id is too long (max %zd characters)",
|
||||
sizeof(virt_dev->prod_id));
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_lock(&vdisk_serial_rwlock);
|
||||
sprintf(virt_dev->prod_id, "%.*s", len, buf);
|
||||
virt_dev->prod_id_set = 1;
|
||||
write_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_prod_id_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int pos;
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
read_lock(&vdisk_serial_rwlock);
|
||||
pos = sprintf(buf, "%s\n%s", virt_dev->prod_id,
|
||||
virt_dev->prod_id_set ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
read_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
char *p;
|
||||
int res, len;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
p = memchr(buf, '\n', count);
|
||||
len = p ? p - buf : count;
|
||||
|
||||
if (len >= sizeof(virt_dev->prod_rev_lvl)) {
|
||||
PRINT_ERROR("Product revision level is too long (max %zd"
|
||||
" characters)",
|
||||
sizeof(virt_dev->prod_rev_lvl));
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
write_lock(&vdisk_serial_rwlock);
|
||||
sprintf(virt_dev->prod_rev_lvl, "%.*s", len, buf);
|
||||
virt_dev->prod_rev_lvl_set = 1;
|
||||
write_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int pos;
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
read_lock(&vdisk_serial_rwlock);
|
||||
pos = sprintf(buf, "%s\n%s", virt_dev->prod_rev_lvl,
|
||||
virt_dev->prod_rev_lvl_set ? SCST_SYSFS_KEY_MARK "\n" :
|
||||
"");
|
||||
read_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
@@ -5853,6 +6208,55 @@ static ssize_t vdev_sysfs_usn_show(struct kobject *kobj,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_inq_vend_specific_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
char *p;
|
||||
int res = -EINVAL, len;
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
p = memchr(buf, '\n', count);
|
||||
len = p ? p - buf : count;
|
||||
if (len > MAX_INQ_VEND_SPECIFIC_LEN)
|
||||
goto out;
|
||||
|
||||
write_lock(&vdisk_serial_rwlock);
|
||||
memcpy(virt_dev->inq_vend_specific, buf, len);
|
||||
virt_dev->inq_vend_specific_len = len;
|
||||
write_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t vdev_sysfs_inq_vend_specific_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int pos;
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
read_lock(&vdisk_serial_rwlock);
|
||||
pos = snprintf(buf, PAGE_SIZE, "%.*s\n%s",
|
||||
virt_dev->inq_vend_specific_len,
|
||||
virt_dev->inq_vend_specific,
|
||||
virt_dev->inq_vend_specific_len ?
|
||||
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
read_unlock(&vdisk_serial_rwlock);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdev_zero_copy_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
+7
-7
@@ -4645,7 +4645,7 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp,
|
||||
uint8_t write16_cdb[16];
|
||||
struct scatterlist *sg;
|
||||
int sg_cnt, len = blocks << ws_cmd->dev->block_shift;
|
||||
struct sgv_pool_obj *sgv;
|
||||
struct sgv_pool_obj *sgv = NULL;
|
||||
struct scst_cmd *cmd;
|
||||
int64_t cur_lba;
|
||||
|
||||
@@ -4686,7 +4686,6 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp,
|
||||
goto set_add;
|
||||
}
|
||||
|
||||
sgv = NULL; /* we don't supply sgv */
|
||||
sg = sgv_pool_alloc(ws_cmd->tgt_dev->pool, len, GFP_KERNEL, 0,
|
||||
&sg_cnt, &sgv, &cmd->dev->dev_mem_lim, NULL);
|
||||
if (sg == NULL) {
|
||||
@@ -5433,8 +5432,7 @@ void scst_free_cmd(struct scst_cmd *cmd)
|
||||
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
|
||||
TRACE_MGMT_DBG("Freeing aborted cmd %p", cmd);
|
||||
|
||||
EXTRACHECKS_BUG_ON(cmd->unblock_dev || cmd->dec_on_dev_needed ||
|
||||
cmd->dec_pr_readers_count_needed);
|
||||
EXTRACHECKS_BUG_ON(cmd->unblock_dev || cmd->dec_on_dev_needed);
|
||||
|
||||
/*
|
||||
* Target driver can already free sg buffer before calling
|
||||
@@ -6687,7 +6685,7 @@ static int get_cdb_info_write_same16(struct scst_cmd *cmd,
|
||||
}
|
||||
|
||||
/**
|
||||
* scst_get_cdb_info_apt() - Parse ATA PASS-THROUGH CDB.
|
||||
* get_cdb_info_apt() - Parse ATA PASS-THROUGH CDB.
|
||||
*
|
||||
* Parse ATA PASS-THROUGH(12) and ATA PASS-THROUGH(16). See also SAT-3 for a
|
||||
* detailed description of these commands.
|
||||
@@ -6870,6 +6868,8 @@ int scst_get_cdb_info(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
cmd->cdb_len = SCST_GET_CDB_LEN(op);
|
||||
cmd->cmd_naca = (cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT);
|
||||
cmd->cmd_linked = (cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_LINK_BIT);
|
||||
cmd->op_name = ptr->info_op_name;
|
||||
cmd->data_direction = ptr->info_data_direction;
|
||||
cmd->op_flags = ptr->info_op_flags | SCST_INFO_VALID;
|
||||
@@ -8267,7 +8267,7 @@ void scst_unblock_dev(struct scst_device *dev)
|
||||
struct scst_cmd *cmd, *tcmd;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
local_irq_save_nort(flags);
|
||||
list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list,
|
||||
blocked_cmd_list_entry) {
|
||||
bool strictly_serialized;
|
||||
@@ -8287,7 +8287,7 @@ void scst_unblock_dev(struct scst_device *dev)
|
||||
if (dev->strictly_serialized_cmd_waiting && strictly_serialized)
|
||||
break;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
local_irq_restore_nort(flags);
|
||||
|
||||
dev->strictly_serialized_cmd_waiting = 0;
|
||||
}
|
||||
|
||||
+11
-11
@@ -1126,15 +1126,16 @@ out:
|
||||
/* Called under scst_mutex */
|
||||
void scst_pr_clear_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
struct scst_device *dev = tgt_dev->dev;
|
||||
struct scst_dev_registrant *reg;
|
||||
struct scst_tgt_dev *t;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (tgt_dev->registrant != NULL) {
|
||||
struct scst_dev_registrant *reg = tgt_dev->registrant;
|
||||
struct scst_device *dev = tgt_dev->dev;
|
||||
struct scst_tgt_dev *t;
|
||||
|
||||
scst_pr_write_lock(dev);
|
||||
scst_pr_write_lock(dev);
|
||||
|
||||
reg = tgt_dev->registrant;
|
||||
if (reg) {
|
||||
tgt_dev->registrant = NULL;
|
||||
reg->tgt_dev = NULL;
|
||||
|
||||
@@ -1155,10 +1156,10 @@ void scst_pr_clear_tgt_dev(struct scst_tgt_dev *tgt_dev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scst_pr_write_unlock(dev);
|
||||
}
|
||||
|
||||
scst_pr_write_unlock(dev);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
@@ -2324,11 +2325,10 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd)
|
||||
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
|
||||
struct scst_dev_registrant *reg;
|
||||
uint8_t type;
|
||||
bool unlock;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
unlock = scst_pr_read_lock(cmd);
|
||||
scst_pr_read_lock(dev);
|
||||
|
||||
TRACE_DBG("Testing if command %s (0x%x) from %s allowed to execute",
|
||||
cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name);
|
||||
@@ -2388,7 +2388,7 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd)
|
||||
cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name);
|
||||
|
||||
out_unlock:
|
||||
scst_pr_read_unlock(cmd, unlock);
|
||||
scst_pr_read_unlock(dev);
|
||||
|
||||
TRACE_EXIT_RES(allowed);
|
||||
return allowed;
|
||||
|
||||
+4
-110
@@ -54,63 +54,6 @@
|
||||
/* Persistent reservation SCOPE field */
|
||||
#define SCOPE_LU 0x00
|
||||
|
||||
static inline void scst_inc_pr_readers_count(struct scst_cmd *cmd,
|
||||
bool locked)
|
||||
{
|
||||
struct scst_device *dev = cmd->dev;
|
||||
|
||||
EXTRACHECKS_BUG_ON(cmd->dec_pr_readers_count_needed);
|
||||
|
||||
if (!locked)
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
EXTRACHECKS_BUG_ON(!spin_is_locked(&dev->dev_lock));
|
||||
#endif
|
||||
|
||||
dev->pr_readers_count++;
|
||||
cmd->dec_pr_readers_count_needed = 1;
|
||||
TRACE_DBG("New inc pr_readers_count %d (cmd %p)", dev->pr_readers_count,
|
||||
cmd);
|
||||
|
||||
if (!locked)
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void scst_dec_pr_readers_count(struct scst_cmd *cmd,
|
||||
bool locked)
|
||||
{
|
||||
struct scst_device *dev = cmd->dev;
|
||||
|
||||
if (unlikely(!cmd->dec_pr_readers_count_needed)) {
|
||||
PRINT_ERROR("__scst_check_local_events(x, false) should not "
|
||||
"be called twice (cmd %p, op %x)! Use "
|
||||
"scst_check_local_events() instead.", cmd, cmd->cdb[0]);
|
||||
WARN_ON(1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!locked)
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
EXTRACHECKS_BUG_ON(!spin_is_locked(&dev->dev_lock));
|
||||
#endif
|
||||
|
||||
dev->pr_readers_count--;
|
||||
cmd->dec_pr_readers_count_needed = 0;
|
||||
TRACE_DBG("New dec pr_readers_count %d (cmd %p)", dev->pr_readers_count,
|
||||
cmd);
|
||||
|
||||
if (!locked)
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
out:
|
||||
EXTRACHECKS_BUG_ON(dev->pr_readers_count < 0);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline bool scst_pr_type_valid(uint8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -126,73 +69,24 @@ static inline bool scst_pr_type_valid(uint8_t type)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool scst_pr_read_lock(struct scst_cmd *cmd)
|
||||
static inline void scst_pr_read_lock(struct scst_device *dev)
|
||||
{
|
||||
struct scst_device *dev = cmd->dev;
|
||||
bool unlock = false;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
smp_mb(); /* to sync with scst_pr_write_lock() */
|
||||
if (unlikely(dev->pr_writer_active)) {
|
||||
unlock = true;
|
||||
scst_dec_pr_readers_count(cmd, false);
|
||||
mutex_lock(&dev->dev_pr_mutex);
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(unlock);
|
||||
return unlock;
|
||||
mutex_lock(&dev->dev_pr_mutex);
|
||||
}
|
||||
|
||||
static inline void scst_pr_read_unlock(struct scst_cmd *cmd, bool unlock)
|
||||
static inline void scst_pr_read_unlock(struct scst_device *dev)
|
||||
{
|
||||
struct scst_device *dev = cmd->dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (unlikely(unlock))
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
else
|
||||
scst_dec_pr_readers_count(cmd, false);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
}
|
||||
|
||||
static inline void scst_pr_write_lock(struct scst_device *dev)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
mutex_lock(&dev->dev_pr_mutex);
|
||||
|
||||
dev->pr_writer_active = 1;
|
||||
/* to sync with scst_pr_read_lock() and unlock() */
|
||||
smp_mb();
|
||||
|
||||
while (true) {
|
||||
int readers;
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
readers = dev->pr_readers_count;
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
if (readers == 0)
|
||||
break;
|
||||
TRACE_DBG("Waiting for %d readers (dev %p)", readers, dev);
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void scst_pr_write_unlock(struct scst_device *dev)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev->pr_writer_active = 0;
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
int scst_pr_init_dev(struct scst_device *dev);
|
||||
|
||||
@@ -120,6 +120,26 @@ extern unsigned long scst_trace_flag;
|
||||
#define SCST_MAX_EACH_INTERNAL_IO_SIZE (128*1024)
|
||||
#define SCST_MAX_IN_FLIGHT_INTERNAL_COMMANDS 32
|
||||
|
||||
/*
|
||||
* Compatibility with real-time (CONFIG_PREEMPT_RT_FULL) kernels.
|
||||
* In such kernels:
|
||||
* - Interrupt handlers run in kernel thread context (see e.g.
|
||||
* http://lwn.net/Articles/302043/).
|
||||
* - spin_lock() calls can sleep (see e.g. http://lwn.net/Articles/271817/).
|
||||
* - local_irq functions manipulate preemptibility, not HW interruptibility
|
||||
* (see also http://lwn.net/Articles/146861).
|
||||
* For the upstream kernels up to at least kernel 3.14 _nort functions are
|
||||
* only defined if a CONFIG PREEMPT RT patch has been applied to the kernel.
|
||||
* See https://rt.wiki.kernel.org/index.php/CONFIG_PREEMPT_RT_Patch.
|
||||
*/
|
||||
#ifndef local_irq_enable_nort
|
||||
/* Kernel does not have CONFIG_PREEMPT_RT patch */
|
||||
#define local_irq_enable_nort() local_irq_enable()
|
||||
#define local_irq_disable_nort() local_irq_disable()
|
||||
#define local_irq_save_nort(flags) local_irq_save(flags)
|
||||
#define local_irq_restore_nort(flags) local_irq_restore(flags)
|
||||
#endif
|
||||
|
||||
typedef void (*scst_i_finish_fn_t) (struct scst_cmd *cmd);
|
||||
|
||||
extern struct mutex scst_mutex2;
|
||||
|
||||
+91
-44
@@ -1185,11 +1185,6 @@ static void scst_tgt_release(struct kobject *kobj)
|
||||
return;
|
||||
}
|
||||
|
||||
static struct kobj_type tgt_ktype = {
|
||||
.sysfs_ops = &scst_sysfs_ops,
|
||||
.release = scst_tgt_release,
|
||||
};
|
||||
|
||||
static int __scst_process_luns_mgmt_store(char *buffer,
|
||||
struct scst_tgt *tgt, struct scst_acg *acg, bool tgt_kobj)
|
||||
{
|
||||
@@ -2405,6 +2400,97 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(scst_create_tgt_attr);
|
||||
|
||||
#define SCST_TGT_SYSFS_STAT_ATTR(member_name, attr, dir, result_op) \
|
||||
static int scst_tgt_sysfs_##attr##_show_work_fn( \
|
||||
struct scst_sysfs_work_item *work) \
|
||||
{ \
|
||||
struct scst_tgt *tgt = work->tgt; \
|
||||
struct scst_session *sess; \
|
||||
int res; \
|
||||
uint64_t c = 0; \
|
||||
\
|
||||
BUILD_BUG_ON((unsigned)(dir) >= ARRAY_SIZE(sess->io_stats)); \
|
||||
\
|
||||
res = mutex_lock_interruptible(&scst_mutex); \
|
||||
if (res) \
|
||||
goto out; \
|
||||
list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) \
|
||||
c += sess->io_stats[(dir)].member_name; \
|
||||
mutex_unlock(&scst_mutex); \
|
||||
\
|
||||
work->res_buf = kasprintf(GFP_KERNEL, "%llu\n", c result_op); \
|
||||
res = work->res_buf ? 0 : -ENOMEM; \
|
||||
\
|
||||
out: \
|
||||
kobject_put(&tgt->tgt_kobj); \
|
||||
return res; \
|
||||
} \
|
||||
\
|
||||
static ssize_t scst_tgt_sysfs_##attr##_show(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct scst_tgt *tgt = \
|
||||
container_of(kobj, struct scst_tgt, tgt_kobj); \
|
||||
struct scst_sysfs_work_item *work; \
|
||||
int res; \
|
||||
\
|
||||
res = scst_alloc_sysfs_work(scst_tgt_sysfs_##attr##_show_work_fn, \
|
||||
true, &work); \
|
||||
if (res) \
|
||||
goto out; \
|
||||
\
|
||||
work->tgt = tgt; \
|
||||
SCST_SET_DEP_MAP(work, &scst_tgt_dep_map); \
|
||||
kobject_get(&tgt->tgt_kobj); \
|
||||
scst_sysfs_work_get(work); \
|
||||
res = scst_sysfs_queue_wait_work(work); \
|
||||
if (res == 0) \
|
||||
res = scnprintf(buf, PAGE_SIZE, "%s", work->res_buf); \
|
||||
scst_sysfs_work_put(work); \
|
||||
\
|
||||
out: \
|
||||
return res; \
|
||||
} \
|
||||
\
|
||||
static struct kobj_attribute scst_tgt_##attr##_attr = \
|
||||
__ATTR(attr, S_IRUGO, scst_tgt_sysfs_##attr##_show, NULL);
|
||||
|
||||
SCST_TGT_SYSFS_STAT_ATTR(cmd_count, unknown_cmd_count, SCST_DATA_UNKNOWN, >> 0);
|
||||
SCST_TGT_SYSFS_STAT_ATTR(cmd_count, write_cmd_count, SCST_DATA_WRITE, >> 0);
|
||||
SCST_TGT_SYSFS_STAT_ATTR(io_byte_count, write_io_count_kb, SCST_DATA_WRITE,
|
||||
>> 10);
|
||||
SCST_TGT_SYSFS_STAT_ATTR(cmd_count, read_cmd_count, SCST_DATA_READ, >> 0);
|
||||
SCST_TGT_SYSFS_STAT_ATTR(io_byte_count, read_io_count_kb, SCST_DATA_READ,
|
||||
>> 10);
|
||||
SCST_TGT_SYSFS_STAT_ATTR(cmd_count, bidi_cmd_count, SCST_DATA_BIDI, >> 0);
|
||||
SCST_TGT_SYSFS_STAT_ATTR(io_byte_count, bidi_io_count_kb, SCST_DATA_BIDI,
|
||||
>> 10);
|
||||
SCST_TGT_SYSFS_STAT_ATTR(cmd_count, none_cmd_count, SCST_DATA_NONE, >> 0);
|
||||
|
||||
static struct attribute *scst_tgt_attrs[] = {
|
||||
&scst_rel_tgt_id.attr,
|
||||
&scst_tgt_comment.attr,
|
||||
&scst_tgt_addr_method.attr,
|
||||
&scst_tgt_io_grouping_type.attr,
|
||||
&scst_tgt_cpu_mask.attr,
|
||||
&scst_tgt_unknown_cmd_count_attr.attr,
|
||||
&scst_tgt_write_cmd_count_attr.attr,
|
||||
&scst_tgt_write_io_count_kb_attr.attr,
|
||||
&scst_tgt_read_cmd_count_attr.attr,
|
||||
&scst_tgt_read_io_count_kb_attr.attr,
|
||||
&scst_tgt_bidi_cmd_count_attr.attr,
|
||||
&scst_tgt_bidi_io_count_kb_attr.attr,
|
||||
&scst_tgt_none_cmd_count_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct kobj_type tgt_ktype = {
|
||||
.sysfs_ops = &scst_sysfs_ops,
|
||||
.release = scst_tgt_release,
|
||||
.default_attrs = scst_tgt_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* Supposed to be called under scst_mutex. In case of error will drop,
|
||||
* then reacquire it.
|
||||
@@ -2468,45 +2554,6 @@ int scst_tgt_sysfs_create(struct scst_tgt *tgt)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&scst_rel_tgt_id.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_rel_tgt_id.attr.name, tgt->tgt_name);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&scst_tgt_comment.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_tgt_comment.attr.name, tgt->tgt_name);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&scst_tgt_addr_method.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_tgt_addr_method.attr.name, tgt->tgt_name);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&scst_tgt_io_grouping_type.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_tgt_io_grouping_type.attr.name, tgt->tgt_name);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&tgt->tgt_kobj, &scst_tgt_cpu_mask.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_tgt_cpu_mask.attr.name, tgt->tgt_name);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (tgt->tgtt->tgt_attrs) {
|
||||
res = sysfs_create_files(&tgt->tgt_kobj, tgt->tgtt->tgt_attrs);
|
||||
if (res != 0) {
|
||||
|
||||
+51
-54
@@ -119,8 +119,6 @@ static bool scst_check_blocked_dev(struct scst_cmd *cmd)
|
||||
cmd->dec_on_dev_needed = 1;
|
||||
TRACE_DBG("New inc on_dev_count %d (cmd %p)", dev->on_dev_cmd_count, cmd);
|
||||
|
||||
scst_inc_pr_readers_count(cmd, true);
|
||||
|
||||
if (unlikely(dev->block_count > 0) ||
|
||||
unlikely(dev->dev_double_ua_possible) ||
|
||||
unlikely((cmd->op_flags & SCST_SERIALIZED) != 0))
|
||||
@@ -134,8 +132,6 @@ static bool scst_check_blocked_dev(struct scst_cmd *cmd)
|
||||
cmd->dec_on_dev_needed = 0;
|
||||
TRACE_DBG("New dec on_dev_count %d (cmd %p)",
|
||||
dev->on_dev_cmd_count, cmd);
|
||||
|
||||
scst_dec_pr_readers_count(cmd, true);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
@@ -159,9 +155,6 @@ static void scst_check_unblock_dev(struct scst_cmd *cmd)
|
||||
dev->on_dev_cmd_count, cmd);
|
||||
}
|
||||
|
||||
if (unlikely(cmd->dec_pr_readers_count_needed))
|
||||
scst_dec_pr_readers_count(cmd, true);
|
||||
|
||||
if (unlikely(cmd->unblock_dev)) {
|
||||
TRACE_BLOCK("cmd %p (tag %llu): unblocking dev %s", cmd,
|
||||
(long long unsigned int)cmd->tag, dev->virt_name);
|
||||
@@ -744,7 +737,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
cmd->op_flags &= ~SCST_UNKNOWN_LENGTH;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT)) {
|
||||
if (unlikely(cmd->cmd_naca)) {
|
||||
PRINT_ERROR("NACA bit in control byte CDB is not supported "
|
||||
"(opcode 0x%02x)", cmd->cdb[0]);
|
||||
scst_set_cmd_error(cmd,
|
||||
@@ -752,7 +745,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->cdb[cmd->cdb_len-1] & CONTROL_BYTE_LINK_BIT)) {
|
||||
if (unlikely(cmd->cmd_linked)) {
|
||||
PRINT_ERROR("Linked commands are not supported "
|
||||
"(opcode 0x%02x)", cmd->cdb[0]);
|
||||
scst_set_invalid_field_in_cdb(cmd, cmd->cdb_len-1,
|
||||
@@ -948,23 +941,34 @@ set_res:
|
||||
|
||||
out:
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
/*
|
||||
* At this point either both lba and data_len must be initialized to
|
||||
* at least 0 for not data transfer commands, or cmd must be
|
||||
* completed (with an error) and have correct state set.
|
||||
*/
|
||||
if (unlikely((((cmd->lba == SCST_DEF_LBA_DATA_LEN) &&
|
||||
!(cmd->op_flags & SCST_LBA_NOT_VALID)) ||
|
||||
(cmd->data_len == SCST_DEF_LBA_DATA_LEN)) &&
|
||||
(!cmd->completed ||
|
||||
(((cmd->state < SCST_CMD_STATE_PRE_XMIT_RESP) ||
|
||||
(cmd->state >= SCST_CMD_STATE_LAST_ACTIVE)) &&
|
||||
(cmd->state != SCST_CMD_STATE_PREPROCESSING_DONE))))) {
|
||||
PRINT_CRIT_ERROR("Not initialized data_len for going to "
|
||||
"execute command or bad state (cmd %p, data_len %lld, "
|
||||
"completed %d, state %d)", cmd,
|
||||
(long long)cmd->data_len, cmd->completed, cmd->state);
|
||||
sBUG();
|
||||
if (unlikely(cmd->completed)) {
|
||||
/* Command completed with error */
|
||||
bool valid_state = (cmd->state == SCST_CMD_STATE_PREPROCESSING_DONE) ||
|
||||
((cmd->state >= SCST_CMD_STATE_PRE_XMIT_RESP) &&
|
||||
(cmd->state < SCST_CMD_STATE_LAST_ACTIVE));
|
||||
|
||||
if (!valid_state) {
|
||||
PRINT_CRIT_ERROR("Bad state for completed cmd "
|
||||
"(cmd %p, state %d)", cmd, cmd->state);
|
||||
sBUG();
|
||||
}
|
||||
} else if (cmd->state != SCST_CMD_STATE_PARSE) {
|
||||
/*
|
||||
* Ready to execute. At this point both lba and data_len must
|
||||
* be initialized or marked non-applicable.
|
||||
*/
|
||||
bool bad_lba = (cmd->lba == SCST_DEF_LBA_DATA_LEN) &&
|
||||
!(cmd->op_flags & SCST_LBA_NOT_VALID);
|
||||
bool bad_data_len = (cmd->data_len == SCST_DEF_LBA_DATA_LEN);
|
||||
|
||||
if (unlikely(bad_lba || bad_data_len)) {
|
||||
PRINT_CRIT_ERROR("Uninitialized lba or data_len for "
|
||||
"ready-to-execute command (cmd %p, lba %lld, "
|
||||
"data_len %lld, state %d)", cmd,
|
||||
(long long)cmd->lba, (long long)cmd->data_len,
|
||||
cmd->state);
|
||||
sBUG();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2211,7 +2215,7 @@ static int scst_persistent_reserve_in_local(struct scst_cmd *cmd)
|
||||
if (unlikely(buffer_size <= 0))
|
||||
goto out_done;
|
||||
|
||||
scst_pr_write_lock(dev);
|
||||
scst_pr_read_lock(dev);
|
||||
|
||||
/* We can be aborted by another PR command while waiting for the lock */
|
||||
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
|
||||
@@ -2246,7 +2250,7 @@ out_complete:
|
||||
cmd->completed = 1;
|
||||
|
||||
out_unlock:
|
||||
scst_pr_write_unlock(dev);
|
||||
scst_pr_read_unlock(dev);
|
||||
|
||||
scst_put_buf_full(cmd, buffer);
|
||||
|
||||
@@ -2303,6 +2307,12 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
buffer_size = scst_get_buf_full_sense(cmd, &buffer);
|
||||
if (unlikely(buffer_size <= 0))
|
||||
goto out_done;
|
||||
|
||||
scst_pr_write_lock(dev);
|
||||
|
||||
/*
|
||||
* Check if tgt_dev already registered. Also by this check we make
|
||||
* sure that table "PERSISTENT RESERVE OUT service actions that are
|
||||
@@ -2314,20 +2324,16 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
(tgt_dev->registrant == NULL)) {
|
||||
TRACE_PR("'%s' not registered", cmd->sess->initiator_name);
|
||||
scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT);
|
||||
goto out_done;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
buffer_size = scst_get_buf_full_sense(cmd, &buffer);
|
||||
if (unlikely(buffer_size <= 0))
|
||||
goto out_done;
|
||||
|
||||
/* Check scope */
|
||||
if ((action != PR_REGISTER) && (action != PR_REGISTER_AND_IGNORE) &&
|
||||
(action != PR_CLEAR) && (cmd->cdb[2] >> 4) != SCOPE_LU) {
|
||||
TRACE_PR("Scope must be SCOPE_LU for action %x", action);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out_put_buf_full;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Check SPEC_I_PT (PR_REGISTER_AND_MOVE has another format) */
|
||||
@@ -2336,7 +2342,7 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
TRACE_PR("SPEC_I_PT must be zero for action %x", action);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
|
||||
scst_sense_invalid_field_in_cdb));
|
||||
goto out_put_buf_full;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* Check ALL_TG_PT (PR_REGISTER_AND_MOVE has another format) */
|
||||
@@ -2345,11 +2351,9 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
TRACE_PR("ALL_TG_PT must be zero for action %x", action);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out_put_buf_full;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
scst_pr_write_lock(dev);
|
||||
|
||||
/* We can be aborted by another PR command while waiting for the lock */
|
||||
aborted = test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
if (unlikely(aborted)) {
|
||||
@@ -2400,7 +2404,6 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
out_unlock:
|
||||
scst_pr_write_unlock(dev);
|
||||
|
||||
out_put_buf_full:
|
||||
scst_put_buf_full(cmd, buffer);
|
||||
|
||||
out_done:
|
||||
@@ -2438,7 +2441,6 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
|
||||
/*
|
||||
* The original command passed all checks and not finished yet
|
||||
*/
|
||||
sBUG_ON(cmd->dec_pr_readers_count_needed);
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -2455,7 +2457,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
|
||||
if ((cmd->op_flags & SCST_REG_RESERVE_ALLOWED) == 0) {
|
||||
scst_set_cmd_error_status(cmd,
|
||||
SAM_STAT_RESERVATION_CONFLICT);
|
||||
goto out_dec_pr_readers_count;
|
||||
goto out_complete;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2466,8 +2468,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
|
||||
SAM_STAT_RESERVATION_CONFLICT);
|
||||
goto out_complete;
|
||||
}
|
||||
} else
|
||||
scst_dec_pr_readers_count(cmd, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2521,10 +2522,6 @@ out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_dec_pr_readers_count:
|
||||
if (cmd->dec_pr_readers_count_needed)
|
||||
scst_dec_pr_readers_count(cmd, false);
|
||||
|
||||
out_complete:
|
||||
res = 1;
|
||||
sBUG_ON(!cmd->completed);
|
||||
@@ -5163,7 +5160,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt,
|
||||
continue;
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
local_irq_disable();
|
||||
local_irq_disable_nort();
|
||||
list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list,
|
||||
blocked_cmd_list_entry) {
|
||||
|
||||
@@ -5177,10 +5174,10 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt,
|
||||
TRACE_MGMT_DBG("Unblock aborted blocked cmd %p", cmd);
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
local_irq_enable_nort();
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
local_irq_disable();
|
||||
local_irq_disable_nort();
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
|
||||
dev_tgt_dev_list_entry) {
|
||||
struct scst_order_data *order_data = tgt_dev->curr_order_data;
|
||||
@@ -5203,7 +5200,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt,
|
||||
}
|
||||
spin_unlock(&order_data->sn_lock);
|
||||
}
|
||||
local_irq_enable();
|
||||
local_irq_enable_nort();
|
||||
}
|
||||
|
||||
if (!scst_mutex_held)
|
||||
@@ -6241,7 +6238,7 @@ static int scst_post_rx_mgmt_cmd(struct scst_session *sess,
|
||||
sBUG();
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
local_irq_save_nort(flags);
|
||||
|
||||
spin_lock(&sess->sess_list_lock);
|
||||
|
||||
@@ -6270,7 +6267,7 @@ static int scst_post_rx_mgmt_cmd(struct scst_session *sess,
|
||||
list_add_tail(&mcmd->mgmt_cmd_list_entry, &scst_active_mgmt_cmd_list);
|
||||
spin_unlock(&scst_mcmd_lock);
|
||||
|
||||
local_irq_restore(flags);
|
||||
local_irq_restore_nort(flags);
|
||||
|
||||
wake_up(&scst_mgmt_cmd_list_waitQ);
|
||||
|
||||
@@ -6280,7 +6277,7 @@ out:
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&sess->sess_list_lock);
|
||||
local_irq_restore(flags);
|
||||
local_irq_restore_nort(flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
+25
-12
@@ -2,10 +2,6 @@
|
||||
# A Makefile for the scst-local ...
|
||||
#
|
||||
|
||||
ifndef PREFIX
|
||||
PREFIX=/usr/local
|
||||
endif
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
KMOD := $(shell pwd)/kernel
|
||||
@@ -24,24 +20,40 @@ EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
|
||||
|
||||
EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions
|
||||
|
||||
ifneq ($(PATCHLEVEL),)
|
||||
obj-m := scst_local.o
|
||||
else
|
||||
######### BEGIN OUT-OF-TREE RULES #########
|
||||
|
||||
ifndef PREFIX
|
||||
PREFIX=/usr/local
|
||||
endif
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
endif
|
||||
else
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifneq ($(PATCHLEVEL),)
|
||||
obj-m := scst_local.o
|
||||
else
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \
|
||||
then echo "$$PWD/../scst/include"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
SCST_DIR := $(shell if [ -e "$$PWD/../scst" ]; \
|
||||
then echo "$$PWD/../scst/src"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
|
||||
all: Modules.symvers Module.symvers
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
@@ -50,7 +62,6 @@ all: Modules.symvers Module.symvers
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \
|
||||
SCST_INC_DIR=$(SCST_INC_DIR) modules_install
|
||||
-/sbin/depmod -aq $(KVER)
|
||||
|
||||
SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null)
|
||||
ifneq ($(SCST_MOD_VERS),)
|
||||
@@ -71,7 +82,9 @@ endif
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/scst_local.ko
|
||||
-/sbin/depmod -a $(KVER)
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
########## END OUT-OF-TREE RULES ##########
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_SCST_LOCAL) += scst_local.o
|
||||
|
||||
+12
-9
@@ -375,9 +375,10 @@ static ssize_t scst_local_stats_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
|
||||
{
|
||||
return sprintf(buf, "Aborts: %d, Device Resets: %d, Target Resets: %d",
|
||||
atomic_read(&num_aborts), atomic_read(&num_dev_resets),
|
||||
atomic_read(&num_target_resets));
|
||||
return sprintf(buf,
|
||||
"Aborts: %d, Device Resets: %d, Target Resets: %d\n",
|
||||
atomic_read(&num_aborts), atomic_read(&num_dev_resets),
|
||||
atomic_read(&num_target_resets));
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_local_stats_attr =
|
||||
@@ -960,6 +961,14 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt,
|
||||
|
||||
TRACE_DBG("lun %d, cmd: 0x%02X", SCpnt->device->lun, SCpnt->cmnd[0]);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
|
||||
/*
|
||||
* We save a pointer to the done routine in SCpnt->scsi_done and
|
||||
* we save that as tgt specific stuff below.
|
||||
*/
|
||||
SCpnt->scsi_done = done;
|
||||
#endif
|
||||
|
||||
sess = to_scst_lcl_sess(scsi_get_device(SCpnt->device->host));
|
||||
|
||||
if (sess->unregistering) {
|
||||
@@ -983,12 +992,6 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt,
|
||||
}
|
||||
tgt_specific->cmnd = SCpnt;
|
||||
tgt_specific->done = done;
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
|
||||
/*
|
||||
* We save a pointer to the done routine in SCpnt->scsi_done and
|
||||
* we save that as tgt specific stuff below.
|
||||
*/
|
||||
SCpnt->scsi_done = done;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -136,7 +136,6 @@ rpm:
|
||||
rpmtopdir="$$(if [ $$(id -u) = 0 ]; then echo /usr/src/packages;\
|
||||
else echo $$PWD/rpmbuilddir; fi)" && \
|
||||
$(MAKE) dist-gzip && \
|
||||
rm -rf $${rpmtopdir} && \
|
||||
for d in BUILD RPMS SOURCES SPECS SRPMS; do \
|
||||
mkdir -p $${rpmtopdir}/$$d; \
|
||||
done && \
|
||||
|
||||
@@ -14,7 +14,7 @@ TARGET_DRIVER scst_local {
|
||||
LUN 0 disk01
|
||||
LUN 1 disk01
|
||||
|
||||
GROUP initator_group {
|
||||
GROUP initiator_group {
|
||||
LUN 0 disk01
|
||||
LUN 1 disk01 {
|
||||
read_only 1
|
||||
|
||||
@@ -20,7 +20,7 @@ TARGET_DRIVER scst_local {
|
||||
LUN 0 disk01
|
||||
LUN 1 disk01
|
||||
|
||||
GROUP initator_group {
|
||||
GROUP initiator_group {
|
||||
LUN 0 disk01
|
||||
LUN 1 disk01 {
|
||||
read_only 1
|
||||
|
||||
+25
-10
@@ -7,23 +7,35 @@ endif
|
||||
|
||||
SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \
|
||||
then echo "$$PWD/../scst/include"; \
|
||||
else echo "$(PREFIX)/include/scst"; fi)
|
||||
else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi)
|
||||
SCST_SYMVERS_DIR := $(shell if [ -e $$PWD/../scst ]; then \
|
||||
echo $$PWD/../scst/src; \
|
||||
else echo $(PREFIX)/include/scst; fi)
|
||||
else echo $(DESTDIR)$(PREFIX)/include/scst; fi)
|
||||
SUBDIRS := $(shell pwd)
|
||||
|
||||
ifeq ($(KVER),)
|
||||
ifeq ($(KDIR),)
|
||||
KVER = $(shell uname -r)
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
else
|
||||
KVER = $$KERNELRELEASE
|
||||
ifeq ($(KERNELRELEASE),)
|
||||
KVER := $(strip $(shell \
|
||||
cat $(KDIR)/include/config/kernel.release 2>/dev/null || \
|
||||
make -s -C $(KDIR) kernelversion))
|
||||
else
|
||||
KVER := $(KERNELRELEASE)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
KDIR ?= /lib/modules/$(KVER)/build
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
endif
|
||||
|
||||
ifeq ($(INSTALL_MOD_PATH),)
|
||||
export INSTALL_MOD_PATH := $(DESTDIR)
|
||||
endif
|
||||
|
||||
INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
|
||||
|
||||
# Set variable $(2) to value $(3) in file $(1).
|
||||
set_var = $(shell { if [ -e "$(1)" ]; then grep -v '^$(2)=' "$(1)"; fi; echo "$(2)=$(3)"; } >/tmp/$(1)-$$$$.tmp && mv /tmp/$(1)-$$$$.tmp $(1))
|
||||
|
||||
@@ -59,10 +71,13 @@ all: src/$(MODULE_SYMVERS)
|
||||
PRE_CFLAGS="$(OFED_CFLAGS)" SCST_INC_DIR=$(SCST_INC_DIR) modules
|
||||
|
||||
install: all src/ib_srpt.ko
|
||||
@eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KDIR)/include/linux/version.h $(KDIR)/include/linux/utsrelease.h 2>/dev/null`; \
|
||||
install -vD -m 644 src/ib_srpt.ko \
|
||||
$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/ib_srpt.ko
|
||||
-/sbin/depmod -aq $(KVER)
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src \
|
||||
PRE_CFLAGS="$(OFED_CFLAGS)" SCST_INC_DIR=$(SCST_INC_DIR) \
|
||||
modules_install
|
||||
|
||||
uninstall:
|
||||
rm -f $(INSTALL_DIR)/ib_srpt.ko
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
src/Module.symvers src/Modules.symvers: $(SCST_SYMVERS_DIR)/$(MODULE_SYMVERS)
|
||||
@if $(OFED_KERNEL_IB_RPM_INSTALLED); then \
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 540f7b2..078307f 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -361,6 +361,7 @@ USERINCLUDE := \
|
||||
# Use LINUXINCLUDE when you must reference the include/ directory.
|
||||
# Needed to be compatible with the O= option
|
||||
LINUXINCLUDE := \
|
||||
+ $(PRE_CFLAGS) \
|
||||
-I$(srctree)/arch/$(hdr-arch)/include \
|
||||
-Iarch/$(hdr-arch)/include/generated \
|
||||
$(if $(KBUILD_SRC), -I$(srctree)/include) \
|
||||
+7
-3
@@ -2340,17 +2340,21 @@ static void srpt_drain_channel(struct ib_cm_id *cm_id)
|
||||
|
||||
static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt)
|
||||
{
|
||||
struct srpt_rdma_ch *ch, *next_ch;
|
||||
struct srpt_rdma_ch *ch;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
||||
lockdep_assert_held(&srpt_tgt->spinlock);
|
||||
#endif
|
||||
|
||||
list_for_each_entry_safe(ch, next_ch, &srpt_tgt->rch_list, list) {
|
||||
restart:
|
||||
list_for_each_entry(ch, &srpt_tgt->rch_list, list) {
|
||||
if (ch->state >= CH_DISCONNECTING)
|
||||
continue;
|
||||
PRINT_INFO("Closing channel %s because target %s has been"
|
||||
" disabled", ch->sess_name,
|
||||
srpt_tgt->scst_tgt->tgt_name);
|
||||
__srpt_close_ch(ch);
|
||||
WARN_ON_ONCE(!__srpt_close_ch(ch));
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ OBJS_F = $(SRCS_F:.c=.o)
|
||||
|
||||
SCST_INC_DIR := ../../scst/include
|
||||
#SCST_INC_DIR := $(PREFIX)/include/scst
|
||||
INSTALL_DIR := $(PREFIX)/bin/scst
|
||||
INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin/scst
|
||||
|
||||
CFLAGS += -O2 -Wall -Wextra -Wno-unused-parameter -Wstrict-prototypes \
|
||||
-I$(SCST_INC_DIR) -D_GNU_SOURCE -D__USE_FILE_OFFSET64 \
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="author" content="Daniel Fernandes">
|
||||
<meta name="Robots" content="index,follow">
|
||||
<link rel="stylesheet" href="images/Orange.css" type="text/css">
|
||||
<title>Emulex lpfc FC/FCoE target driver</title>
|
||||
<title>Emulex FC/FCoE target driver</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
@@ -56,17 +56,17 @@
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
<h1>Target driver for Emulex lpfc FC/FCoE adapters</h1>
|
||||
<h1>Target driver for Emulex FC/FCoE adapters</h1>
|
||||
<p><img src="images/t_emulex.gif" width="100" height="120" class="float-left" alt="SCST Emulex">
|
||||
|
||||
<p>The ocs_fc_scst target driver for Emulex lpfc FC/FCoE adapters is developed by the Emulex team
|
||||
and is available at the <a href="http://www.emulex.com/products/onecore-storage-software-development-kit/overview.html" class="readmore">Emulex OneCore SDK</a>
|
||||
developer site. Register for free at the <a href="http://www.emulex.com/products/onecore-storage-software-development-kit/developer-portal-access.html" class="readmore">Developer Portal Access</a>
|
||||
<p>The ocs_fc_scst target driver for Emulex FC/FCoE adapters is developed by the Emulex team
|
||||
and is available at the <a href="http://www.emulex.com/partners/onecore-storage-sdk-program/overview" class="readmore">Emulex OneCore SDK</a>
|
||||
developer site. Register for free at the <a href="http://www.emulex.com/partners/onecore-storage-sdk-program/developer-portal-access/" class="readmore">Developer Portal Access</a>
|
||||
page to get the source code and documentation. The Emulex OneCore SDK is built around the Emulex SLI-4
|
||||
(Service Level Interface) API and is compatible with Emulex 16 Gb/s Fibre Channel HBAs (LPe16000 series)
|
||||
and Ethernet based target mode FCoE UCNAs (OCe11102-F series).</p>
|
||||
|
||||
<p>The ocs_fc_scst driver allows for lpfc adapters to be placed in initiator and/or target mode.
|
||||
<p>The ocs_fc_scst driver allows for Emulex adapters to be placed in initiator and/or target mode.
|
||||
The driver effectively maps SCST to the Emulex SLI-4 interface allowing a simple transition to Emulex 16Gb/s
|
||||
fibre channel technology for existing or new SCST users. NPIV is also supported, allowing virtual
|
||||
ports to be created with individual SCST target instances bound to them.
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
<br><br>
|
||||
<p class="post-footer align-right">
|
||||
<a href="http://www.emulex.com/products/onecore-storage-software-development-kit/overview.html" class="readmore">Emulex OneCore SDK</a>
|
||||
<a href="http://www.emulex.com/partners/onecore-storage-sdk-program/overview" class="readmore">Emulex OneCore SDK</a>
|
||||
</p>
|
||||
<table border=0><tr><td height="300px"> </td></tr></table>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
|
||||
+2
-2
@@ -41,7 +41,7 @@
|
||||
<li><a href="target_qla2x00t.html">QLogic FC qla2x00t</a></li>
|
||||
<li><a href="target_srp.html">SCSI RDMA Protocol (SRP)</a></li>
|
||||
<li><a href="target_mvsas.html">Marvell SAS adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex lpfc FC/FCoE adapters</a></li>
|
||||
<li><a href="target_emulex.html">Emulex FC/FCoE adapters</a></li>
|
||||
<li><a href="target_lsi.html">LSI/MPT adapters</a></li>
|
||||
<li><a href="target_fcoe.html">FCoE Target</a></li>
|
||||
<li><a href="target_local.html">Local Target Driver</a></li>
|
||||
@@ -64,7 +64,7 @@
|
||||
<li><span>Fibre Channel QLogic qla2xxx series</span></li>
|
||||
<li><span>Infiniband SCSI RDMA Protocol (SRP)</span></li>
|
||||
<li><span>Marvell SAS adapters</span></li>
|
||||
<li><span>Emulex lpfc FC/FCoE adapters</span></li>
|
||||
<li><span>Emulex FC/FCoE adapters</span></li>
|
||||
<li><span>LSI/MPT adapters (parallel SCSI, including Wide Ultra320, SAS, Fibre Channel)</span></li>
|
||||
<li><span>FCoE</span></li>
|
||||
<li><span>Local access</span></li>
|
||||
|
||||
Reference in New Issue
Block a user