From ec295c835af38ec62f9956435af543eae7fad7a7 Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Mon, 13 Feb 2012 10:27:01 +0100 Subject: [PATCH 1/5] Add 'fsid' mount option to allowed options. --- lib/libshare/nfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libshare/nfs.c b/lib/libshare/nfs.c index 22e306d4370f..56725d27c356 100644 --- a/lib/libshare/nfs.c +++ b/lib/libshare/nfs.c @@ -360,7 +360,7 @@ get_linux_shareopts_cb(const char *key, const char *value, void *cookie) strcmp(key, "root_squash") != 0 && strcmp(key, "no_root_squash") != 0 && strcmp(key, "all_squash") != 0 && - strcmp(key, "no_all_squash") != 0 && + strcmp(key, "no_all_squash") != 0 && strcmp(key, "fsid") != 0 && strcmp(key, "anonuid") != 0 && strcmp(key, "anongid") != 0) { return SA_SYNTAX_ERR; } From d2383c9dbd1aa263d5c4fdedaacfa3150867a09e Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Sat, 18 Feb 2012 11:05:09 +0100 Subject: [PATCH 2/5] Mark the Release with the last GIT commit date. --- META | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/META b/META index f70acabe066c..38248d23b97b 100644 --- a/META +++ b/META @@ -1,7 +1,7 @@ Meta: 1 Name: zfs Branch: 1.0 -Version: 0.6.0 +Version: 0.6.0_20120217 Release: rc6 Release-Tags: relext License: CDDL From ff1c107ea9a6ec1f67dbd0625f598c3e0768fdfa Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Sat, 18 Feb 2012 11:09:43 +0100 Subject: [PATCH 3/5] Oups! Put it (last GIT commit date) in Release, not Version! --- META | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/META b/META index 38248d23b97b..92cda1f9743d 100644 --- a/META +++ b/META @@ -1,8 +1,8 @@ Meta: 1 Name: zfs Branch: 1.0 -Version: 0.6.0_20120217 -Release: rc6 +Version: 0.6.0 +Release: rc6_20120217 Release-Tags: relext License: CDDL Author: Sun Microsystems/Oracle, Lawrence Livermore National Laboratory From 07bf3a3122b22e13ea46290d241fa2cda7c5e756 Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Sat, 4 Feb 2012 21:08:53 +0100 Subject: [PATCH 4/5] SMBFS sharing for ZoL. Sixth official patch attempt. Previous ones was/is lost in my inability with GIT. * Fix issues after review by behlendorf. = Move comments etc from the README to the code and to the manpage. = Adhere to the 80 char line limit. = Cast constants when setting argv[x]. = More defines, concentrated at the top. = Move smb_retrieve_shares() to the top, to avoid forward declaration. = Make private functions static. = Remove all debugging. = Whitespace fixes. = Return SA_OK instead of 0 where needed. = Remove some fprintf(stderr, "ERROR: ...") strings. Not needed really, they where mostly for debugging any way. = Bump release. = Add missing locale.h include. = Add file_is_executable(). = Remove file_is_executable() per request from Brian. * Some minor SMBFS fixes, comments from Richard Laager: = Remove redundant variable = NULL check. = Rewrite static 'net' command options define's = Remove commented out/redundant line parsing code. = Add Samba host options to net command in smb_disable_share_one() as well. * Fixes after second review by behlendorf. = Putting back things that wasn't mine that I removed or changed.. = Remove the file_is_executable() declaration that came back some how. = Reword, rewrite and indent information about how to setup Samba. = Implement smb_validate_shareopts(). * Fixes after third review by Prakash-Surya. = Removed missplaced space. --- lib/libshare/Makefile.am | 6 +- lib/libshare/Makefile.in | 647 +++++++++++++++++++++++++++++++++++++++ lib/libshare/libshare.c | 2 + lib/libshare/smb.c | 399 ++++++++++++++++++++++++ lib/libshare/smb.h | 26 ++ man/man8/zfs.8 | 13 + 6 files changed, 1091 insertions(+), 2 deletions(-) create mode 100644 lib/libshare/Makefile.in create mode 100644 lib/libshare/smb.c create mode 100644 lib/libshare/smb.h diff --git a/lib/libshare/Makefile.am b/lib/libshare/Makefile.am index 1439b33ac804..53c1223ef26a 100644 --- a/lib/libshare/Makefile.am +++ b/lib/libshare/Makefile.am @@ -8,6 +8,8 @@ noinst_LTLIBRARIES = libshare.la libshare_la_SOURCES = \ $(top_srcdir)/lib/libshare/libshare.c \ - $(top_srcdir)/lib/libshare/nfs.c \ $(top_srcdir)/lib/libshare/libshare_impl.h \ - $(top_srcdir)/lib/libshare/nfs.h + $(top_srcdir)/lib/libshare/nfs.c \ + $(top_srcdir)/lib/libshare/nfs.h \ + $(top_srcdir)/lib/libshare/smb.c \ + $(top_srcdir)/lib/libshare/smb.h diff --git a/lib/libshare/Makefile.in b/lib/libshare/Makefile.in new file mode 100644 index 000000000000..1a3096ccd4a9 --- /dev/null +++ b/lib/libshare/Makefile.in @@ -0,0 +1,647 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/config/Rules.am +subdir = lib/libshare +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \ + $(top_srcdir)/config/kernel-automount.m4 \ + $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \ + $(top_srcdir)/config/kernel-bdev-logical-size.m4 \ + $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \ + $(top_srcdir)/config/kernel-bdi.m4 \ + $(top_srcdir)/config/kernel-bio-empty-barrier.m4 \ + $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \ + $(top_srcdir)/config/kernel-bio-failfast.m4 \ + $(top_srcdir)/config/kernel-bio-rw-syncio.m4 \ + $(top_srcdir)/config/kernel-blk-end-request.m4 \ + $(top_srcdir)/config/kernel-blk-fetch-request.m4 \ + $(top_srcdir)/config/kernel-blk-queue-discard.m4 \ + $(top_srcdir)/config/kernel-blk-queue-flush.m4 \ + $(top_srcdir)/config/kernel-blk-queue-io-opt.m4 \ + $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \ + $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \ + $(top_srcdir)/config/kernel-blk-queue-nonrot.m4 \ + $(top_srcdir)/config/kernel-blk-queue-physical-block-size.m4 \ + $(top_srcdir)/config/kernel-blk-requeue-request.m4 \ + $(top_srcdir)/config/kernel-blk-rq-bytes.m4 \ + $(top_srcdir)/config/kernel-blk-rq-pos.m4 \ + $(top_srcdir)/config/kernel-blk-rq-sectors.m4 \ + $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \ + $(top_srcdir)/config/kernel-check-disk-size-change.m4 \ + $(top_srcdir)/config/kernel-d-obtain-alias.m4 \ + $(top_srcdir)/config/kernel-evict-inode.m4 \ + $(top_srcdir)/config/kernel-fallocate.m4 \ + $(top_srcdir)/config/kernel-fmode-t.m4 \ + $(top_srcdir)/config/kernel-fsync.m4 \ + $(top_srcdir)/config/kernel-get-disk-ro.m4 \ + $(top_srcdir)/config/kernel-insert-inode-locked.m4 \ + $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \ + $(top_srcdir)/config/kernel-kobj-name-len.m4 \ + $(top_srcdir)/config/kernel-mount-nodev.m4 \ + $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \ + $(top_srcdir)/config/kernel-rq-for-each_segment.m4 \ + $(top_srcdir)/config/kernel-rq-is_sync.m4 \ + $(top_srcdir)/config/kernel-security-inode-init.m4 \ + $(top_srcdir)/config/kernel-set-nlink.m4 \ + $(top_srcdir)/config/kernel-show-options.m4 \ + $(top_srcdir)/config/kernel-shrink.m4 \ + $(top_srcdir)/config/kernel-truncate-setsize.m4 \ + $(top_srcdir)/config/kernel-xattr-handler.m4 \ + $(top_srcdir)/config/kernel.m4 \ + $(top_srcdir)/config/user-arch.m4 \ + $(top_srcdir)/config/user-frame-larger-than.m4 \ + $(top_srcdir)/config/user-ioctl.m4 \ + $(top_srcdir)/config/user-libblkid.m4 \ + $(top_srcdir)/config/user-libuuid.m4 \ + $(top_srcdir)/config/user-nptl_guard_within_stack.m4 \ + $(top_srcdir)/config/user-selinux.m4 \ + $(top_srcdir)/config/user-udev.m4 \ + $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \ + $(top_srcdir)/config/zfs-build.m4 \ + $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/zfs_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libshare_la_LIBADD = +am_libshare_la_OBJECTS = libshare.lo nfs.lo smb.lo +libshare_la_OBJECTS = $(am_libshare_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libshare_la_SOURCES) +DIST_SOURCES = $(libshare_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALIEN = @ALIEN@ +ALIEN_VERSION = @ALIEN_VERSION@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_CFLAGS = @DEBUG_CFLAGS@ +DEBUG_DMU_TX = @DEBUG_DMU_TX@ +DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@ +DEBUG_ZFS = @DEBUG_ZFS@ +DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@ +DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@ +DEFAULT_PACKAGE = @DEFAULT_PACKAGE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DPKG = @DPKG@ +DPKGBUILD = @DPKGBUILD@ +DPKGBUILD_VERSION = @DPKGBUILD_VERSION@ +DPKG_VERSION = @DPKG_VERSION@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FRAME_LARGER_THAN = @FRAME_LARGER_THAN@ +GREP = @GREP@ +HAVE_ALIEN = @HAVE_ALIEN@ +HAVE_DPKG = @HAVE_DPKG@ +HAVE_DPKGBUILD = @HAVE_DPKGBUILD@ +HAVE_MAKEPKG = @HAVE_MAKEPKG@ +HAVE_PACMAN = @HAVE_PACMAN@ +HAVE_RPM = @HAVE_RPM@ +HAVE_RPMBUILD = @HAVE_RPMBUILD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KERNELCPPFLAGS = @KERNELCPPFLAGS@ +KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBBLKID = @LIBBLKID@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSELINUX = @LIBSELINUX@ +LIBTOOL = @LIBTOOL@ +LIBUUID = @LIBUUID@ +LINUX = @LINUX@ +LINUX_OBJ = @LINUX_OBJ@ +LINUX_SYMBOLS = @LINUX_SYMBOLS@ +LINUX_VERSION = @LINUX_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKEPKG = @MAKEPKG@ +MAKEPKG_VERSION = @MAKEPKG_VERSION@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACMAN = @PACMAN@ +PACMAN_VERSION = @PACMAN_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RPM = @RPM@ +RPMBUILD = @RPMBUILD@ +RPMBUILD_VERSION = @RPMBUILD_VERSION@ +RPM_VERSION = @RPM_VERSION@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPL = @SPL@ +SPL_OBJ = @SPL_OBJ@ +SPL_SYMBOLS = @SPL_SYMBOLS@ +SPL_VERSION = @SPL_VERSION@ +STRIP = @STRIP@ +TARGET_ASM_DIR = @TARGET_ASM_DIR@ +VENDOR = @VENDOR@ +VERSION = @VERSION@ +ZFS_CONFIG = @ZFS_CONFIG@ +ZFS_META_ALIAS = @ZFS_META_ALIAS@ +ZFS_META_AUTHOR = @ZFS_META_AUTHOR@ +ZFS_META_DATA = @ZFS_META_DATA@ +ZFS_META_LICENSE = @ZFS_META_LICENSE@ +ZFS_META_LT_AGE = @ZFS_META_LT_AGE@ +ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@ +ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@ +ZFS_META_NAME = @ZFS_META_NAME@ +ZFS_META_RELEASE = @ZFS_META_RELEASE@ +ZFS_META_VERSION = @ZFS_META_VERSION@ +ZLIB = @ZLIB@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +udevdir = @udevdir@ +udevruledir = @udevruledir@ +DEFAULT_INCLUDES = -include ${top_builddir}/zfs_config.h \ + -I$(top_srcdir)/include -I$(top_srcdir)/lib/libspl/include +AM_LIBTOOLFLAGS = --silent +AM_CFLAGS = -Wall -Wstrict-prototypes -fno-strict-aliasing \ + ${NO_UNUSED_BUT_SET_VARIABLE} ${DEBUG_CFLAGS} -D_GNU_SOURCE \ + -D__EXTENSIONS__ -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS \ + -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE \ + -DTEXT_DOMAIN=\"zfs-linux-user\" +noinst_LTLIBRARIES = libshare.la +libshare_la_SOURCES = \ + $(top_srcdir)/lib/libshare/libshare.c \ + $(top_srcdir)/lib/libshare/libshare_impl.h \ + $(top_srcdir)/lib/libshare/nfs.c \ + $(top_srcdir)/lib/libshare/nfs.h \ + $(top_srcdir)/lib/libshare/smb.c \ + $(top_srcdir)/lib/libshare/smb.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/Rules.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/libshare/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/libshare/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libshare.la: $(libshare_la_OBJECTS) $(libshare_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libshare_la_OBJECTS) $(libshare_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libshare.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smb.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libshare.lo: $(top_srcdir)/lib/libshare/libshare.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libshare.lo -MD -MP -MF $(DEPDIR)/libshare.Tpo -c -o libshare.lo `test -f '$(top_srcdir)/lib/libshare/libshare.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/libshare.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libshare.Tpo $(DEPDIR)/libshare.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_srcdir)/lib/libshare/libshare.c' object='libshare.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libshare.lo `test -f '$(top_srcdir)/lib/libshare/libshare.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/libshare.c + +nfs.lo: $(top_srcdir)/lib/libshare/nfs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nfs.lo -MD -MP -MF $(DEPDIR)/nfs.Tpo -c -o nfs.lo `test -f '$(top_srcdir)/lib/libshare/nfs.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/nfs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nfs.Tpo $(DEPDIR)/nfs.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_srcdir)/lib/libshare/nfs.c' object='nfs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nfs.lo `test -f '$(top_srcdir)/lib/libshare/nfs.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/nfs.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +smb.lo: $(top_srcdir)/lib/libshare/smb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT smb.lo -MD -MP -MF $(DEPDIR)/smb.Tpo -c -o smb.lo `test -f '$(top_srcdir)/lib/libshare/smb.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/smb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/smb.Tpo $(DEPDIR)/smb.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_srcdir)/lib/libshare/smb.c' object='smb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o smb.lo `test -f '$(top_srcdir)/lib/libshare/smb.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/smb.c + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/libshare/libshare.c b/lib/libshare/libshare.c index c34e83919402..6b39ba8724e2 100644 --- a/lib/libshare/libshare.c +++ b/lib/libshare/libshare.c @@ -36,6 +36,7 @@ #include #include "libshare_impl.h" #include "nfs.h" +#include "smb.h" static sa_share_impl_t find_share(sa_handle_impl_t handle, const char *sharepath); @@ -103,6 +104,7 @@ __attribute__((constructor)) static void libshare_init(void) { libshare_nfs_init(); + libshare_smb_init(); /* * This bit causes /etc/dfs/sharetab to be updated before libzfs gets a diff --git a/lib/libshare/smb.c b/lib/libshare/smb.c new file mode 100644 index 000000000000..a2814a08a0ec --- /dev/null +++ b/lib/libshare/smb.c @@ -0,0 +1,399 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 Turbo Fredriksson + * + * This is an addition to the zfs device driver to add, modify and remove SMB + * shares using the 'net share' command that comes with Samba. + + * TESTING + * Make sure that samba listens to 'localhost' (127.0.0.1) and that the options + * 'usershare max shares' and 'usershare owner only' have been rewied/set + * accordingly (see zfs(8) for information). + * + * Once configuration in samba have been done, test that this + * works with the following three commands (in this case, my ZFS + * filesystem is called 'share/Test1'): + * + * (root)# net -U root -S 127.0.0.1 usershare add Test1 /share/Test1 \ + * "Comment: /share/Test1" "Everyone:F" + * (root)# net usershare list | grep -i test + * (root)# net -U root -S 127.0.0.1 usershare delete Test1 + * + * The first command will create a user share that gives everyone full access. + * To limit the access below that, use normal UNIX commands (chmod, chown etc). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libshare_impl.h" +#include "smb.h" + +/* + * The maximum SMB share name seems to be 254 characters, though good + * references are hard to find. +*/ +#define SMB_NAME_MAX 255 +#define SMB_COMMENT_MAX 255 +#define SHARE_DIR "/var/lib/samba/usershares" +#define NET_CMD_PATH "/usr/bin/net" +#define NET_CMD_ARG_HOST "127.0.0.1" + +typedef struct smb_share_s { + char name[SMB_NAME_MAX]; /* Share name */ + char path[PATH_MAX]; /* Share path */ + char comment[SMB_COMMENT_MAX]; /* Share's comment */ + boolean_t guest_ok; /* 'y' or 'n' */ + + struct smb_share_s *next; +} smb_share_t; + +static sa_fstype_t *smb_fstype; +boolean_t smb_available; +smb_share_t *smb_shares; + +static int +smb_retrieve_shares(void) +{ + int rc = SA_OK; + char file_path[PATH_MAX], line[512], *token, *key, *value; + char *dup_value, *path = NULL, *comment = NULL, *name = NULL; + char *guest_ok = NULL; + DIR *shares_dir; + FILE *share_file_fp = NULL; + struct dirent *directory; + struct stat eStat; + smb_share_t *shares, *new_shares = NULL; + + /* opendir(), stat() */ + shares_dir = opendir(SHARE_DIR); + if (shares_dir == NULL) + return SA_SYSTEM_ERR; + + /* Go through the directory, looking for shares */ + while ((directory = readdir(shares_dir))) { + if (directory->d_name[0] == '.') + continue; + + snprintf(file_path, sizeof (file_path), + "%s/%s", SHARE_DIR, directory->d_name); + + if (stat(file_path, &eStat) == -1) { + rc = SA_SYSTEM_ERR; + goto out; + } + + if (!S_ISREG(eStat.st_mode)) + continue; + + if ((share_file_fp = fopen(file_path, "r")) == NULL) { + rc = SA_SYSTEM_ERR; + goto out; + } + + name = strdup(directory->d_name); + if (name == NULL) { + rc = SA_NO_MEMORY; + goto out; + } + + while (fgets(line, sizeof(line), share_file_fp)) { + if (line[0] == '#') + continue; + + /* Trim trailing new-line character(s). */ + while (line[strlen(line) - 1] == '\r' || + line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; + + /* Split the line in two, separated by '=' */ + token = strchr(line, '='); + if (token == NULL) + continue; + + key = line; + value = token + 1; + *token = '\0'; + + dup_value = strdup(value); + if (dup_value == NULL) { + rc = SA_NO_MEMORY; + goto out; + } + + if (strcmp(key, "path") == 0) + path = dup_value; + if (strcmp(key, "comment") == 0) + comment = dup_value; + if (strcmp(key, "guest_ok") == 0) + guest_ok = dup_value; + + if (path == NULL || comment == NULL || guest_ok == NULL) + continue; /* Incomplete share definition */ + else { + shares = (smb_share_t *) + malloc(sizeof (smb_share_t)); + if (shares == NULL) { + rc = SA_NO_MEMORY; + goto out; + } + + strncpy(shares->name, name, + sizeof (shares->name)); + shares->name [sizeof(shares->name)-1] = '\0'; + + strncpy(shares->path, path, + sizeof (shares->path)); + shares->path [sizeof(shares->path)-1] = '\0'; + + strncpy(shares->comment, comment, + sizeof (shares->comment)); + shares->comment[sizeof(shares->comment)-1]='\0'; + + shares->guest_ok = atoi(guest_ok); + + shares->next = new_shares; + new_shares = shares; + + name = NULL; + path = NULL; + comment = NULL; + guest_ok = NULL; + } + } + +out: + if (share_file_fp != NULL) + fclose(share_file_fp); + + free(name); + free(path); + free(comment); + free(guest_ok); + } + closedir(shares_dir); + + smb_shares = new_shares; + + return rc; +} + +static int +smb_enable_share_one(const char *sharename, const char *sharepath) +{ + char *argv[10], *pos; + char name[SMB_NAME_MAX], comment[SMB_COMMENT_MAX]; + int rc; + + /* Support ZFS share name regexp '[[:alnum:]_-.: ]' */ + strncpy(name, sharename, sizeof(name)); + name [sizeof(name)-1] = '\0'; + + pos = name; + while (*pos != '\0') { + switch (*pos) { + case '/': + case '-': + case ':': + case ' ': + *pos = '_'; + } + + ++pos; + } + + /* CMD: net -S NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \ + * "Comment" "Everyone:F" */ + snprintf(comment, sizeof(comment), "Comment: %s", sharepath); + + argv[0] = NET_CMD_PATH; + argv[1] = (char*)"-S"; + argv[2] = NET_CMD_ARG_HOST; + argv[3] = (char*)"usershare"; + argv[4] = (char*)"add"; + argv[5] = (char*)name; + argv[6] = (char*)sharepath; + argv[7] = (char*)comment; + argv[8] = "Everyone:F"; + argv[9] = NULL; + + rc = libzfs_run_process(argv[0], argv, 0); + if (rc < 0) + return SA_SYSTEM_ERR; + + /* Reload the share file */ + (void) smb_retrieve_shares(); + + return SA_OK; +} + +static int +smb_enable_share(sa_share_impl_t impl_share) +{ + char *shareopts; + + if (!smb_available) + return SA_SYSTEM_ERR; + + shareopts = FSINFO(impl_share, smb_fstype)->shareopts; + if (shareopts == NULL) /* on/off */ + return SA_SYSTEM_ERR; + + if (strcmp(shareopts, "off") == 0) + return SA_OK; + + /* Magic: Enable (i.e., 'create new') share */ + return smb_enable_share_one(impl_share->dataset, + impl_share->sharepath); +} + +static int +smb_disable_share_one(const char *sharename) +{ + int rc = SA_OK; + char *argv[7]; + + /* CMD: net -S NET_CMD_ARG_HOST usershare delete Test1 */ + argv[0] = NET_CMD_PATH; + argv[1] = (char*)"-S"; + argv[2] = NET_CMD_ARG_HOST; + argv[3] = (char*)"usershare"; + argv[4] = (char*)"delete"; + argv[5] = strdup(sharename); + argv[6] = NULL; + + rc = libzfs_run_process(argv[0], argv, 0); + if (rc < 0) + return SA_SYSTEM_ERR; + + return rc; +} + +static int +smb_disable_share(sa_share_impl_t impl_share) +{ + smb_share_t *shares = smb_shares; + + while (shares != NULL) { + if (strcmp(impl_share->sharepath, shares->path) == 0) + return smb_disable_share_one(shares->name); + + shares = shares->next; + } + + /* Reload the share file */ + (void) smb_retrieve_shares(); + + return SA_OK; +} + +static boolean_t +smb_is_share_active(sa_share_impl_t impl_share) +{ + smb_share_t *shares = smb_shares; + + while (shares != NULL) { + if (strcmp(impl_share->sharepath, shares->path) == 0) + return B_TRUE; + + shares = shares->next; + } + + return B_FALSE; +} + +static int +smb_validate_shareopts(const char *shareopts) +{ + if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0)) + return SA_OK; + return SA_SYNTAX_ERR; +} + +static int +smb_update_shareopts(sa_share_impl_t impl_share, const char *resource, + const char *shareopts) +{ + char *shareopts_dup; + boolean_t needs_reshare = B_FALSE; + char *old_shareopts; + + FSINFO(impl_share,smb_fstype)->active =smb_is_share_active(impl_share); + + old_shareopts = FSINFO(impl_share, smb_fstype)->shareopts; + + if (FSINFO(impl_share, smb_fstype)->active && old_shareopts != NULL && + strcmp(old_shareopts, shareopts) != 0) { + needs_reshare = B_TRUE; + smb_disable_share(impl_share); + } + + shareopts_dup = strdup(shareopts); + + if (shareopts_dup == NULL) + return SA_NO_MEMORY; + + if (old_shareopts != NULL) + free(old_shareopts); + + FSINFO(impl_share, smb_fstype)->shareopts = shareopts_dup; + + if (needs_reshare) + smb_enable_share(impl_share); + + return SA_OK; +} + +static void +smb_clear_shareopts(sa_share_impl_t impl_share) +{ + free(FSINFO(impl_share, smb_fstype)->shareopts); + FSINFO(impl_share, smb_fstype)->shareopts = NULL; +} + +static const sa_share_ops_t smb_shareops = { + .enable_share = smb_enable_share, + .disable_share = smb_disable_share, + + .validate_shareopts = smb_validate_shareopts, + .update_shareopts = smb_update_shareopts, + .clear_shareopts = smb_clear_shareopts, +}; + +void +libshare_smb_init(void) +{ + smb_available = (smb_retrieve_shares() == SA_OK); + + smb_fstype = register_fstype("smb", &smb_shareops); +} diff --git a/lib/libshare/smb.h b/lib/libshare/smb.h new file mode 100644 index 000000000000..cb9018317c6c --- /dev/null +++ b/lib/libshare/smb.h @@ -0,0 +1,26 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2011 Turbo Fredriksson . + */ + +void libshare_smb_init(void); diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index 59ecceb817e1..2e8b728fe4b2 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -1015,6 +1015,19 @@ Because \fBSMB\fR shares requires a resource name, a unique resource name is con When SMB shares are created, the SMB share name appears as an entry in the \fB\&.zfs/shares\fR directory. You can use the \fBls\fR or \fBchmod\fR command to display the share-level ACLs on the entries in this directory. .sp When the \fBsharesmb\fR property is changed for a dataset, the dataset and any children inheriting the property are re-shared with the new options, only if the property was previously set to \fBoff\fR, or if they were shared before the property was changed. If the new property is set to \fBoff\fR, the file systems are unshared. +.sp +.LP +\fBSetting up Samba\fR +.sp +.in +2 +To setup samba to be able to use the \fBsharesmb\fR property, Samba (tested on version 3.3.3) will need to be listening on 'localhost' (127.0.0.1) by setting the \fBinterfaces\fR configuration option. +.sp +In addition to this, the Samba configuration options \fBusershare path\fR, \fBusershare max shares\fR and \fBusershare owner only\fR needs to be setup properly. The first one, \fBusershare path\fR, is by default set to \fB/var/lib/samba/usershares\fR in the code so if this is not wanted, then \fBsmb.conf\fR and \fBlib/libshare/smb.c\fR in the code needs to be changed and recompiled. +.sp +The second one is only necessary if there is more than 100 volumes that will be shared (default value is 100). +.sp +The third option is if there is a need to allow non-root users to share volumes they do NOT own. That is, to allow non-root users to be able to set the \fBsharesmb\fR property. For a non-user to be able to share a volume, he/she will also have to have write access to the \fB/dev/zfs\fR device node. +.in -2 .RE .sp From f96b1fad14c3b1824683535a0995e6b2b3a9bd87 Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Sat, 4 Feb 2012 21:01:25 +0100 Subject: [PATCH 5/5] Add iSCSI sharing to ZoL. Sixth official patch attempt. Previous ones was/is lost in my inability with GIT. * Script to run through some tests to test share/unsharing... * Debugging output added. * Retabbing * Fix faulty nfs|smb check (setting ZFS_TYPE_FILESYSTEM). Now possible to use 'share -a [nfs|smb|iscsi] as command line suggests. Not documented in man page though... + In unshare_unmount(), 'if(do_all)', 'continue' instead of 'break' after checking 'sharenfs=off' (so that we can continue checking for shareiscsi and sharesmb). * Process iscsi shares early in update_zfs_shares_cb(). * Fix problem with assertion fail when running 'zfs unshare -a'. * Call process_share() early of update_zfs_shares_cb() if iSCSI. * Add shell script (test_zfs.sh) to test some functionality of SMB/iSCSI patch(es). + Remove file_is_executable() from iSCSI per request from Brian. Fix some stuff that I know Brian will nag about :) * 80 char line * Move content of README to code + man page. * Remove all debugging. * Return SA_OK instead of 0 where needed. * Cast to char* when setting argv with constant string(s). * C9x compliance * Make private functions static. Some minor iSCSI fixes, comments from Richard Laager: * Remove redundant variable = NULL check. * Rename the custom iSCSI share script (remove .sh suffix). + Reword manual Some more iSCSI fixes. * Since iscsi_retrieve_targets() is now static, move it up to the top of iscsi.c and remove from iscsi.h. * In update_zfs_shares_cb(), do the iSCSI parts later and skip the if type != FS check etc. * Implement iscsi_validate_shareopts(). * Distinguish between FS and VOL when updating share information. + Support adding a VOL to list. * Uncomment some stuff in process_share() that is/was supposed to possibly fix the 'shareicsi=on' auto sharing but didn't. Only made it to not compile... * Update copyright note and year(s). Fixes after second review by behlendorf and comments by Richard Yao. * Check for getdomainname() - set HAVE_GETDOMAINNAME=1 if so - in ./configure. + Only try to get domain name with getdomainname() if we have it (HAVE_GETDOMAINNAME). If we don't, use the file /etc/domainname (configurable with DOMAINNAME_FILE). * s/if\(/if \(/. * Init iscsi_volumes_fp in iscsi_retrieve_targets() to NULL. * Make sure tid_s is only 11 chars long. * Remove one level of indentation from test binary. * Don't malloc temp - memleak in test binary. * Retabbing. * s/share/tank/g in comments etc. More fixes after review by Richard Yao, Richard Laager and Prakash Surya: * Spelling errors fixed. * ietadm is in man section '8', not '8M' (to much cut-and-past :). * Remove (rewrite) some redundant strlen() usage. * Replace a non-working sizeof with strlen. Other changes and fixes: * Update Release to indicate date and branch. * Remove trailing newline/null in domainname (was cutting a char to much). * Put the extra share script (/sbin/zfs_share_iscsi) as a define. * Optional /etc/iscsi_target_id which contain the TID - this instead of autogenerating one (which changes every month!). * Rewrite domain name information for iSCSI. * Document new optional /etc/iscsi_target_id and it's use. * Update list [iscsi] targets using iscsitadm with something that works in Linux. --- META | 2 +- cmd/zfs/zfs_main.c | 537 +++++++++++++++++------------ configure.ac | 2 + include/libzfs.h | 7 + include/libzfs_impl.h | 6 +- include/sys/fs/zfs.h | 5 +- lib/libshare/Makefile.am | 11 +- lib/libshare/Makefile.in | 44 ++- lib/libshare/iscsi.c | 609 +++++++++++++++++++++++++++++++++ lib/libshare/iscsi.h | 47 +++ lib/libshare/iscsi_test.c | 108 ++++++ lib/libshare/libshare.c | 106 ++++-- lib/libshare/nfs.c | 4 +- lib/libshare/smb.c | 3 +- lib/libshare/test_zfs.sh | 190 ++++++++++ lib/libzfs/libzfs_changelist.c | 28 +- lib/libzfs/libzfs_dataset.c | 11 +- lib/libzfs/libzfs_mount.c | 240 ++++++++----- lib/libzfs/libzfs_util.c | 4 + man/man8/zfs.8 | 23 +- module/zcommon/zfs_prop.c | 3 + 21 files changed, 1626 insertions(+), 364 deletions(-) create mode 100644 lib/libshare/iscsi.c create mode 100644 lib/libshare/iscsi.h create mode 100644 lib/libshare/iscsi_test.c create mode 100755 lib/libshare/test_zfs.sh diff --git a/META b/META index fa2c62320233..4dd782c4b362 100644 --- a/META +++ b/META @@ -2,7 +2,7 @@ Meta: 1 Name: zfs Branch: 1.0 Version: 0.6.0 -Release: rc12 +Release: rc12_20121114+iscsi+smbfs Release-Tags: relext License: CDDL Author: Sun Microsystems/Oracle, Lawrence Livermore National Laboratory diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 797c7a591a7b..6a27b71040d0 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -66,6 +66,7 @@ #include "zfs_iter.h" #include "zfs_util.h" #include "zfs_comutil.h" +#include "../../libshare/iscsi.h" libzfs_handle_t *g_zfs; @@ -3393,6 +3394,7 @@ set_callback(zfs_handle_t *zhp, void *data) "but unable to remount filesystem\n")); break; case EZFS_SHARENFSFAILED: + case EZFS_SHAREISCSIFAILED: (void) fprintf(stderr, gettext("property may be set " "but unable to reshare filesystem\n")); break; @@ -5413,7 +5415,8 @@ get_one_dataset(zfs_handle_t *zhp, void *data) /* * Interate over any nested datasets. */ - if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) { + if (type == ZFS_TYPE_FILESYSTEM && + zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) { zfs_close(zhp); return (1); } @@ -5421,7 +5424,7 @@ get_one_dataset(zfs_handle_t *zhp, void *data) /* * Skip any datasets whose type does not match. */ - if ((type & ZFS_TYPE_FILESYSTEM) == 0) { + if ((type & cbp->cb_types) == 0) { zfs_close(zhp); return (0); } @@ -5432,9 +5435,11 @@ get_one_dataset(zfs_handle_t *zhp, void *data) } static void -get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose) +get_all_datasets(uint_t types, zfs_handle_t ***dslist, size_t *count, + boolean_t verbose) { get_all_cb_t cb = { 0 }; + cb.cb_types = types; cb.cb_verbose = verbose; cb.cb_getone = get_one_dataset; @@ -5470,179 +5475,216 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol, const char *cmdname = op == OP_SHARE ? "share" : "mount"; struct mnttab mnt; uint64_t zoned, canmount; + zfs_type_t type = zfs_get_type(zhp); boolean_t shared_nfs, shared_smb; - assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM); - - /* - * Check to make sure we can mount/share this dataset. If we - * are in the global zone and the filesystem is exported to a - * local zone, or if we are in a local zone and the - * filesystem is not exported, then it is an error. - */ - zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); - - if (zoned && getzoneid() == GLOBAL_ZONEID) { - if (!explicit) - return (0); - - (void) fprintf(stderr, gettext("cannot %s '%s': " - "dataset is exported to a local zone\n"), cmdname, - zfs_get_name(zhp)); - return (1); - - } else if (!zoned && getzoneid() != GLOBAL_ZONEID) { - if (!explicit) - return (0); + assert(type & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)); - (void) fprintf(stderr, gettext("cannot %s '%s': " - "permission denied\n"), cmdname, - zfs_get_name(zhp)); - return (1); - } + if (type == ZFS_TYPE_FILESYSTEM) { + /* + * Check to make sure we can mount/share this dataset. If we + * are in the global zone and the filesystem is exported to a + * local zone, or if we are in a local zone and the + * filesystem is not exported, then it is an error. + */ + zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); - /* - * Ignore any filesystems which don't apply to us. This - * includes those with a legacy mountpoint, or those with - * legacy share options. - */ - verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, - sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0); - verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, - sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); - verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts, - sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0); - - if (op == OP_SHARE && strcmp(shareopts, "off") == 0 && - strcmp(smbshareopts, "off") == 0) { - if (!explicit) - return (0); + if (zoned && getzoneid() == GLOBAL_ZONEID) { + if (!explicit) + return (0); - (void) fprintf(stderr, gettext("cannot share '%s': " - "legacy share\n"), zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("use share(1M) to " - "share this filesystem, or set " - "sharenfs property on\n")); - return (1); - } + (void) fprintf(stderr, gettext("cannot %s '%s': " + "dataset is exported to a local zone\n"), cmdname, + zfs_get_name(zhp)); + return (1); - /* - * We cannot share or mount legacy filesystems. If the - * shareopts is non-legacy but the mountpoint is legacy, we - * treat it as a legacy share. - */ - if (strcmp(mountpoint, "legacy") == 0) { - if (!explicit) - return (0); + } else if (!zoned && getzoneid() != GLOBAL_ZONEID) { + if (!explicit) + return (0); - (void) fprintf(stderr, gettext("cannot %s '%s': " - "legacy mountpoint\n"), cmdname, zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("use %s(1M) to " - "%s this filesystem\n"), cmdname, cmdname); - return (1); - } + (void) fprintf(stderr, gettext("cannot %s '%s': " + "permission denied\n"), cmdname, + zfs_get_name(zhp)); + return (1); + } - if (strcmp(mountpoint, "none") == 0) { - if (!explicit) - return (0); + /* + * Ignore any filesystems which don't apply to us. This + * includes those with a legacy mountpoint, or those with + * legacy share options. + */ + verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, + sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0); + verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, + sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); + verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts, + sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0); + + if (op == OP_SHARE && + strcmp(shareopts, "off") == 0 && + strcmp(smbshareopts, "off") == 0) { + if (!explicit) + return (0); - (void) fprintf(stderr, gettext("cannot %s '%s': no " - "mountpoint set\n"), cmdname, zfs_get_name(zhp)); - return (1); - } + (void) fprintf(stderr, gettext("cannot share '%s': " + "legacy share\n"), zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("use share(1M) to " + "share this filesystem, or set " + "sharenfs property on\n")); + return (1); + } - /* - * canmount explicit outcome - * on no pass through - * on yes pass through - * off no return 0 - * off yes display error, return 1 - * noauto no return 0 - * noauto yes pass through - */ - canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); - if (canmount == ZFS_CANMOUNT_OFF) { - if (!explicit) - return (0); + /* + * We cannot share or mount legacy filesystems. If the + * shareopts is non-legacy but the mountpoint is legacy, we + * treat it as a legacy share. + */ + if (strcmp(mountpoint, "legacy") == 0) { + if (!explicit) + return (0); - (void) fprintf(stderr, gettext("cannot %s '%s': " - "'canmount' property is set to 'off'\n"), cmdname, - zfs_get_name(zhp)); - return (1); - } else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) { - return (0); - } + (void) fprintf(stderr, gettext("cannot %s '%s': " + "legacy mountpoint\n"), cmdname, zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("use %s(1M) to " + "%s this filesystem\n"), cmdname, cmdname); + return (1); + } - /* - * At this point, we have verified that the mountpoint and/or - * shareopts are appropriate for auto management. If the - * filesystem is already mounted or shared, return (failing - * for explicit requests); otherwise mount or share the - * filesystem. - */ - switch (op) { - case OP_SHARE: + if (strcmp(mountpoint, "none") == 0) { + if (!explicit) + return (0); - shared_nfs = zfs_is_shared_nfs(zhp, NULL); - shared_smb = zfs_is_shared_smb(zhp, NULL); + (void) fprintf(stderr, gettext("cannot %s '%s': no " + "mountpoint set\n"), cmdname, zfs_get_name(zhp)); + return (1); + } - if ((shared_nfs && shared_smb) || - ((shared_nfs && strcmp(shareopts, "on") == 0) && - (strcmp(smbshareopts, "off") == 0)) || - ((shared_smb && strcmp(smbshareopts, "on") == 0) && - (strcmp(shareopts, "off") == 0))) { + /* + * canmount explicit outcome + * on no pass through + * on yes pass through + * off no return 0 + * off yes display error, return 1 + * noauto no return 0 + * noauto yes pass through + */ + canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); + if (canmount == ZFS_CANMOUNT_OFF) { if (!explicit) return (0); - (void) fprintf(stderr, gettext("cannot share " - "'%s': filesystem already shared\n"), + (void) fprintf(stderr, gettext("cannot %s '%s': " + "'canmount' property is set to 'off'\n"), cmdname, zfs_get_name(zhp)); return (1); + } else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) { + return (0); } - if (!zfs_is_mounted(zhp, NULL) && - zfs_mount(zhp, NULL, 0) != 0) - return (1); + /* + * At this point, we have verified that the mountpoint and/or + * shareopts are appropriate for auto management. If the + * filesystem is already mounted or shared, return (failing + * for explicit requests); otherwise mount or share the + * filesystem. + */ + switch (op) { + case OP_SHARE: + shared_nfs = zfs_is_shared_nfs(zhp, NULL); + shared_smb = zfs_is_shared_smb(zhp, NULL); + + if ((shared_nfs && shared_smb) || + ((shared_nfs && strcmp(shareopts, "on") == 0) && + (strcmp(smbshareopts, "off") == 0)) || + ((shared_smb && strcmp(smbshareopts, "on") == 0) && + (strcmp(shareopts, "off") == 0))) { + if (!explicit) + return (0); + + (void) fprintf(stderr, gettext("cannot share " + "'%s': filesystem already shared\n"), + zfs_get_name(zhp)); + return (1); + } - if (protocol == NULL) { - if (zfs_shareall(zhp) != 0) + if (!zfs_is_mounted(zhp, NULL) && + zfs_mount(zhp, NULL, 0) != 0) return (1); - } else if (strcmp(protocol, "nfs") == 0) { - if (zfs_share_nfs(zhp)) + + if (protocol == NULL) { + if (zfs_shareall(zhp) != 0) + return (1); + } else if (strcmp(protocol, "nfs") == 0) { + if (zfs_share_nfs(zhp)) + return (1); + } else if (strcmp(protocol, "smb") == 0) { + if (zfs_share_smb(zhp)) + return (1); + } else { + (void) fprintf(stderr, gettext("cannot share " + "'%s': invalid share type '%s' " + "specified\n"), + zfs_get_name(zhp), protocol); return (1); - } else if (strcmp(protocol, "smb") == 0) { - if (zfs_share_smb(zhp)) + } + + break; + + case OP_MOUNT: + if (options == NULL) + mnt.mnt_mntopts = ""; + else + mnt.mnt_mntopts = (char *)options; + + if (!hasmntopt(&mnt, MNTOPT_REMOUNT) && + zfs_is_mounted(zhp, NULL)) { + if (!explicit) + return (0); + + (void) fprintf(stderr, gettext("cannot mount " + "'%s': filesystem already mounted\n"), + zfs_get_name(zhp)); return (1); - } else { - (void) fprintf(stderr, gettext("cannot share " - "'%s': invalid share type '%s' " - "specified\n"), - zfs_get_name(zhp), protocol); - return (1); + } + + if (zfs_mount(zhp, options, flags) != 0) + return (1); + break; } + } else { + assert(op == OP_SHARE); - break; + /* + * Ignore any volumes that aren't shared. + */ + verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, + sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); - case OP_MOUNT: - if (options == NULL) - mnt.mnt_mntopts = ""; - else - mnt.mnt_mntopts = (char *)options; + if (strcmp(shareopts, "off") == 0) { + if (!explicit) + return (0); + + (void) fprintf(stderr, gettext("cannot share '%s': " + "'shareiscsi' property not set\n"), + zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("set 'shareiscsi' " + "property or use iscsitadm(1M) to share this " + "volume\n")); + return (1); + } - if (!hasmntopt(&mnt, MNTOPT_REMOUNT) && - zfs_is_mounted(zhp, NULL)) { + if (zfs_is_shared_iscsi(zhp, NULL)) { if (!explicit) return (0); - (void) fprintf(stderr, gettext("cannot mount " - "'%s': filesystem already mounted\n"), - zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("cannot share " + "'%s': volume already shared\n"), + zfs_get_name(zhp)); return (1); } - if (zfs_mount(zhp, options, flags) != 0) + if (zfs_share_iscsi(zhp) != 0) return (1); - break; } return (0); @@ -5705,7 +5747,7 @@ share_mount(int op, int argc, char **argv) boolean_t verbose = B_FALSE; int c, ret = 0; char *options = NULL; - int flags = 0; + int types = -1, flags = 0; /* check options */ while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a")) @@ -5754,16 +5796,24 @@ share_mount(int op, int argc, char **argv) size_t i, count = 0; char *protocol = NULL; - if (op == OP_SHARE && argc > 0) { - if (strcmp(argv[0], "nfs") != 0 && - strcmp(argv[0], "smb") != 0) { + if (op == OP_MOUNT) { + types = ZFS_TYPE_FILESYSTEM; + } else if (argc > 0) { + if (strcmp(argv[0], "nfs") == 0 || + strcmp(argv[0], "smb") == 0) { + types = ZFS_TYPE_FILESYSTEM; + } else if (strcmp(argv[0], "iscsi") == 0) { + types = ZFS_TYPE_VOLUME; + } else { (void) fprintf(stderr, gettext("share type " - "must be 'nfs' or 'smb'\n")); + "must be 'nfs', 'smb' or 'iscsi'\n")); usage(B_FALSE); } protocol = argv[0]; argc--; argv++; + } else { + types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME; } if (argc != 0) { @@ -5772,7 +5822,7 @@ share_mount(int op, int argc, char **argv) } start_progress_timer(); - get_all_datasets(&dslist, &count, verbose); + get_all_datasets(types, &dslist, &count, verbose); if (count == 0) return (0); @@ -5817,14 +5867,17 @@ share_mount(int op, int argc, char **argv) } else { zfs_handle_t *zhp; + types = ZFS_TYPE_FILESYSTEM; + if (op == OP_SHARE) + types |= ZFS_TYPE_VOLUME; + if (argc > 1) { (void) fprintf(stderr, gettext("too many arguments\n")); usage(B_FALSE); } - if ((zhp = zfs_open(g_zfs, argv[0], - ZFS_TYPE_FILESYSTEM)) == NULL) { + if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) { ret = 1; } else { ret = share_mount_one(zhp, op, flags, NULL, B_TRUE, @@ -5849,7 +5902,7 @@ zfs_do_mount(int argc, char **argv) } /* - * zfs share -a [nfs | smb] + * zfs share -a [nfs | smb | iscsi] * zfs share filesystem * * Share all filesystems, or share the given filesystem. @@ -5951,18 +6004,22 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) if (op == OP_SHARE) { char nfs_mnt_prop[ZFS_MAXPROPLEN]; char smbshare_prop[ZFS_MAXPROPLEN]; + char iscsishare_prop[ZFS_MAXPROPLEN]; verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshare_prop, sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0); + verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, iscsishare_prop, + sizeof (iscsishare_prop), NULL, NULL, 0, B_FALSE) == 0); if (strcmp(nfs_mnt_prop, "off") == 0 && - strcmp(smbshare_prop, "off") == 0) { + strcmp(smbshare_prop, "off") == 0 && + strcmp(iscsishare_prop, "off") == 0) { (void) fprintf(stderr, gettext("cannot unshare " "'%s': legacy share\n"), path); - (void) fprintf(stderr, gettext("use exportfs(8) " - "or smbcontrol(1) to unshare this filesystem\n")); + (void) fprintf(stderr, gettext("use exportfs(8), " + "smbcontrol(1) or ietadm(8) to unshare this filesystem\n")); } else if (!zfs_is_shared(zhp)) { (void) fprintf(stderr, gettext("cannot unshare '%s': " "not currently shared\n"), path); @@ -6003,9 +6060,9 @@ unshare_unmount(int op, int argc, char **argv) int do_all = 0; int flags = 0; int ret = 0; - int c; + int types, c; zfs_handle_t *zhp; - char nfs_mnt_prop[ZFS_MAXPROPLEN]; + char nfsiscsi_mnt_prop[ZFS_MAXPROPLEN]; char sharesmb[ZFS_MAXPROPLEN]; /* check options */ @@ -6063,9 +6120,8 @@ unshare_unmount(int op, int argc, char **argv) rewind(mnttab_file); while (getmntent(mnttab_file, &entry) == 0) { - /* ignore non-ZFS entries */ - if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) + if ((strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)) continue; /* ignore snapshots */ @@ -6080,31 +6136,42 @@ unshare_unmount(int op, int argc, char **argv) switch (op) { case OP_SHARE: - verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, - nfs_mnt_prop, - sizeof (nfs_mnt_prop), - NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfs_mnt_prop, "off") != 0) - break; - verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, - nfs_mnt_prop, - sizeof (nfs_mnt_prop), - NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfs_mnt_prop, "off") == 0) - continue; + if(zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { + verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, + nfsiscsi_mnt_prop, + sizeof (nfsiscsi_mnt_prop), + NULL, NULL, 0, B_FALSE) == 0); + if (strcmp(nfsiscsi_mnt_prop, "off") != 0) + continue; + verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, + nfsiscsi_mnt_prop, + sizeof (nfsiscsi_mnt_prop), + NULL, NULL, 0, B_FALSE) == 0); + if (strcmp(nfsiscsi_mnt_prop, "off") == 0) + continue; + } else { + verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, + nfsiscsi_mnt_prop, + sizeof (nfsiscsi_mnt_prop), + NULL, NULL, 0, B_FALSE) == 0); + if (strcmp(nfsiscsi_mnt_prop, "off") == 0) + continue; + } break; + case OP_MOUNT: /* Ignore legacy mounts */ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, - nfs_mnt_prop, - sizeof (nfs_mnt_prop), + nfsiscsi_mnt_prop, + sizeof (nfsiscsi_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfs_mnt_prop, "legacy") == 0) + if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) continue; /* Ignore canmount=noauto mounts */ if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) continue; + default: break; } @@ -6158,6 +6225,8 @@ unshare_unmount(int op, int argc, char **argv) uu_avl_destroy(tree); uu_avl_pool_destroy(pool); + if (op == OP_SHARE) + iscsi_disable_share_all(); } else { if (argc != 1) { if (argc == 0) @@ -6179,63 +6248,93 @@ unshare_unmount(int op, int argc, char **argv) return (unshare_unmount_path(op, argv[0], flags, B_FALSE)); - if ((zhp = zfs_open(g_zfs, argv[0], - ZFS_TYPE_FILESYSTEM)) == NULL) + types = ZFS_TYPE_FILESYSTEM; + if (op == OP_SHARE) + types |= ZFS_TYPE_VOLUME; + + if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) return (1); - verify(zfs_prop_get(zhp, op == OP_SHARE ? - ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, - nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL, - NULL, 0, B_FALSE) == 0); + if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { + verify(zfs_prop_get(zhp, op == OP_SHARE ? + ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, + nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop), NULL, + NULL, 0, B_FALSE) == 0); - switch (op) { - case OP_SHARE: - verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, - nfs_mnt_prop, - sizeof (nfs_mnt_prop), - NULL, NULL, 0, B_FALSE) == 0); - verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, - sharesmb, sizeof (sharesmb), NULL, NULL, - 0, B_FALSE) == 0); - - if (strcmp(nfs_mnt_prop, "off") == 0 && - strcmp(sharesmb, "off") == 0) { - (void) fprintf(stderr, gettext("cannot " - "unshare '%s': legacy share\n"), - zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("use " - "unshare(1M) to unshare this " - "filesystem\n")); - ret = 1; - } else if (!zfs_is_shared(zhp)) { - (void) fprintf(stderr, gettext("cannot " - "unshare '%s': not currently " - "shared\n"), zfs_get_name(zhp)); - ret = 1; - } else if (zfs_unshareall(zhp) != 0) { - ret = 1; - } - break; + switch (op) { + case OP_SHARE: + verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, + nfsiscsi_mnt_prop, + sizeof (nfsiscsi_mnt_prop), + NULL, NULL, 0, B_FALSE) == 0); + verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, + sharesmb, + sizeof (sharesmb), + NULL, NULL, 0, B_FALSE) == 0); + + if (strcmp(nfsiscsi_mnt_prop, "off") == 0 && + strcmp(sharesmb, "off") == 0) { + (void) fprintf(stderr, gettext("cannot " + "unshare '%s': legacy share\n"), + zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("use " + "unshare(1M) to unshare this " + "filesystem\n")); + ret = 1; + } else if (!zfs_is_shared(zhp)) { + (void) fprintf(stderr, gettext("cannot " + "unshare '%s': not currently " + "shared\n"), zfs_get_name(zhp)); + ret = 1; + } else if (zfs_unshareall(zhp) != 0) { + ret = 1; + } + break; - case OP_MOUNT: - if (strcmp(nfs_mnt_prop, "legacy") == 0) { - (void) fprintf(stderr, gettext("cannot " - "unmount '%s': legacy " - "mountpoint\n"), zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("use " - "umount(1M) to unmount this " - "filesystem\n")); + case OP_MOUNT: + if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) { + (void) fprintf(stderr, gettext("cannot " + "unmount '%s': legacy " + "mountpoint\n"), zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("use " + "umount(1M) to unmount this " + "filesystem\n")); + ret = 1; + } else if (!zfs_is_mounted(zhp, NULL)) { + (void) fprintf(stderr, gettext("cannot " + "unmount '%s': not currently " + "mounted\n"), + zfs_get_name(zhp)); + ret = 1; + } else if (zfs_unmountall(zhp, flags) != 0) { + ret = 1; + } + break; + } + } else { + assert(op == OP_SHARE); + + verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, + nfsiscsi_mnt_prop, + sizeof (nfsiscsi_mnt_prop), + NULL, NULL, 0, B_FALSE) == 0); + + if (strcmp(nfsiscsi_mnt_prop, "off") == 0) { + (void) fprintf(stderr, gettext("cannot unshare " + "'%s': 'shareiscsi' property not set\n"), + zfs_get_name(zhp)); + (void) fprintf(stderr, gettext("set " + "'shareiscsi' property or use " + "iscsitadm(1M) to share this volume\n")); ret = 1; - } else if (!zfs_is_mounted(zhp, NULL)) { + } else if (!zfs_is_shared_iscsi(zhp, NULL)) { (void) fprintf(stderr, gettext("cannot " - "unmount '%s': not currently " - "mounted\n"), - zfs_get_name(zhp)); + "unshare '%s': not currently shared\n"), + zfs_get_name(zhp)); ret = 1; - } else if (zfs_unmountall(zhp, flags) != 0) { + } else if (zfs_unshare_iscsi(zhp, NULL) != 0) { ret = 1; } - break; } zfs_close(zhp); diff --git a/configure.ac b/configure.ac index 2b79f5ff2add..2fa6352eeab4 100644 --- a/configure.ac +++ b/configure.ac @@ -128,4 +128,6 @@ AC_CONFIG_FILES([ dkms.conf ]) +AC_CHECK_FUNC(getdomainname, AC_DEFINE(HAVE_GETDOMAINNAME, 1, [Define if you have the `getdomainname' function.])) + AC_OUTPUT diff --git a/include/libzfs.h b/include/libzfs.h index e59350c9dbdd..0944b81cfc9b 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -134,6 +134,8 @@ enum { 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 }; @@ -525,6 +527,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; @@ -672,13 +675,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 *, diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h index fabcb1183144..0ea53da70bb1 100644 --- a/include/libzfs_impl.h +++ b/include/libzfs_impl.h @@ -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; /* @@ -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 *); diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index f72c74fc93e1..af6b5460726c 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -128,6 +128,7 @@ typedef enum { ZFS_PROP_REFRATIO, ZFS_PROP_WRITTEN, ZFS_PROP_CLONES, + ZFS_PROP_SHAREISCSI, ZFS_NUM_PROPS } zfs_prop_t; @@ -297,7 +298,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 { diff --git a/lib/libshare/Makefile.am b/lib/libshare/Makefile.am index 53c1223ef26a..a838b6d2c6f0 100644 --- a/lib/libshare/Makefile.am +++ b/lib/libshare/Makefile.am @@ -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.h + +libshare_la_LDFLAGS = -version-info 1:0:0 + +iscsi_test_SOURCES = \ + $(top_srcdir)/lib/libshare/iscsi_test.c \ + $(top_srcdir)/lib/libshare/iscsi.c \ + $(top_srcdir)/lib/libshare/iscsi.h diff --git a/lib/libshare/Makefile.in b/lib/libshare/Makefile.in index 1a3096ccd4a9..1f377272f2c3 100644 --- a/lib/libshare/Makefile.in +++ b/lib/libshare/Makefile.in @@ -104,7 +104,7 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libshare_la_LIBADD = -am_libshare_la_OBJECTS = libshare.lo nfs.lo smb.lo +am_libshare_la_OBJECTS = libshare.lo nfs.lo smb.lo iscsi.lo libshare_la_OBJECTS = $(am_libshare_la_OBJECTS) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) @@ -134,8 +134,8 @@ am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; -SOURCES = $(libshare_la_SOURCES) -DIST_SOURCES = $(libshare_la_SOURCES) +SOURCES = $(libshare_la_SOURCES) $(iscsi_test_SOURCES) +DIST_SOURCES = $(libshare_la_SOURCES) $(iscsi_test_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -332,7 +332,27 @@ 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.h + +libshare_la_LDFLAGS = -version-info 1:0:0 + +iscsi_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(LDFLAGS) -o $@ +am_iscsi_test_OBJECTS = $(libshare_la_OBJECTS) iscsi_test.o +iscsi_test_OBJECTS = $(am_iscsi_test_OBJECTS) +iscsi_test_SOURCES = \ + $(top_srcdir)/lib/libshare/iscsi_test.c \ + $(top_srcdir)/lib/libshare/iscsi.c \ + $(top_srcdir)/lib/libshare/iscsi.h +iscsi_test_DEPENDENCIES = \ + $(lib_LTLIBRARIES) \ + $(top_builddir)/lib/libzfs/libzfs.la +iscsi_test_LDADD = \ + $(lib_LTLIBRARIES) \ + $(top_builddir)/lib/libzfs/libzfs.la all: all-am @@ -380,8 +400,12 @@ clean-noinstLTLIBRARIES: libshare.la: $(libshare_la_OBJECTS) $(libshare_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libshare_la_OBJECTS) $(libshare_la_LIBADD) $(LIBS) +iscsi_test$(EXEEXT): $(iscsi_test_OBJECTS) $(iscsi_test_DEPENDENCIES) + @rm -f iscsi_test$(EXEEXT) + $(AM_V_CCLD)$(iscsi_test_LINK) $(iscsi_test_LDADD) iscsi_test.$(OBJEXT) + mostlyclean-compile: - -rm -f *.$(OBJEXT) + -rm -f *.$(OBJEXT) iscsi_test$(EXEEXT) distclean-compile: -rm -f *.tab.c @@ -389,6 +413,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libshare.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iscsi.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -430,6 +455,15 @@ nfs.lo: $(top_srcdir)/lib/libshare/nfs.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nfs.lo `test -f '$(top_srcdir)/lib/libshare/nfs.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/nfs.c +iscsi.lo: $(top_srcdir)/lib/libshare/iscsi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT iscsi.lo -MD -MP -MF $(DEPDIR)/iscsi.Tpo -c -o iscsi.lo `test -f '$(top_srcdir)/lib/libshare/iscsi.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/iscsi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/iscsi.Tpo $(DEPDIR)/iscsi.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_srcdir)/lib/libshare/iscsi.c' object='iscsi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o iscsi.lo `test -f '$(top_srcdir)/lib/libshare/iscsi.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/libshare/iscsi.c + + mostlyclean-libtool: -rm -f *.lo diff --git a/lib/libshare/iscsi.c b/lib/libshare/iscsi.c new file mode 100644 index 000000000000..291895ed69c4 --- /dev/null +++ b/lib/libshare/iscsi.c @@ -0,0 +1,609 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011,2012 Turbo Fredriksson , based on nfs.c + * by Gunnar Beutner + * + * This is an addition to the zfs device driver to retrieve, add and remove + * iSCSI targets using the 'ietadm' command. As of this, it only currently + * supports the IET iSCSI target implementation. + * + * It uses a linked list named 'iscsi_target_t' to keep track of all targets. + * + * It will call ietadm to both add or remove a iSCSI + * target from the call to 'zfs share': + * + * zfs create -V tank/test + * zfs set shareiscsi=on tank/test + * zfs share tank/test + * + * The driver will execute the following commands (example!): + * + * /usr/sbin/ietadm --op new --tid 1 --params + * Name=iqn.2012-01.com.bayour:tank.test1 + * /usr/sbin/ietadm --op new --tid 1 --lun 0 --params + * Path=/dev/zvol/tank/test,Type=fileio + * + * It (the driver) will automatically calculate the TID and IQN and use only + * the ZVOL (in this case 'tank/test') in the command lines. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libshare_impl.h" +#include "iscsi.h" + +static sa_fstype_t *iscsi_fstype; +boolean_t iscsi_available; + +#define PROC_IET_VOLUME "/proc/net/iet/volume" +#define IETM_CMD_PATH "/usr/sbin/ietadm" +#define DOMAINNAME_FILE "/etc/domainname" +#define TARGET_NAME_FILE "/etc/iscsi_target_id" +#define EXTRA_SHARE_SCRIPT "/sbin/zfs_share_iscsi" + +/* + * Generate a target name using the current year and month, + * the domain name and the path: + * + * => iqn.yyyy-mm.tld.domain:path + */ +int +iscsi_generate_target(const char *path, char *iqn, size_t iqn_len) +{ + char tsbuf[8]; /* YYYY-MM */ + char domain[256], revname[255], name[255], + tmpdom[255], *p, tmp[20][255], *pos, + buffer[512], file_iqn[255]; + time_t now; + struct tm *now_local; + int i; + FILE *domainname_fp = NULL, *iscsi_target_name_fp = NULL; + + iscsi_target_name_fp = fopen(TARGET_NAME_FILE, "r"); + if (iscsi_target_name_fp == NULL) { + /* Generate a name using domain name and date etc */ + + /* Get current time in EPOCH */ + now = time(NULL); + now_local = localtime(&now); + if (now_local == NULL) + return -1; + + /* Parse EPOCH and get YYY-MM */ + if (strftime(tsbuf, sizeof (tsbuf), "%Y-%m", now_local) == 0) + return -1; + +#ifdef HAVE_GETDOMAINNAME + /* Retrieve the domain */ + if (getdomainname(domain, sizeof (domain)) < 0) { + fprintf(stderr, "ERROR: Can't get domainname using getdomainname(): %s\n", + strerror(errno)); + return -1; + } + + if ((strlen(domain) == 0) || (strcmp(domain, "(none)") == 0)) { +#endif + domainname_fp = fopen(DOMAINNAME_FILE, "r"); + if (domainname_fp == NULL) { + fprintf(stderr, "ERROR: Can't open %s: %s\n", DOMAINNAME_FILE, + strerror(errno)); + return -1; + } + + if (fgets(buffer, sizeof (buffer), domainname_fp) != NULL) { + strncpy(domain, buffer, sizeof (domain)-1); + domain[strlen(domain)-1] = '\0'; + } else { + fprintf(stderr, "ERROR: Can't read from %s: %s\n", DOMAINNAME_FILE, + strerror(errno)); + return -1; + } + + fclose(domainname_fp); +#ifdef HAVE_GETDOMAINNAME + } +#endif + + /* Reverse the domainname ('bayour.com' => 'com.bayour') */ + strncpy(tmpdom, domain, sizeof (domain)); + + i = 0; + p = strtok(tmpdom, "."); + while (p != NULL) { + strncpy(tmp[i], p, strlen(p)); + p = strtok(NULL, "."); + + i++; + } + i--; + memset(&revname[0], 0, sizeof (revname)); + for (; i >= 0; i--) { + if (strlen(revname)) { + snprintf(tmpdom, strlen(revname)+strlen(tmp[i])+2, + "%s.%s", revname, tmp[i]); + snprintf(revname, strlen(tmpdom)+1, "%s", tmpdom); + } else { + strncpy(revname, tmp[i], strlen(tmp[i])); + revname [sizeof(revname)-1] = '\0'; + } + } + } else { + /* Use the content of file as the IQN => "iqn.2012-11.com.bayour" */ + if (fgets(buffer, sizeof (buffer), iscsi_target_name_fp) != NULL) { + strncpy(file_iqn, buffer, sizeof (file_iqn)-1); + file_iqn[strlen(file_iqn)-1] = '\0'; + } else { + fprintf(stderr, "ERROR: Can't read from %s: %s\n", TARGET_NAME_FILE, + strerror(errno)); + return -1; + } + + fclose(iscsi_target_name_fp); + } + + /* Take the dataset name, replace / with . */ + strncpy(name, path, sizeof(name)); + pos = name; + while (*pos != '\0') { + switch( *pos ) { + case '/': + case '-': + case ':': + case ' ': + *pos = '.'; + } + ++pos; + } + + /* Put the whole thing togheter => "iqn.2012-11.com.bayour:share.VirtualMachines.Astrix" */ + if (strlen(file_iqn)) + snprintf(iqn, iqn_len, "%s:%s", file_iqn, name); + else + snprintf(iqn, iqn_len, "iqn.%s.%s:%s", tsbuf, revname, name); + + return SA_OK; +} + +/* + * iscsi_retrieve_targets() retrieves list of iSCSI targets from + * /proc/net/iet/volume + */ +static int +iscsi_retrieve_targets(void) +{ + FILE *iscsi_volumes_fp = NULL; + char buffer[512]; + char *line, *token, *key, *value, *colon, *dup_value; + char *tid = NULL, *name = NULL, *lun = NULL, *state = NULL; + char *iotype = NULL, *iomode = NULL, *blocks = NULL; + char *blocksize = NULL, *path = NULL; + iscsi_target_t *target, *new_targets = NULL; + int buffer_len, rc = SA_OK; + enum { ISCSI_TARGET, ISCSI_LUN } type; + + /* Open file with targets */ + iscsi_volumes_fp = fopen(PROC_IET_VOLUME, "r"); + if (iscsi_volumes_fp == NULL) { + rc = SA_SYSTEM_ERR; + goto out; + } + + /* Load the file... */ + while (fgets(buffer, sizeof (buffer), iscsi_volumes_fp) != NULL) { + /* tid:1 name:iqn.2011-12.com.bayour:storage.astrix + * lun:0 state:0 iotype:fileio iomode:wt \ + * blocks:31457280 blocksize:512 \ + * path:/dev/zvol/tank/VMs/Astrix + */ + + /* Trim trailing new-line character(s). */ + buffer_len = strlen(buffer); + while (buffer[buffer_len - 1] == '\r' || + buffer[buffer_len - 1] == '\n') + buffer[buffer_len - 1] = '\0'; + + if (buffer[0] != '\t') { + /* + * Line doesn't start with a TAB which means this is a + * target definition + */ + line = buffer; + type = ISCSI_TARGET; + + free(tid); + tid = NULL; + + free(name); + name = NULL; + } else { + /* LUN definition */ + line = buffer + 1; + type = ISCSI_LUN; + + free(lun); + lun = NULL; + + free(state); + state = NULL; + + free(iotype); + iotype = NULL; + + free(iomode); + iomode = NULL; + + free(blocks); + blocks = NULL; + + free(blocksize); + blocksize = NULL; + + free(path); + path = NULL; + } + + /* Get each option, which is separated by space */ + /* token='tid:18' */ + token = strtok(line, " "); + while (token != NULL) { + colon = strchr(token, ':'); + + if (colon == NULL) + goto next; + + key = token; + value = colon + 1; + *colon = '\0'; + + dup_value = strdup(value); + + if (dup_value == NULL) { + rc = SA_NO_MEMORY; + goto out; + } + + if (type == ISCSI_TARGET) { + if (strcmp(key, "tid") == 0) + tid = dup_value; + else if (strcmp(key, "name") == 0) + name = dup_value; + else + free(dup_value); + } else { + if (strcmp(key, "lun") == 0) + lun = dup_value; + else if (strcmp(key, "state") == 0) + state = dup_value; + else if (strcmp(key, "iotype") == 0) + iotype = dup_value; + else if (strcmp(key, "iomode") == 0) + iomode = dup_value; + else if (strcmp(key, "blocks") == 0) + blocks = dup_value; + else if (strcmp(key, "blocksize") == 0) + blocksize = dup_value; + else if (strcmp(key, "path") == 0) + path = dup_value; + else + free(dup_value); + } + +next: + token = strtok(NULL, " "); + } + + if (type != ISCSI_LUN) + continue; + + if (tid == NULL || name == NULL || lun == NULL || + state == NULL || iotype == NULL || iomode == NULL || + blocks == NULL || blocksize == NULL || path == NULL) + continue; /* Incomplete LUN definition */ + + target = (iscsi_target_t *)malloc(sizeof (iscsi_target_t)); + if (target == NULL) { + rc = SA_NO_MEMORY; + goto out; + } + + target->tid = atoi(tid); + strncpy(target->name, name, sizeof (target->name)); + target->lun = atoi(lun); + target->state = atoi(state); + strncpy(target->iotype, iotype, sizeof (target->iotype)); + strncpy(target->iomode, iomode, sizeof (target->iomode)); + target->blocks = atoi(blocks); + target->blocksize = atoi(blocksize); + strncpy(target->path, path, sizeof (target->path)); + + /* Append the target to the list of new targets */ + target->next = new_targets; + new_targets = target; + } + + /* TODO: free existing iscsi_targets */ + iscsi_targets = new_targets; + +out: + if (iscsi_volumes_fp != NULL) + fclose(iscsi_volumes_fp); + + free(tid); + free(name); + free(lun); + free(state); + free(iotype); + free(iomode); + free(blocks); + free(blocksize); + free(path); + + return rc; +} + +int +iscsi_enable_share_one(int tid, char *sharename, const char *sharepath, + const char *iotype) +{ + char *argv[10]; + char params_name[255], params_path[255], tid_s[11]; + int rc; + + /* + * ietadm --op new --tid $next --params Name=$iqn + * ietadm --op new --tid $next --lun=0 --params \ + * Path=/dev/zvol/$sharepath,Type=$iotype + */ + + /* ====== */ + /* PART 1 */ + snprintf(params_name, sizeof (params_name), "Name=%s", sharename); + + /* int: between -2,147,483,648 and 2,147,483,647 => 10 chars + NUL */ + snprintf(tid_s, sizeof(tid_s), "%d", tid); + + argv[0] = IETM_CMD_PATH; + argv[1] = (char*)"--op"; + argv[2] = (char*)"new"; + argv[3] = (char*)"--tid"; + argv[4] = tid_s; + argv[5] = (char*)"--params"; + argv[6] = params_name; + argv[7] = NULL; + + rc = libzfs_run_process(argv[0], argv, 0); + if (rc < 0) + return SA_SYSTEM_ERR; + + /* ====== */ + /* PART 2 */ + snprintf(params_path, sizeof (params_path), + "Path=%s,Type=%s", sharepath, iotype); + + argv[5] = (char*)"--lun"; + argv[6] = (char*)"0"; + argv[7] = (char*)"--params"; + argv[8] = params_path; + argv[9] = NULL; + + rc = libzfs_run_process(argv[0], argv, 0); + if (rc < 0) + return SA_SYSTEM_ERR; + + /* ====== */ + /* Part 3 */ + argv[0] = (char*)EXTRA_SHARE_SCRIPT; + argv[1] = tid_s; + argv[2] = NULL; + + rc = libzfs_run_process(argv[0], argv, 0); + if (rc < 0) + return SA_SYSTEM_ERR; + + /* ====== */ + /* Reload the share file */ + iscsi_retrieve_targets(); + + return SA_OK; +} + +static int +iscsi_enable_share(sa_share_impl_t impl_share) +{ + char *shareopts; + char iqn[255]; + int tid = 0; + iscsi_target_t *target = iscsi_targets; + + if (!iscsi_available) + return SA_SYSTEM_ERR; + + shareopts = FSINFO(impl_share, iscsi_fstype)->shareopts; + + if (shareopts == NULL) /* on/off */ + return SA_SYSTEM_ERR; + + if (strcmp(shareopts, "off") == 0) + return SA_OK; + + if (iscsi_generate_target(impl_share->dataset, iqn, sizeof (iqn)) < 0) + return SA_SYSTEM_ERR; + + /* Go through list of targets, take next avail. */ + while (target != NULL) { + tid = target->tid; + target = target->next; + } + tid++; /* Next TID is/should be availible */ + + /* Magic: Enable (i.e., 'create new') share */ + return iscsi_enable_share_one(tid, iqn, + impl_share->sharepath, "fileio"); +} + +int +iscsi_disable_share_one(int tid) +{ + char *argv[6]; + char tid_s[11]; + int rc; + + /* int: between -2,147,483,648 and 2,147,483,647 => 10 chars + NUL */ + snprintf(tid_s, sizeof (tid_s), "%d", tid); + + argv[0] = IETM_CMD_PATH; + argv[1] = (char*)"--op"; + argv[2] = (char*)"delete"; + argv[3] = (char*)"--tid"; + argv[4] = tid_s; + argv[5] = NULL; + + rc = libzfs_run_process(argv[0], argv, 0); + if (rc < 0) + return SA_SYSTEM_ERR; + else { + /* Reload the share file */ + iscsi_retrieve_targets(); + + return SA_OK; + } +} + +static int +iscsi_disable_share(sa_share_impl_t impl_share) +{ + if (!iscsi_available) { + /* + * The share can't possibly be active, so nothing + * needs to be done to disable it. + */ + return SA_OK; + } + + return SA_OK; +} + +int +iscsi_disable_share_all(void) +{ + int rc = 0; + iscsi_target_t *target = iscsi_targets; + + while (target != NULL) { + rc += iscsi_disable_share_one(target->tid); + + target = target->next; + } + + return rc; +} + +static boolean_t +iscsi_is_share_active(sa_share_impl_t impl_share) +{ + iscsi_target_t *target = iscsi_targets; + + while (target != NULL) { + if (strcmp(impl_share->sharepath, target->path) == 0) + return B_TRUE; + + target = target->next; + } + + return B_FALSE; +} + +static int +iscsi_validate_shareopts(const char *shareopts) +{ + if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0)) + return SA_OK; + return SA_SYNTAX_ERR; +} + +static int +iscsi_update_shareopts(sa_share_impl_t impl_share, const char *resource, + const char *shareopts) +{ + char *shareopts_dup; + boolean_t needs_reshare = B_FALSE; + char *old_shareopts; + + FSINFO(impl_share, iscsi_fstype)->active = + iscsi_is_share_active(impl_share); + + old_shareopts = FSINFO(impl_share, iscsi_fstype)->shareopts; + + if (FSINFO(impl_share, iscsi_fstype)->active && old_shareopts != NULL && + strcmp(old_shareopts, shareopts) != 0) { + needs_reshare = B_TRUE; + iscsi_disable_share(impl_share); + } + + shareopts_dup = strdup(shareopts); + + if (shareopts_dup == NULL) + return SA_NO_MEMORY; + + if (old_shareopts != NULL) + free(old_shareopts); + + FSINFO(impl_share, iscsi_fstype)->shareopts = shareopts_dup; + + if (needs_reshare) + iscsi_enable_share(impl_share); + + return SA_OK; +} + +static void +iscsi_clear_shareopts(sa_share_impl_t impl_share) +{ + free(FSINFO(impl_share, iscsi_fstype)->shareopts); + FSINFO(impl_share, iscsi_fstype)->shareopts = NULL; +} + +static const sa_share_ops_t iscsi_shareops = { + .enable_share = iscsi_enable_share, + .disable_share = iscsi_disable_share, + + .validate_shareopts = iscsi_validate_shareopts, + .update_shareopts = iscsi_update_shareopts, + .clear_shareopts = iscsi_clear_shareopts, +}; + +void +libshare_iscsi_init(void) +{ + iscsi_available = (iscsi_retrieve_targets() == SA_OK); + + iscsi_fstype = register_fstype("iscsi", &iscsi_shareops); +} diff --git a/lib/libshare/iscsi.h b/lib/libshare/iscsi.h new file mode 100644 index 000000000000..3180f711ff28 --- /dev/null +++ b/lib/libshare/iscsi.h @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 Gunnar Beutner + */ + +typedef struct iscsi_target_s { + int tid; /* Target ID */ + char name[255]; /* Target Name */ + int lun; /* Target LUN */ + int state; /* Target State */ + char iotype[3]; /* Target IO Type */ + char iomode[20]; /* Target IO Mode */ + int blocks; /* Target Size (blocks) */ + int blocksize; /* Target Block Size (bytes) */ + char path[255]; /* Target Path */ + + struct iscsi_target_s *next; +} iscsi_target_t; + +iscsi_target_t *iscsi_targets; + +void libshare_iscsi_init(void); +int iscsi_generate_target(const char *, char *, size_t); +int iscsi_enable_share_one(int, char *, const char *, const char *); +int iscsi_disable_share_one(int); +int iscsi_disable_share_all(void); diff --git a/lib/libshare/iscsi_test.c b/lib/libshare/iscsi_test.c new file mode 100644 index 000000000000..e047f5c4184a --- /dev/null +++ b/lib/libshare/iscsi_test.c @@ -0,0 +1,108 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* Copyright (c) 2011 Turbo Fredriksson */ + +/* This is a simple debug command to verify that the zfs module + * retreives values from the iSCSI layer. + * It will/should output each TID, it's Name and Path of the iSCSI + * target, one per line. Must be run on the iSCSI target machine. + * + * If you don't get any output (or want to make sure it retreive all + * nessesary values, such as LUN, block sizes etc), try compiling the + * iscsi.c file with DEBUG and see what happens. + * + * + * Currently only supports the IET iSCSI target implementation (simply + * because that's what I run). Feel free to add support for the TGT iSCSI + * implementation... + * + * + * This command is not built by default since it's only a verification/debug + * command. To compile it, execute + * + * make iscsi_test + * + * in it's directory and run it like this: + * + * ./iscsi_test + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libshare_impl.h" +#include "iscsi.h" + +extern boolean_t iscsi_available; +extern iscsi_target_t *iscsi_targets; + +int +main(void) +{ + int tid = 0; + iscsi_target_t *temp; +#ifdef DEBUG + char iqn[255]; +#endif + + printf("iscsi_available=%d\n", iscsi_available); + if (!iscsi_available) + exit(SA_SYSTEM_ERR); + + temp = iscsi_targets; + do + { + if(temp->next == NULL) + break; + + printf(" main tid=%2d => %s ; %s\n", + temp->tid, temp->name, temp->path); + + tid = temp->tid; + temp = temp->next; + } while (temp != iscsi_targets); + tid++; /* Next TID is/should be availible */ + +#ifdef DEBUG + printf("\nfirst free tid=%d\n", tid); + + iscsi_generate_target("share/test2", iqn, sizeof (iqn)); + + if (iscsi_enable_share_one(tid, iqn, + "/dev/zvol/share/VirtualMachines/Test", + "fileio")) + { + printf("ERROR: Failed to create share\n"); + exit(SA_SYSTEM_ERR); + } + + iscsi_disable_share_one(tid); +#endif + + exit(SA_OK); +} diff --git a/lib/libshare/libshare.c b/lib/libshare/libshare.c index 6b39ba8724e2..79e143d4acce 100644 --- a/lib/libshare/libshare.c +++ b/lib/libshare/libshare.c @@ -37,6 +37,7 @@ #include "libshare_impl.h" #include "nfs.h" #include "smb.h" +#include "iscsi.h" static sa_share_impl_t find_share(sa_handle_impl_t handle, const char *sharepath); @@ -105,6 +106,7 @@ libshare_init(void) { libshare_nfs_init(); libshare_smb_init(); + libshare_iscsi_init(); /* * This bit causes /etc/dfs/sharetab to be updated before libzfs gets a @@ -240,21 +242,17 @@ update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie) char *dataset; zfs_type_t type = zfs_get_type(zhp); - if (type == ZFS_TYPE_FILESYSTEM && - zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) { - zfs_close(zhp); - return 1; - } - - if (type != ZFS_TYPE_FILESYSTEM) { - zfs_close(zhp); - return 0; - } + if (type == ZFS_TYPE_FILESYSTEM) { + if (zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) { + zfs_close(zhp); + return 1; + } - if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, - sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { - zfs_close(zhp); - return 0; + if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, + sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { + zfs_close(zhp); + return 0; + } } dataset = (char *)zfs_get_name(zhp); @@ -264,25 +262,35 @@ update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie) return 0; } - if (!zfs_is_mounted(zhp, NULL)) { - zfs_close(zhp); - return 0; - } + if (type == ZFS_TYPE_VOLUME) { + if ((udata->proto == NULL || strcmp(udata->proto, "iscsi") == 0) && + zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, + sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 && + strcmp(shareopts, "off") != 0) { + (void) process_share(udata->handle, NULL, mountpoint, NULL, + "iscsi", shareopts, NULL, dataset, B_FALSE); + } + } else { + if (!zfs_is_mounted(zhp, NULL)) { + zfs_close(zhp); + return 0; + } - if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) && - zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, - sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 && - strcmp(shareopts, "off") != 0) { - (void) process_share(udata->handle, NULL, mountpoint, NULL, - "nfs", shareopts, NULL, dataset, B_FALSE); - } + if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) && + zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, + sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 && + strcmp(shareopts, "off") != 0) { + (void) process_share(udata->handle, NULL, mountpoint, NULL, + "nfs", shareopts, NULL, dataset, B_FALSE); + } - if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) && - zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts, - sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 && - strcmp(shareopts, "off") != 0) { - (void) process_share(udata->handle, NULL, mountpoint, NULL, - "smb", shareopts, NULL, dataset, B_FALSE); + if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) && + zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts, + sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 && + strcmp(shareopts, "off") != 0) { + (void) process_share(udata->handle, NULL, mountpoint, NULL, + "smb", shareopts, NULL, dataset, B_FALSE); + } } zfs_close(zhp); @@ -303,7 +311,7 @@ update_zfs_share(sa_share_impl_t impl_share, const char *proto) assert(impl_share->dataset != NULL); zhp = zfs_open(impl_share->handle->zfs_libhandle, impl_share->dataset, - ZFS_TYPE_FILESYSTEM); + ZFS_TYPE_FILESYSTEM|ZFS_TYPE_VOLUME); if (zhp == NULL) return SA_SYSTEM_ERR; @@ -342,17 +350,38 @@ process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share, char *resource_dup = NULL, *dataset_dup = NULL; boolean_t new_share; sa_fstype_t *fstype; +// zfs_handle_t *zhp; +// zfs_type_t type; new_share = B_FALSE; if (impl_share == NULL) impl_share = find_share(impl_handle, pathname); +// if (impl_share != NULL) { +// /* Need this to be able to distinguish VOLUME from FILESYSTEM later */ +// zhp = zfs_open(impl_share->handle->zfs_libhandle, impl_share->dataset, +// ZFS_TYPE_FILESYSTEM|ZFS_TYPE_VOLUME); +// type = zfs_get_type(zhp); +// zfs_close(zhp); +// } +// +// if ((type == ZFS_TYPE_FILESYSTEM) && (impl_share == NULL)) { if (impl_share == NULL) { - if (lstat(pathname, &statbuf) != 0 || - !S_ISDIR(statbuf.st_mode)) + if (lstat(pathname, &statbuf) != 0) + return SA_BAD_PATH; + + if (!S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) + return SA_BAD_PATH; + + if (S_ISLNK(statbuf.st_mode)) { + if (stat(pathname, &statbuf) != 0) return SA_BAD_PATH; + if (!S_ISBLK(statbuf.st_mode)) + return SA_BAD_PATH; + } + impl_share = alloc_share(pathname); if (impl_share == NULL) { @@ -361,6 +390,15 @@ process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share, } new_share = B_TRUE; +// } else if (type == ZFS_TYPE_VOLUME) { +// impl_share = alloc_share(pathname); +// +// if (impl_share == NULL) { +// rc = SA_NO_MEMORY; +// goto err; +// } +// +// new_share = B_TRUE; } if (dataset != NULL) { diff --git a/lib/libshare/nfs.c b/lib/libshare/nfs.c index 53691ebe588f..7995668c6116 100644 --- a/lib/libshare/nfs.c +++ b/lib/libshare/nfs.c @@ -516,7 +516,7 @@ nfs_validate_shareopts(const char *shareopts) * Checks whether a share is currently active. */ static boolean_t -is_share_active(sa_share_impl_t impl_share) +nfs_is_share_active(sa_share_impl_t impl_share) { char line[512]; char *tab, *cur; @@ -587,7 +587,7 @@ nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource, boolean_t needs_reshare = B_FALSE; char *old_shareopts; - FSINFO(impl_share, nfs_fstype)->active = is_share_active(impl_share); + FSINFO(impl_share, nfs_fstype)->active = nfs_is_share_active(impl_share); old_shareopts = FSINFO(impl_share, nfs_fstype)->shareopts; diff --git a/lib/libshare/smb.c b/lib/libshare/smb.c index a2814a08a0ec..9adab05f7255 100644 --- a/lib/libshare/smb.c +++ b/lib/libshare/smb.c @@ -21,7 +21,8 @@ /* * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 Turbo Fredriksson + * Copyright (c) 2011,2012 Turbo Fredriksson , based on nfs.c + * by Gunnar Beutner * * This is an addition to the zfs device driver to add, modify and remove SMB * shares using the 'net share' command that comes with Samba. diff --git a/lib/libshare/test_zfs.sh b/lib/libshare/test_zfs.sh new file mode 100755 index 000000000000..23e0432ae14a --- /dev/null +++ b/lib/libshare/test_zfs.sh @@ -0,0 +1,190 @@ +#!/bin/bash + +BASETANK="tank" +DATE=`date "+%Y%m%d"` + +TEST_ISCSI=0 +TEST_SMBFS=0 +TEST_DESTROY=0 + +if [ -z "$1" ]; then + echo "Usage: `basename $0` [unpack]<[iscsi][smbfs][snapshot][all]>" + exit 1 +fi + +set_onoff() { + type="$1" + dataset="$2" + toggle="$3" + + current=`zfs get -H $type -o value $dataset` + if [ "$current" != "$toggle" ]; then + run "zfs set $type=$toggle $dataset" + fi +} + +check_exists() { + dataset="$1" + + extra="" + [ -n "$2" ] && extra="$2" + + zfs get all "$dataset" > /dev/null 2>&1 + if [ $? != 0 ]; then + run "zfs create $extra $dataset" + fi +} + +check_shares() { + if [ "$TEST_ISCSI" == "1" -o "$TEST_SMBFS" == "1" ]; then + echo + echo "Shares:" + + if [ "$TEST_ISCSI" == "1" ]; then + cat /proc/net/iet/volume + echo + fi + + if [ "$TEST_SMBFS" == "1" ]; then + net usershare list + echo + fi + fi + + sleep 2 +} + +run() { + cmd="$*" + + if [ "$TEST_ISCSI" == "1" -o "$TEST_SMBFS" == "1" ]; then + echo "-------------------" + fi + + echo "CMD: $cmd" + $cmd +} + +check_exists $BASETANK/tests + +# --------- +# Needs more work... +if echo "$*" | grep -qi "unpack"; then + zfs unmount -a + zfs unshare -a + run "zfs destroy -r $BASETANK/tests" + + sh /etc/init.d/zfs stop + +# for tid in `grep ^tid /proc/net/iet/volume | sed "s@.*:\([0-9].*\) name.*@\1@"` +# do +# ietadm --op delete --tid $tid +# done + + set -e + rmmod `lsmod | grep ^z | grep -v zlib_deflate | sed 's@ .*@@'` spl zlib_deflate + + pushd / > /dev/null + tar xzf tmp/zfs.tgz + popd > /dev/null + + depmod -a + + sh /etc/init.d/zfs start + set +e +fi + +# --------- +if echo "$*" | egrep -qi "iscsi|all"; then + TEST_ISCSI=1 + + for volnr in 1 2 3; do + check_exists $BASETANK/tests/iscsi$volnr "-V 15G" + done + + str= + for volnr in 1 2 3; do + str="$str $BASETANK/tests/iscsi$volnr" + done + run "zfs get shareiscsi $str" + + for volnr in 1 2 3; do + set_onoff shareiscsi $BASETANK/tests/iscsi$volnr on + done + + for volnr in 1 2 3; do + run "zfs share $BASETANK/tests/iscsi$volnr" ; check_shares + done + + for volnr in 2 1 3; do + run "zfs unshare $BASETANK/tests/iscsi$volnr" ; check_shares + done +fi + +# --------- +if echo "$*" | egrep -qi "smbfs|all"; then + TEST_SMBFS=1 + + for volnr in 1 2 3; do + check_exists $BASETANK/tests/smbfs$volnr + done + + str= + for volnr in 1 2 3; do + str="$str $BASETANK/tests/iscsi$volnr" + done + run "zfs get sharesmb $str" + + for volnr in 1 2 3; do + set_onoff sharesmb $BASETANK/tests/smbfs$volnr on + done + + for volnr in 1 2 3; do + run "zfs share $BASETANK/tests/smbfs$volnr" ; check_shares + done + + for volnr in 3 1 2; do + run "zfs unshare $BASETANK/tests/smbfs$volnr" ; check_shares + done +fi + +if echo "$*" | egrep -qi "iscsi|smbfs|all"; then + run "zfs share -a" ; check_shares + run "zfs unshare -a" ; check_shares + + if echo "$*" | egrep -qi "iscsi|all"; then + for volnr in 1 2 3; do + run "zfs destroy $BASETANK/tests/iscsi$volnr" + done + fi + + if echo "$*" | egrep -qi "smbfs|all"; then + for volnr in 1 2 3; do + run "zfs destroy $BASETANK/tests/smbfs$volnr" + done + fi +fi + +# --------- +if echo "$*" | grep -qi "snapshot|all"; then + echo ; echo "-------------------" + check_exists $BASETANK/tests/destroy + check_exists $BASETANK/tests/destroy/destroy1 + run "zfs destroy -r $BASETANK/tests/destroy" + + echo ; echo "-------------------" + check_exists $BASETANK/tests/destroy + run "zfs snapshot $BASETANK/tests/destroy@$DATE" + run "zfs destroy -r $BASETANK/tests/destroy" + + echo ; echo "-------------------" + check_exists $BASETANK/tests/destroy + run "zfs snapshot $BASETANK/tests/destroy@$DATE" + run "zfs destroy -r $BASETANK/tests/destroy@$DATE" + run "zfs destroy -r $BASETANK/tests/destroy" +fi + +if echo "$*" | egrep -qi "iscsi|smbfs|all"; then + run "zfs unshare -a" + run "zfs destroy -r $BASETANK/tests" +fi diff --git a/lib/libzfs/libzfs_changelist.c b/lib/libzfs/libzfs_changelist.c index 0bcfc0423b6b..39ec4e1a2747 100644 --- a/lib/libzfs/libzfs_changelist.c +++ b/lib/libzfs/libzfs_changelist.c @@ -72,7 +72,7 @@ typedef struct prop_changenode { struct prop_changelist { zfs_prop_t cl_prop; zfs_prop_t cl_realprop; - zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb */ + zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb/shareiscsi */ uu_list_pool_t *cl_pool; uu_list_t *cl_list; boolean_t cl_waslegacy; @@ -86,7 +86,7 @@ struct prop_changelist { /* * If the property is 'mountpoint', go through and unmount filesystems as - * necessary. We don't do the same for 'sharenfs', because we can just re-share + * necessary. We don't do the same for 'sharenfs'/'shareiscsi', because we can just re-share * with different options without interrupting service. We do handle 'sharesmb' * since there may be old resource names that need to be removed. */ @@ -195,6 +195,7 @@ changelist_postfix(prop_changelist_t *clp) boolean_t sharenfs; boolean_t sharesmb; + boolean_t shareiscsi; boolean_t mounted; /* @@ -226,10 +227,14 @@ changelist_postfix(prop_changelist_t *clp) shareopts, sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); + shareiscsi = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHAREISCSI, + shareopts, sizeof (shareopts), NULL, NULL, 0, + B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); + mounted = zfs_is_mounted(cn->cn_handle, NULL); if (!mounted && (cn->cn_mounted || - ((sharenfs || sharesmb || clp->cl_waslegacy) && + ((sharenfs || sharesmb || shareiscsi || clp->cl_waslegacy) && (zfs_prop_get_int(cn->cn_handle, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) { @@ -252,6 +257,10 @@ changelist_postfix(prop_changelist_t *clp) errors += zfs_share_smb(cn->cn_handle); else if (cn->cn_shared || clp->cl_waslegacy) errors += zfs_unshare_smb(cn->cn_handle, NULL); + if (shareiscsi && mounted) + errors += zfs_share_iscsi(cn->cn_handle); + else if (cn->cn_shared || clp->cl_waslegacy) + errors += zfs_unshare_iscsi(cn->cn_handle, NULL); } return (errors ? -1 : 0); @@ -321,7 +330,8 @@ changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto) int ret = 0; if (clp->cl_prop != ZFS_PROP_SHARENFS && - clp->cl_prop != ZFS_PROP_SHARESMB) + clp->cl_prop != ZFS_PROP_SHARESMB && + clp->cl_prop != ZFS_PROP_SHAREISCSI) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; @@ -417,7 +427,7 @@ change_one(zfs_handle_t *zhp, void *data) } /* - * If we are "watching" sharenfs or sharesmb + * If we are "watching" sharenfs, sharesmb or shareiscsi * then check out the companion property which is tracked * in cl_shareprop */ @@ -547,7 +557,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags, */ if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED || prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS || - prop == ZFS_PROP_SHARESMB) { + prop == ZFS_PROP_SHARESMB || prop == ZFS_PROP_SHAREISCSI) { if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, sizeof (property), @@ -611,13 +621,15 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags, if (clp->cl_prop != ZFS_PROP_MOUNTPOINT && clp->cl_prop != ZFS_PROP_SHARENFS && - clp->cl_prop != ZFS_PROP_SHARESMB) + clp->cl_prop != ZFS_PROP_SHARESMB && + clp->cl_prop != ZFS_PROP_SHAREISCSI) return (clp); /* - * If watching SHARENFS or SHARESMB then + * If watching SHARENFS, SHARESMB then * also watch its companion property. */ + /* TODO: add SHAREISCSI ? */ if (clp->cl_prop == ZFS_PROP_SHARENFS) clp->cl_shareprop = ZFS_PROP_SHARESMB; else if (clp->cl_prop == ZFS_PROP_SHARESMB) diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 7cf78c8f7e76..128f389758d0 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -1075,6 +1075,7 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, case ZFS_PROP_SHARESMB: case ZFS_PROP_SHARENFS: + case ZFS_PROP_SHAREISCSI: /* * For the mountpoint and sharenfs or sharesmb * properties, check if it can be set in a @@ -1101,7 +1102,8 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, errbuf); goto error; } else if (prop == ZFS_PROP_SHARENFS || - prop == ZFS_PROP_SHARESMB) { + prop == ZFS_PROP_SHARESMB || + prop == ZFS_PROP_SHAREISCSI) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set in " "a non-global zone"), propname); @@ -1127,12 +1129,15 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, * property value is valid if it is sharenfs. */ if ((prop == ZFS_PROP_SHARENFS || - prop == ZFS_PROP_SHARESMB) && + prop == ZFS_PROP_SHARESMB || + prop == ZFS_PROP_SHAREISCSI) && strcmp(strval, "on") != 0 && strcmp(strval, "off") != 0) { zfs_share_proto_t proto; - if (prop == ZFS_PROP_SHARESMB) + if (prop == ZFS_PROP_SHAREISCSI) + proto = PROTO_ISCSI; + else if (prop == ZFS_PROP_SHARESMB) proto = PROTO_SMB; else proto = PROTO_NFS; diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c index 0fe83e550c14..bb6db1735939 100644 --- a/lib/libzfs/libzfs_mount.c +++ b/lib/libzfs/libzfs_mount.c @@ -43,12 +43,15 @@ * * zfs_is_shared_nfs() * zfs_is_shared_smb() + * zfs_is_shared_iscsi() * zfs_share_proto() * zfs_shareall(); * zfs_unshare_nfs() * zfs_unshare_smb() + * zfs_unshare_iscsi() * zfs_unshareall_nfs() * zfs_unshareall_smb() + * zfs_unshareall_iscsi() * zfs_unshareall() * zfs_unshareall_bypath() * @@ -76,6 +79,7 @@ #include #include "libzfs_impl.h" +#include "../libshare/iscsi.h" #include #include @@ -99,6 +103,7 @@ typedef struct { proto_table_t proto_table[PROTO_END] = { {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED}, {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED}, + {ZFS_PROP_SHAREISCSI, "iscsi", EZFS_SHAREISCSIFAILED, EZFS_UNSHAREISCSIFAILED}, }; zfs_share_proto_t nfs_only[] = { @@ -110,9 +115,15 @@ zfs_share_proto_t smb_only[] = { PROTO_SMB, PROTO_END }; + +zfs_share_proto_t iscsi_only[] = { + PROTO_ISCSI, + PROTO_END +}; zfs_share_proto_t share_all_proto[] = { PROTO_NFS, PROTO_SMB, + PROTO_ISCSI, PROTO_END }; @@ -125,43 +136,55 @@ is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) { char buf[MAXPATHLEN], *tab; char *ptr; + iscsi_target_t *target = iscsi_targets; - if (hdl->libzfs_sharetab == NULL) - return (SHARED_NOT_SHARED); + switch (proto) { + case PROTO_ISCSI: + while (target != NULL) { + if (strcmp(mountpoint, target->path) == 0) + return (SHARED_ISCSI); - (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); - - while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { - - /* the mountpoint is the first entry on each line */ - if ((tab = strchr(buf, '\t')) == NULL) - continue; - - *tab = '\0'; - if (strcmp(buf, mountpoint) == 0) { - /* - * the protocol field is the third field - * skip over second field - */ - ptr = ++tab; - if ((tab = strchr(ptr, '\t')) == NULL) - continue; - ptr = ++tab; - if ((tab = strchr(ptr, '\t')) == NULL) - continue; - *tab = '\0'; - if (strcmp(ptr, - proto_table[proto].p_name) == 0) { - switch (proto) { - case PROTO_NFS: - return (SHARED_NFS); - case PROTO_SMB: - return (SHARED_SMB); - default: - return (0); + target = target->next; + } + break; + + default: + if (hdl->libzfs_sharetab == NULL) + return (SHARED_NOT_SHARED); + + (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); + + while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { + /* the mountpoint is the first entry on each line */ + if ((tab = strchr(buf, '\t')) == NULL) + continue; + + *tab = '\0'; + if (strcmp(buf, mountpoint) == 0) { + /* + * the protocol field is the third field + * skip over second field + */ + ptr = ++tab; + if ((tab = strchr(ptr, '\t')) == NULL) + continue; + ptr = ++tab; + if ((tab = strchr(ptr, '\t')) == NULL) + continue; + *tab = '\0'; + if (strcmp(ptr, + proto_table[proto].p_name) == 0) { + switch (proto) { + case PROTO_NFS: + return (SHARED_NFS); + case PROTO_SMB: + return (SHARED_SMB); + default: + return (0); + } + } } } - } } return (SHARED_NOT_SHARED); @@ -581,9 +604,6 @@ zfs_is_shared(zfs_handle_t *zhp) zfs_share_type_t rc = 0; zfs_share_proto_t *curr_proto; - if (ZFS_IS_VOLUME(zhp)) - return (B_FALSE); - for (curr_proto = share_all_proto; *curr_proto != PROTO_END; curr_proto++) rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); @@ -594,14 +614,12 @@ zfs_is_shared(zfs_handle_t *zhp) int zfs_share(zfs_handle_t *zhp) { - assert(!ZFS_IS_VOLUME(zhp)); return (zfs_share_proto(zhp, share_all_proto)); } int zfs_unshare(zfs_handle_t *zhp) { - assert(!ZFS_IS_VOLUME(zhp)); return (zfs_unshareall(zhp)); } @@ -614,7 +632,12 @@ zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) char *mountpoint; zfs_share_type_t rc; - if (!zfs_is_mounted(zhp, &mountpoint)) + if (ZFS_IS_VOLUME(zhp)) { + /* TODO: check whether this is sane */ + if (asprintf(&mountpoint, "/dev/zvol/%s", + zfs_get_name(zhp)) < 0) + return (SHARED_NOT_SHARED); + } else if (!zfs_is_mounted(zhp, &mountpoint)) return (SHARED_NOT_SHARED); if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))) { @@ -643,6 +666,13 @@ zfs_is_shared_smb(zfs_handle_t *zhp, char **where) PROTO_SMB) != SHARED_NOT_SHARED); } +boolean_t +zfs_is_shared_iscsi(zfs_handle_t *zhp, char **where) +{ + return (zfs_is_shared_proto(zhp, where, + PROTO_ISCSI) != SHARED_NOT_SHARED); +} + /* * zfs_init_libshare(zhandle, service) * @@ -711,7 +741,7 @@ zfs_parse_options(char *options, zfs_share_proto_t proto) /* * Share the given filesystem according to the options in the specified - * protocol specific properties (sharenfs, sharesmb). We rely + * protocol specific properties (sharenfs, sharesmb, shareiscsi). We rely * on "libshare" to the dirty work for us. */ static int @@ -726,13 +756,17 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) zprop_source_t sourcetype; int ret; - if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) + if (ZFS_IS_VOLUME(zhp)) + /* TODO: check whether this is sane */ + snprintf(mountpoint, sizeof (mountpoint), "/dev/zvol/%s", + zfs_get_name(zhp)); + else if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) return (0); if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, - dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), - zfs_get_name(zhp), sa_errorstr(ret)); + dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), + zfs_get_name(zhp), sa_errorstr(ret)); return (-1); } @@ -741,9 +775,9 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) * Return success if there are no share options. */ if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, - shareopts, sizeof (shareopts), &sourcetype, sourcestr, - ZFS_MAXPROPLEN, B_FALSE) != 0 || - strcmp(shareopts, "off") == 0) + shareopts, sizeof (shareopts), &sourcetype, sourcestr, + ZFS_MAXPROPLEN, B_FALSE) != 0 || + strcmp(shareopts, "off") == 0) continue; /* @@ -767,35 +801,35 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) * configuration. */ if (sa_zfs_process_share(hdl->libzfs_sharehdl, - NULL, NULL, mountpoint, - proto_table[*curr_proto].p_name, sourcetype, - shareopts, sourcestr, zhp->zfs_name) != SA_OK) { + NULL, NULL, mountpoint, + proto_table[*curr_proto].p_name, sourcetype, + shareopts, sourcestr, zhp->zfs_name) != SA_OK) { (void) zfs_error_fmt(hdl, - proto_table[*curr_proto].p_share_err, - dgettext(TEXT_DOMAIN, "cannot share '%s'"), - zfs_get_name(zhp)); + proto_table[*curr_proto].p_share_err, + dgettext(TEXT_DOMAIN, "cannot share '%s'"), + zfs_get_name(zhp)); return (-1); } hdl->libzfs_shareflags |= ZFSSHARE_MISS; share = sa_find_share(hdl->libzfs_sharehdl, - mountpoint); + mountpoint); } if (share != NULL) { int err; err = sa_enable_share(share, - proto_table[*curr_proto].p_name); + proto_table[*curr_proto].p_name); if (err != SA_OK) { (void) zfs_error_fmt(hdl, - proto_table[*curr_proto].p_share_err, - dgettext(TEXT_DOMAIN, "cannot share '%s'"), - zfs_get_name(zhp)); + proto_table[*curr_proto].p_share_err, + dgettext(TEXT_DOMAIN, "cannot share '%s'"), + zfs_get_name(zhp)); return (-1); } } else { (void) zfs_error_fmt(hdl, - proto_table[*curr_proto].p_share_err, - dgettext(TEXT_DOMAIN, "cannot share '%s'"), - zfs_get_name(zhp)); + proto_table[*curr_proto].p_share_err, + dgettext(TEXT_DOMAIN, "cannot share '%s'"), + zfs_get_name(zhp)); return (-1); } @@ -816,6 +850,12 @@ zfs_share_smb(zfs_handle_t *zhp) return (zfs_share_proto(zhp, smb_only)); } +int +zfs_share_iscsi(zfs_handle_t *zhp) +{ + return (zfs_share_proto(zhp, iscsi_only)); +} + int zfs_shareall(zfs_handle_t *zhp) { @@ -862,6 +902,7 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), name)); } + return (0); } @@ -874,34 +915,57 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, { libzfs_handle_t *hdl = zhp->zfs_hdl; struct mnttab entry; - char *mntpt = NULL; - - /* check to see if need to unmount the filesystem */ - rewind(zhp->zfs_hdl->libzfs_mnttab); - if (mountpoint != NULL) - mountpoint = mntpt = zfs_strdup(hdl, mountpoint); - - if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && - libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) { - zfs_share_proto_t *curr_proto; + char *mntpt = NULL, *mnt = NULL; + iscsi_target_t *target = iscsi_targets; + + switch (*proto) { + case PROTO_ISCSI: + if (mountpoint == NULL) { + /* TODO: check whether this is sane */ + if (asprintf(&mnt, "/dev/zvol/%s", zfs_get_name(zhp)) < 0) + return (-1); - if (mountpoint == NULL) - mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); + mountpoint = strdup(mnt); + } - for (curr_proto = proto; *curr_proto != PROTO_END; - curr_proto++) { + while (target != NULL) { + if (strcmp(mountpoint, target->path) == 0) + iscsi_disable_share_one(target->tid); - if (is_shared(hdl, mntpt, *curr_proto) && - unshare_one(hdl, zhp->zfs_name, - mntpt, *curr_proto) != 0) { - if (mntpt != NULL) - free(mntpt); - return (-1); + target = target->next; + } + break; + + default: + /* check to see if need to unmount the filesystem */ + rewind(zhp->zfs_hdl->libzfs_mnttab); + if (mountpoint != NULL) + mountpoint = mntpt = zfs_strdup(hdl, mountpoint); + + if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && + libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) + { + zfs_share_proto_t *curr_proto; + + if (mountpoint == NULL) + mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); + + for (curr_proto = proto; *curr_proto != PROTO_END; + curr_proto++) { + + if (is_shared(hdl, mntpt, *curr_proto) && + unshare_one(hdl, zhp->zfs_name, + mntpt, *curr_proto) != 0) { + if (mntpt != NULL) + free(mntpt); + return (-1); + } } } + + if (mntpt != NULL) + free(mntpt); } - if (mntpt != NULL) - free(mntpt); return (0); } @@ -918,6 +982,12 @@ zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) return (zfs_unshare_proto(zhp, mountpoint, smb_only)); } +int +zfs_unshare_iscsi(zfs_handle_t *zhp, const char *mountpoint) +{ + return (zfs_unshare_proto(zhp, mountpoint, iscsi_only)); +} + /* * Same as zfs_unmountall(), but for NFS and SMB unshares. */ @@ -949,6 +1019,12 @@ zfs_unshareall_smb(zfs_handle_t *zhp) return (zfs_unshareall_proto(zhp, smb_only)); } +int +zfs_unshareall_iscsi(zfs_handle_t *zhp) +{ + return (zfs_unshareall_proto(zhp, iscsi_only)); +} + int zfs_unshareall(zfs_handle_t *zhp) { diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 16affd1cec21..eb40bcf07bb4 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -138,6 +138,10 @@ libzfs_error_description(libzfs_handle_t *hdl) return (dgettext(TEXT_DOMAIN, "smb remove share failed")); case EZFS_SHARESMBFAILED: return (dgettext(TEXT_DOMAIN, "smb add share failed")); + case EZFS_UNSHAREISCSIFAILED: + return (dgettext(TEXT_DOMAIN, "iSCSI remove share failed")); + case EZFS_SHAREISCSIFAILED: + return (dgettext(TEXT_DOMAIN, "iSCSI add share failed")); case EZFS_PERM: return (dgettext(TEXT_DOMAIN, "permission denied")); case EZFS_NOSPC: diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index 2e8b728fe4b2..ee5fb36492fb 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -998,6 +998,22 @@ Controls whether the set-\fBUID\fR bit is respected for the file system. The def Like the \fBsharenfs\fR property, \fBshareiscsi\fR indicates whether a \fBZFS\fR volume is exported as an \fBiSCSI\fR target. The acceptable values for this property are \fBon\fR, \fBoff\fR, and \fBtype=disk\fR. The default value is \fBoff\fR. In the future, other target types might be supported. For example, \fBtape\fR. .sp You might want to set \fBshareiscsi=on\fR for a file system so that all \fBZFS\fR volumes within the file system are shared by default. However, setting this property on a file system has no direct effect. +.sp +The Linux implementation of \fBshareiscsi\fR uses \fBietadm\fR to add, remove and modify iSCSI targets. In addition to this, the module will use the optional script/binary named \fB/sbin/zfs_share_iscsi\fR. The only parameter to this script/binary is the TID number and this script is intended to allow administrators to allow custom commands to be done on the share/target. +.sp +The module will 'execute and forget'. Meaning, it will not care about exit code nor any output it gives. So if the script/binary fails for some reason, it is up to it to catch this. The ZFS module will not intervene. +.sp +The domainname needs to be set in \fB/etc/domainname\fR (by echo'ing the domain name to the file) or \fB/proc/sys/kernel/domainname\fR (by using sysctl - usually \fB/etc/sysctl.conf\fR) for the driver to work out the iqn correctly. +.sp +The module will either fetch the TID (\fBT\fRarget \fBID\fR) from \fB/etc/iscsi_target_id\fR or autogenerate it using the domain name (see above) and the current date (YYYY-MM). It will then add the volume name (replacing odd characters with slash). +.sp +The content of the \fB/etc/iscsi_target_id\fR can look some thing like this: +.LP +.in +2 +iqn.2012-11.com.bayour +.sp +.in -2 +That is: The word 'iqn', a dot, year and date, a dot and then the reversed form of the domain for the machine (in this case \fBbayour.com\fR) and then a newline. The line must start at the first column (no leading spaces etc) and contain only one line. .RE .sp @@ -3196,11 +3212,8 @@ The following example shows how to create a \fBZFS\fR volume as an \fBiSCSI\fR t .nf # \fBzfs create -V 2g pool/volumes/vol1\fR # \fBzfs set shareiscsi=on pool/volumes/vol1\fR -# \fBiscsitadm list target\fR -Target: pool/volumes/vol1 - iSCSI Name: - iqn.1986-03.com.sun:02:7b4b02a6-3277-eb1b-e686-a24762c52a8c - Connections: 0 +# \fBiscsiadm --mode node\fR +192.168.69.8:3260,1 iqn.2012-11.com.bayour:pool.volumes.vol1 .fi .in -2 .sp diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 0a0c25bd4175..cc12530ca397 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -310,6 +310,9 @@ zfs_prop_init(void) zprop_register_string(ZFS_PROP_MLSLABEL, "mlslabel", ZFS_MLSLABEL_DEFAULT, PROP_INHERIT, ZFS_TYPE_DATASET, "", "MLSLABEL"); + zprop_register_string(ZFS_PROP_SHAREISCSI, "shareiscsi", "off", + PROP_DEFAULT, ZFS_TYPE_VOLUME, "on | off | ietadm(8) options", + "SHAREISCSI"); /* readonly number properties */ zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,