Skip to content

Commit

Permalink
iSCSI Integration (shareiscsi)
Browse files Browse the repository at this point in the history
This is iSCSI sharing for ZoL (shareiscsi).
* Supports the following iSCSI implementations (in this order of discovery):
  + IET         http://iscsitarget.sourceforge.net
  + STGT        http://stgt.berlios.de
  + SCST        http://scst.sourceforge.net
    + Requires that SCST was compiled with /sys support (the default).
  + LIO         http://linux-iscsi.org
* Will refuse to unshares an active target (one with sessions).
* Supports the following options to the 'shareiscsi' property:
  + name/iqn    Full iSCSI Qualified Name (IQN), including identifier.
                This is generated by iscsi_generate_target():
                + Uses the content of an optional /etc/iscsi_target_id file:
                  Example: iqn.YYYY-MM.tld.domain
                + If this file doesn't exist, it uses the current year, month
                  and domain name to generate the iqn.
                + The dataset name is appended at the end of the iqn, with
                  slashes replaced with dots.
                  => <iqn>:<dataset>
  + lun         LUN (0-16384)
                Default: 0 (1 for STGT)
  + type        Share mode (fileio, blockio, nullio, disk, tape)
                STGT: ssc, pt
                Default: blockio (disk for STGT)
  + iomode      IO mode (wb, wt, ro)
                STGT: rdwr, aio, mmap, sg, ssc
                Default: wt (rdwr for STGT)
  + blocksize   Logical block size (512, 1024, 2048, 4096)
                Default: Volume blocksize, 4096 if not usable.
                NOTE: Currently not supported for STGT (doesn't seem to be
                      an option for it in tgtadm).
  + initiator   Allow only this initiator to bind to target.
                Currently only availible for LIO, STGT and SCST.
  + authname    Global user to use in binds on targets.
  + authpass    Password for global user.
* If not called with a 'name/iqn' value, then force setting it.
  This so that the IQN doesn't change every month (when it is
  regenerated again). It will be generated by iscsi_generate_target()
  (see above).

NOTE:
+ Moved nfs.c:foreach_nfs_shareopt() to libshare.c:foreach_shareopt()
  so that it can be (re)used in smb.c and iscsi.c.
+ Split iSCSI implementation into their own separate source files
+ Use the list_{create,insert}() etc for keeping tabs of the linked lists
  instead of using a home-made version.
+ A half second delay had to be added in lib/libzfs/libzfs_mount.c:zfs_unmount()
  after the successful unshare. This to avoid 'dataset busy' when destroying
  recursivly.
= The 'initiator', 'authname' and 'authpass' option might have some issues:
  It will make the compatibility between the different iSCSI implementations
  questionable - can't switch between them easily (it will ONLY be availible
  in ZoL). I COULD make the option be silently ignored (instead of forcibly
  rejected if not availible).

  But that still doesn't solve the (possible) problem between ZoL and
  OpenZFS/Illumos (setting the option, will possibly introduce problems when
  importing the pool on something else than ZoL).

  So some more discussion might be needed..
  • Loading branch information
FransUrbo authored and behlendorf committed Mar 4, 2015
1 parent d8be51d commit 67aa029
Show file tree
Hide file tree
Showing 33 changed files with 6,138 additions and 353 deletions.
563 changes: 346 additions & 217 deletions cmd/zfs/zfs_main.c

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ typedef enum zfs_error {
EZFS_DIFF, /* general failure of zfs diff */
EZFS_DIFFDATA, /* bad zfs diff data */
EZFS_POOLREADONLY, /* pool is in read-only mode */
EZFS_UNSHAREISCSIFAILED, /* failed to unshare over iSCSI */
EZFS_SHAREISCSIFAILED, /* failed to share over iSCSI */
EZFS_UNKNOWN
} zfs_error_t;

Expand Down Expand Up @@ -566,6 +568,7 @@ typedef struct get_all_cb {
zfs_handle_t **cb_handles;
size_t cb_alloc;
size_t cb_used;
uint_t cb_types;
boolean_t cb_verbose;
int (*cb_getone)(zfs_handle_t *, void *);
} get_all_cb_t;
Expand Down Expand Up @@ -721,13 +724,17 @@ extern int zfs_unshare(zfs_handle_t *);
*/
extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **);
extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *, char **);
extern int zfs_share_nfs(zfs_handle_t *);
extern int zfs_share_smb(zfs_handle_t *);
extern int zfs_share_iscsi(zfs_handle_t *);
extern int zfs_shareall(zfs_handle_t *);
extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
extern int zfs_unshare_smb(zfs_handle_t *, const char *);
extern int zfs_unshare_iscsi(zfs_handle_t *, const char *);
extern int zfs_unshareall_nfs(zfs_handle_t *);
extern int zfs_unshareall_smb(zfs_handle_t *);
extern int zfs_unshareall_iscsi(zfs_handle_t *);
extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
extern int zfs_unshareall(zfs_handle_t *);
extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *,
Expand Down
6 changes: 4 additions & 2 deletions include/libzfs_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ struct zpool_handle {
typedef enum {
PROTO_NFS = 0,
PROTO_SMB = 1,
PROTO_END = 2
PROTO_ISCSI = 2,
PROTO_END = 3
} zfs_share_proto_t;

/*
Expand All @@ -133,7 +134,8 @@ typedef enum {
typedef enum {
SHARED_NOT_SHARED = 0x0,
SHARED_NFS = 0x2,
SHARED_SMB = 0x4
SHARED_SMB = 0x4,
SHARED_ISCSI = 0x8
} zfs_share_type_t;

int zfs_error(libzfs_handle_t *, int, const char *);
Expand Down
5 changes: 4 additions & 1 deletion include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ typedef enum {
ZFS_PROP_RELATIME,
ZFS_PROP_REDUNDANT_METADATA,
ZFS_PROP_OVERLAY,
ZFS_PROP_SHAREISCSI,
ZFS_NUM_PROPS
} zfs_prop_t;

Expand Down Expand Up @@ -326,7 +327,9 @@ typedef enum zfs_share_op {
ZFS_SHARE_NFS = 0,
ZFS_UNSHARE_NFS = 1,
ZFS_SHARE_SMB = 2,
ZFS_UNSHARE_SMB = 3
ZFS_UNSHARE_SMB = 3,
ZFS_SHARE_ISCSI = 4,
ZFS_UNSHARE_ISCSI = 5
} zfs_share_op_t;

typedef enum zfs_smb_acl_op {
Expand Down
11 changes: 10 additions & 1 deletion lib/libshare/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,13 @@ libshare_la_SOURCES = \
$(top_srcdir)/lib/libshare/nfs.c \
$(top_srcdir)/lib/libshare/nfs.h \
$(top_srcdir)/lib/libshare/smb.c \
$(top_srcdir)/lib/libshare/smb.h
$(top_srcdir)/lib/libshare/smb.h \
$(top_srcdir)/lib/libshare/iscsi.c \
$(top_srcdir)/lib/libshare/iscsi_iet.c \
$(top_srcdir)/lib/libshare/iscsi_lio.c \
$(top_srcdir)/lib/libshare/iscsi_scst.c \
$(top_srcdir)/lib/libshare/iscsi_stgt.c \
$(top_srcdir)/lib/libshare/iscsi.h

libshare_la_LIBADD = \
$(top_builddir)/lib/libspl/libspl.la
124 changes: 124 additions & 0 deletions lib/libshare/README_iscsi.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
This is iSCSI support for the IET, SCST and STGT iSCSI target implementations.

Implementation URL Package name(s)
IET http://iscsitarget.sourceforge.net iscsitarget + iscsitarget-dkms
SCST http://scst.sourceforge.net iscsi-scst + scst-dkms + scst-fileio-tgt + scstadmin
STGT http://stgt.berlios.de tgt
LIO http://linux-iscsi.org lio-utils + targetcli

It will call ietmadm (for IET), tgtadm (for STGT) or modify files in
/sys/kernel/scst_tgt (for SCST) or /sys/kernel/config/target (for LIO) to both
add or remove a iSCSI target from the call to 'zfs share':

zfs create -s -V10G mypool/test
zfs set shareiscsi=on mypool/test

There is no need to issue 'zfs share tank/test', because ZFS will
automatically issue the corresponding share command(s) when setting
(or modifying) the shareiscsi property.


The driver will execute the following commands to setup a target (example!):

* For IET:

/usr/sbin/ietadm --op new --tid TID --params Name=iqn.2010-09.org.zfsonlinux:mypool.test
/usr/sbin/ietadm --op new --tid TID --lun LUN --params Path=/dev/zvol/mypool/test,Type=fileio

* For STGT:

tgtadm --lld iscsi --op new --mode target --tid TID -T iqn.2010-09.org.zfsonlinux:share.test
tgtadm --lld iscsi --op new --mode logicalunit --tid TID --lun 1 -b /dev/zvol/mypool/test
tgtadm --lld iscsi --op bind --mode target --tid TID --initiator-address ALL

* For SCST:

SYSFS_SCST="/sys/kernel/scst_tgt"

echo "add_target iqn.2010-09.org.zfsonlinux:mypool.test" > $SYSFS_SCST/targets/iscsi/mgmt
echo "add_device DEVICE filename=/dev/zvol/mypool/test; blocksize=BLOCKSIZE" > $SYSFS_SCST/handlers/vdisk_blockio/mgmt
echo "add DEVICE LUN" > $SYSFS_SCST/targets/iscsi/iqn.2010-09.org.zfsonlinux:mypool.test/luns/mgmt
echo 1 > $SYSFS_SCST/targets/iscsi/iqn.2010-09.org.zfsonlinux:mypool.test/enabled

* For LIO

SYSFS_LIO="/sys/kernel/config/target"

# TEST DATA:
ip=$(ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | head -n1 | sed "s@.*addr:\(.*\) Bcast.*@\1@")
md5=$(date | md5sum | cut -f1 -d' ')

# SETUP Device
mkdir -p $SYSFS_LIO/core/iblock_TID/mypool.test
echo -n "/dev/zvol/mypool/test" > $SYSFS_LIO/core/iblock_TID/mypool.test/udev_path
echo -n "udev_path=/dev/zvol/mypool/test" > $SYSFS_LIO/core/iblock_TID/mypool.test/control
echo -n $md5 > $SYSFS_LIO/core/iblock_TID/mypool.test/wwn/vpd_unit_serial
echo 1 > $SYSFS_LIO/core/iblock_TID/mypool.test/enable
echo 4096 > $SYSFS_LIO/core/iblock_TID/mypool.test/attrib/block_size
echo 0 > $SYSFS_LIO/core/iblock_TID/mypool.test/attrib/emulate_tas
echo 0 > $SYSFS_LIO/core/iblock_TID/mypool.test/attrib/emulate_ua_intlck_ctrl

# SETUP IQN/Target
mkdir -p $SYSFS_LIO/iscsi/iqn.2010-09.org.zfsonlinux:mypool.test/tpgt_TID/np/$ip:3260
mkdir -p $SYSFS_LIO/iscsi/iqn.2010-09.org.zfsonlinux:mypool.test/tpgt_TID/lun/lun_LUN
ln -s $SYSFS_LIO/core/iblock_TID/mypool.test \
$SYSFS_LIO/iscsi/iqn.2010-09.org.zfsonlinux:mypool.test/tpgt_TID/lun/lun_LUN/$md5
echo -n 0 > $SYSFS_LIO/iscsi/discovery_auth/enforce_discovery_auth
echo 0 > $SYSFS_LIO/iscsi/iqn.2010-09.org.zfsonlinux:mypool.test/tpgt_TID/attrib/authentication
echo 1 > $SYSFS_LIO/iscsi/iqn.2010-09.org.zfsonlinux:mypool.test/tpgt_TID/enable

Here the value DEVICE is generated by iscsi.c:iscsi_generate_scst_device_name()
and is a randomized value, based on the exact time of day when
called. This because SCST have a limit of 16 characters for the device
name, and the chances of have duplicates is large. The BLOCKSIZE that
is used depends on what blocksize the ZVOL was created with.

The LUN value is by default 0 (1 for STGT becase LUN0 is the controller),
but can be overridden using the 'lun' option to the 'shareiscsi' property.

It (the driver) will automatically calculate the TID and IQN and use
only the ZVOL (in this case 'share/test') in the command lines.

If autogenerating the IQN is not wanted (because each reboot or unshare/share,
if it's done in another month, will generate a new IQN), a hardcoded default
can be set in /etc/iscsi_target_id like so:

echo iqn.2010-09.org.zfsonlinux > /etc/iscsi_target_id

Then all targets will start with this value, only adding a colon
and the ZVOL/dataset name (slashes replaced with dots):

iqn.2010-09.org.zfsonlinux:mypool.test


In addition to executing ietadm, tgtadm or modifying files below
/sys/kernel/scst_tgt or /sys/kernel/config/target, zfs will execute
the following script (if it exist and is executable)
'/sbin/zfs_share_iscsi.sh', like so:

/sbin/zfs_share_iscsi TID

This is so that one can create custom commands to be done on the
share.

The only parameter to this script/executable is the TID and the
driver will 'execute and forget'. Meaning, it will not care about
exit code nor any output it gives.

Example scripts have been provided, on for each of the iSCSI
implementation supported:

zfs_share_iscsi.iet
zfs_share_iscsi.lio
zfs_share_iscsi.scst
zfs_share_iscsi.stgt

Simply copy the one for your iSCSI implementation to /sbin/zfs_share/iscsi
and then modify it to your requirenments.

PS. The domainname needs to be set (in /proc/sys/kernel/domainname
using either 'sysctl', 'echo' or the command 'domainname') for
the driver to be able to work out the iqn correctly.

NOTE: This is only required if the IQN haven't been set in the
/etc/iscsi_target_id file!
29 changes: 29 additions & 0 deletions lib/libshare/destroy_lio.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/sh

# This is a script to simply unshare all LIO targets, without going through
# ZFS. Mostly used for testing...

SYSFS=/sys/kernel/config/target

cd $SYSFS/iscsi/
if [ -z "$*" ]; then
targets=`echo iqn.*`
else
targets=`echo $*`
fi

for name in $targets; do
tid=`echo $SYSFS/core/iblock_*/$name | sed "s@.*iblock_\(.*\)/.*@\1@"`
lnk=`find $SYSFS/iscsi/$name/tpgt_$tid/lun/lun_*/* | egrep -v 'alua|statistics' | sed 's@.*/@@'`

echo 0 > $SYSFS/iscsi/$name/tpgt_$tid/enable

rmdir $SYSFS/iscsi/$name/tpgt_$tid/np/*
rm $SYSFS/iscsi/$name/tpgt_$tid/lun/lun_*/$lnk
rmdir $SYSFS/iscsi/$name/tpgt_$tid/lun/lun_*
rmdir $SYSFS/iscsi/$name/tpgt_$tid
rmdir $SYSFS/iscsi/$name

rmdir $SYSFS/core/iblock_$tid/$name
rmdir $SYSFS/core/iblock_$tid
done
32 changes: 32 additions & 0 deletions lib/libshare/destroy_scst.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

# This is a script to somply unshare all SCST targets, without going through
# ZFS. Mostly used for testing...

SYSFS=/sys/kernel/scst_tgt

cd $SYSFS/targets/iscsi/
if [ -z "$*" ]; then
targets=`echo iqn.*`
else
targets=`echo $*`
fi

for name in $targets; do
find $SYSFS/targets/iscsi/$name/sessions/* -type d > /dev/null 2>&1
if [ "$?" -eq "1" ]; then
[ ! -f "$SYSFS/targets/iscsi/$name/enabled" ] && continue

#scstadmin -noprompt -disable_target $name -driver iscsi
echo 0 > $SYSFS/targets/iscsi/$name/enabled

#scstadmin -noprompt -close_dev $dev -handler vdisk_blockio
dev=`/bin/ls -l $SYSFS/targets/iscsi/$name/luns/0/device | sed 's@.*/@@'`
echo "del_device $dev" > $SYSFS/handlers/vdisk_blockio/mgmt

#scstadmin -noprompt -rem_target $name -driver iscsi
echo "del_target $name" > $SYSFS/targets/iscsi/mgmt
else
echo "Can't destroy $name - have sessions"
fi
done
Loading

0 comments on commit 67aa029

Please sign in to comment.