diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index a052be520f50..f99a27b0be5e 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -64,6 +64,7 @@ #include "zfs_iter.h" #include "zfs_util.h" #include "zfs_comutil.h" +#include "../../libshare/iscsi.h" libzfs_handle_t *g_zfs; @@ -3159,6 +3160,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; @@ -5174,7 +5176,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); } @@ -5182,7 +5185,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); } @@ -5193,9 +5196,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; @@ -5231,10 +5236,12 @@ 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); + assert(type & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)); + 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 @@ -5274,7 +5281,8 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol, 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 && + if (op == OP_SHARE && + strcmp(shareopts, "off") == 0 && strcmp(smbshareopts, "off") == 0) { if (!explicit) return (0); @@ -5343,7 +5351,6 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol, */ switch (op) { case OP_SHARE: - shared_nfs = zfs_is_shared_nfs(zhp, NULL); shared_smb = zfs_is_shared_smb(zhp, NULL); @@ -5405,6 +5412,44 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol, return (1); break; } + } else { + assert(op == OP_SHARE); + + /* + * Ignore any volumes that aren't shared. + */ + verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, + sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); + + 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 (zfs_is_shared_iscsi(zhp, NULL)) { + if (!explicit) + return (0); + +#ifdef DEBUG + (void) fprintf(stderr, "share_mount_one(): zfs_is_shared()\n"); +#endif + (void) fprintf(stderr, gettext("cannot share " + "'%s': volume already shared\n"), + zfs_get_name(zhp)); + return (1); + } + + if (zfs_share_iscsi(zhp) != 0) + return (1); + } return (0); } @@ -5466,7 +5511,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:" : "a")) @@ -5513,16 +5558,24 @@ share_mount(int op, int argc, char **argv) size_t i, count = 0; char *protocol = NULL; - if (op == OP_SHARE && argc > 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) { @@ -5531,7 +5584,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); @@ -5576,14 +5629,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, @@ -5608,7 +5664,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. @@ -5710,19 +5766,26 @@ 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)) { +#ifdef DEBUG + (void) fprintf(stderr, "unshare_unmount_path(): !zfs_is_shared()\n"); +#endif (void) fprintf(stderr, gettext("cannot unshare '%s': " "not currently shared\n"), path); } else { @@ -5762,9 +5825,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 */ @@ -5822,10 +5885,15 @@ unshare_unmount(int op, int argc, char **argv) rewind(mnttab_file); while (getmntent(mnttab_file, &entry) == 0) { - +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): mountp=%s, mntopts=%s, fstype=%s\n", + entry.mnt_mountp, entry.mnt_mntopts, entry.mnt_fstype); /* ignore non-ZFS entries */ - if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) + if ((strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)) { +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): fstype=MNTTYPE_ZFS (%s)\n", MNTTYPE_ZFS); continue; + } /* ignore snapshots */ if (strchr(entry.mnt_special, '@') != NULL) @@ -5833,38 +5901,53 @@ unshare_unmount(int op, int argc, char **argv) if ((zhp = zfs_open(g_zfs, entry.mnt_special, ZFS_TYPE_FILESYSTEM)) == NULL) { +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): zfs_open(g_zfs, %ss, ZFS_TYPE_FILESYSTEM) => NULL\n", + entry.mnt_special); ret = 1; continue; } switch (op) { case OP_SHARE: +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): case OP_SHARE - verify(zfs_prop_get())\n"); verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, - 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, "off") != 0) + if (strcmp(nfsiscsi_mnt_prop, "off") != 0) break; verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, - nfs_mnt_prop, - sizeof (nfs_mnt_prop), + 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_SHAREISCSI, + nfsiscsi_mnt_prop, + sizeof (nfsiscsi_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfs_mnt_prop, "off") == 0) + if (strcmp(nfsiscsi_mnt_prop, "off") == 0) continue; break; case OP_MOUNT: +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): case OP_MOUNT - verify(zfs_prop_get())\n"); /* 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: +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): case default\n"); break; } @@ -5896,15 +5979,23 @@ unshare_unmount(int op, int argc, char **argv) switch (op) { case OP_SHARE: +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): case OP_SHARE - Calling zfs_unshareall_bypath(..., %s)\n", node->un_mountp); if (zfs_unshareall_bypath(node->un_zhp, node->un_mountp) != 0) ret = 1; +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): case OP_SHARE - zfs_unshareall_bypath() != 0. Returning 1\n"); break; case OP_MOUNT: +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): case OP_MOUNT - Calling zfs_unshareall_bypath(..., %s)\n", node->un_mountp); if (zfs_unmount(node->un_zhp, node->un_mountp, flags) != 0) ret = 1; +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(do_all): case OP_MOUNT - zfs_unshareall_bypath() != 0. Returning 1\n"); break; } @@ -5917,6 +6008,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) @@ -5938,26 +6031,35 @@ 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; + +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(): Calling zfs_open()\n"); + if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) { +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(): return(1)\n"); return (1); + } + if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { verify(zfs_prop_get(zhp, op == OP_SHARE ? ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, - nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL, + 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), + 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(nfs_mnt_prop, "off") == 0 && + if (strcmp(nfsiscsi_mnt_prop, "off") == 0 && strcmp(sharesmb, "off") == 0) { (void) fprintf(stderr, gettext("cannot " "unshare '%s': legacy share\n"), @@ -5977,7 +6079,7 @@ unshare_unmount(int op, int argc, char **argv) break; case OP_MOUNT: - if (strcmp(nfs_mnt_prop, "legacy") == 0) { + if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) { (void) fprintf(stderr, gettext("cannot " "unmount '%s': legacy " "mountpoint\n"), zfs_get_name(zhp)); @@ -5996,10 +6098,44 @@ unshare_unmount(int op, int argc, char **argv) } 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); + +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(): nfsiscsi_mnt_prop=%s\n", nfsiscsi_mnt_prop); + 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_shared_iscsi(zhp, NULL)) { +// DEBUG +fprintf(stderr, "zfs_main.c:unshare_unmount(): !zfs_is_shared_iscsi(zhp, NULL)\n"); + (void) fprintf(stderr, gettext("cannot " + "unshare '%s': not currently shared\n"), + zfs_get_name(zhp)); + ret = 1; + } else if (zfs_unshare_iscsi(zhp, NULL) != 0) { +// DEBUG +fprintf(stderr, "zfs_main.c:unshare_unmount(): zfs_unshare_iscsi(zhp, NULL) != 0 -> returning 1\n"); + ret = 1; + } + } +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(): Calling zfs_close()\n"); zfs_close(zhp); } +// DEBUG +fprintf(stderr, " zfs_main.c:unshare_unmount(): Returning %d\n", ret); return (ret); } @@ -6024,7 +6160,9 @@ zfs_do_unmount(int argc, char **argv) static int zfs_do_unshare(int argc, char **argv) { - return (unshare_unmount(OP_SHARE, argc, argv)); +// DEBUG +fprintf(stderr, "zfs_main.c:zfs_do_unshare(): Call unshare_unmount(OP_SHARE)\n"); + return(unshare_unmount(OP_SHARE, argc, argv)); // Unmount/unshare all NFS/SMB FS } static int diff --git a/include/libzfs.h b/include/libzfs.h index 26b1ce302b99..358f3507b46b 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -143,6 +143,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 }; @@ -523,6 +525,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; @@ -660,13 +663,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 2389b7823aaa..1c12bb62f45f 100644 --- a/include/libzfs_impl.h +++ b/include/libzfs_impl.h @@ -122,7 +122,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; /* @@ -132,7 +133,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 2b6abbf1bd50..bf110d677a6f 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -124,6 +124,7 @@ typedef enum { ZFS_PROP_MLSLABEL, ZFS_PROP_SYNC, ZFS_PROP_REFRATIO, + ZFS_PROP_SHAREISCSI, ZFS_NUM_PROPS } zfs_prop_t; @@ -287,7 +288,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/.gitignore b/lib/libshare/.gitignore new file mode 100644 index 000000000000..08e06b33f675 --- /dev/null +++ b/lib/libshare/.gitignore @@ -0,0 +1 @@ +iscsi_test diff --git a/lib/libshare/Makefile.am b/lib/libshare/Makefile.am index b66df8c56e86..e1863c908b06 100644 --- a/lib/libshare/Makefile.am +++ b/lib/libshare/Makefile.am @@ -8,8 +8,15 @@ lib_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/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 3705c7d28fec..20f817506e39 100644 --- a/lib/libshare/Makefile.in +++ b/lib/libshare/Makefile.in @@ -114,7 +114,7 @@ am__base_list = \ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libshare_la_LIBADD = -am_libshare_la_OBJECTS = libshare.lo nfs.lo +am_libshare_la_OBJECTS = libshare.lo nfs.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)) @@ -147,8 +147,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) @@ -333,11 +333,30 @@ AM_CFLAGS = -Wall -Wstrict-prototypes -fno-strict-aliasing \ lib_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/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 .SUFFIXES: @@ -406,14 +425,19 @@ clean-libLTLIBRARIES: libshare.la: $(libshare_la_OBJECTS) $(libshare_la_DEPENDENCIES) $(AM_V_CCLD)$(libshare_la_LINK) -rpath $(libdir) $(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 @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)/iscsi.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -455,6 +479,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/README_iscsi.txt b/lib/libshare/README_iscsi.txt new file mode 100644 index 000000000000..a0994e09ad2f --- /dev/null +++ b/lib/libshare/README_iscsi.txt @@ -0,0 +1,13 @@ +This is iSCSI support for the IET iSCSI targets. + +It will call ietmadm 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 + +PS. The domainname needs to be set in /proc/sys/kernel/domainname + for the driver to work out the iqn correctly. You can either + set it by echo'ing the domain name to the file, OR set it + using sysctl. diff --git a/lib/libshare/iscsi.c b/lib/libshare/iscsi.c new file mode 100644 index 000000000000..3aeddd46fec2 --- /dev/null +++ b/lib/libshare/iscsi.c @@ -0,0 +1,551 @@ +/* + * 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 , 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. + */ + +#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; + +#if DEBUG >= 3 +#define PROC_IET_VOLUME "/tmp/volume" +#else +#define PROC_IET_VOLUME "/proc/net/iet/volume" +#endif + +/* + * By Jerome Bettis + * http://ubuntuforums.org/showthread.php?t=141670 + */ +static void +strrep(char *str, char old, char new) +{ + char *pos; + + if (new == old) + return; + + pos = strchr(str, old); + while (pos != NULL) { + *pos = new; + pos = strchr(pos + 1, old); + } +} + +/* + * 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[255], revname[255], name[255], + tmpdom[255], *p, tmp[20][255]; + time_t now; + struct tm *now_local; + int i; + + /* Get current time in EPOH */ + now = time(NULL); + now_local = localtime(&now); + if (now_local == NULL) + return -1; + + /* Parse EPOH and get YYY-MM */ + if (strftime(tsbuf, sizeof (tsbuf), "%Y-%m", now_local) == 0) + return -1; + + /* Retrieve the domain */ + if ((getdomainname(domain, sizeof (domain)) < 0) || + (strcmp(domain, "(none)") == 0)) + { + fprintf(stderr, "ERROR: Can't get domainname: %s\n", strerror(errno)); + return -1; + } + + /* 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])); + } + + /* Take the dataset name, replace / with . */ + strncpy(name, path, sizeof(name)); + strrep(name, '/', '.'); + + /* Put the whole thing togheter */ + snprintf(iqn, iqn_len, "iqn.%s.%s:%s", tsbuf, revname, name); + + return 0; +} + +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[16]; + int rc; + + /* + * ietadm --op new --tid $next --params Name=$iqn + * ietadm --op new --tid $next --lun=0 --params \ + * Path=/dev/zvol/$sharepath,Type=$iotype + */ + +#ifdef DEBUG + fprintf(stderr, "iscsi_enable_share_one(%d, %s, %s, %s)\n", + tid, sharename, sharepath, iotype); +#endif + + /* PART 1 */ + snprintf(params_name, sizeof (params_name), "Name=%s", sharename); + + /* int: between -2,147,483,648 and 2,147,483,647 => 10 chars + EOL */ + snprintf(tid_s, sizeof(tid_s), "%d", tid); + + argv[0] = "/usr/sbin/ietadm"; + argv[1] = "--op"; + argv[2] = "new"; + argv[3] = "--tid"; + argv[4] = tid_s; + argv[5] = "--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] = "--lun"; + argv[6] = "0"; + argv[7] = "--params"; + argv[8] = params_path; + argv[9] = NULL; + + rc = libzfs_run_process(argv[0], argv, 0); + if (rc < 0) + return SA_SYSTEM_ERR; + + /* Reload the share file */ + iscsi_retrieve_targets(); + + return 0; +} + +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; + +// DEBUG +fprintf(stderr, "iscsi_enable_share(): dataset=%s\n", impl_share->dataset); + + 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 (0); + + 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; +// DEBUG +fprintf(stderr, "iscsi_enable_share(): tid=%d (%s)\n", target->tid, target->name); + + target = target->next; + } + tid++; /* Next TID is/should be availible */ +// DEBUG +fprintf(stderr, "iscsi_enable_share(): next tid=%d\n", tid); + + /* 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) +{ + int rc; + char *argv[6]; + char tid_s[16]; + +#ifdef DEBUG + fprintf(stderr, "iscsi_disable_share_one(%d)\n", tid); +#endif + + /* int: between -2,147,483,648 and 2,147,483,647 => 10 chars + EOL */ + snprintf(tid_s, sizeof (tid_s), "%d", tid); + + argv[0] = "/usr/sbin/ietadm"; + argv[1] = "--op"; + argv[2] = "delete"; + argv[3] = "--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) +{ + /* TODO: implement */ + return 0; +} + +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 0; +} + +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, +}; + +/* + * iscsi_retrieve_targets() retrieves list of iSCSI targets from + * /proc/net/iet/volume + */ +int +iscsi_retrieve_targets(void) +{ + FILE *iscsi_volumes_fp; + 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 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/share/VMs/Astrix + */ + + /* Trim trailing new-line character(s). */ + while (buffer[strlen(buffer) - 1] == '\r' || + buffer[strlen(buffer) - 1] == '\n') + buffer[strlen(buffer) - 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; +} + +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..341a3cf6a58e --- /dev/null +++ b/lib/libshare/iscsi.h @@ -0,0 +1,48 @@ +/* + * 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); +int iscsi_retrieve_targets(void); diff --git a/lib/libshare/iscsi_test.c b/lib/libshare/iscsi_test.c new file mode 100644 index 000000000000..b7aaffa08500 --- /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 = malloc( sizeof(iscsi_target_t) ); +#ifdef DEBUG + char iqn[255]; +#endif + + printf("iscsi_available=%d\n", iscsi_available); + if(iscsi_available) { + 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); + } else + exit(SA_SYSTEM_ERR); +} diff --git a/lib/libshare/libshare.c b/lib/libshare/libshare.c index c34e83919402..22ee2ae6ac5e 100644 --- a/lib/libshare/libshare.c +++ b/lib/libshare/libshare.c @@ -36,6 +36,7 @@ #include #include "libshare_impl.h" #include "nfs.h" +#include "iscsi.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_iscsi_init(); /* * This bit causes /etc/dfs/sharetab to be updated before libzfs gets a @@ -283,6 +285,14 @@ update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie) "smb", shareopts, NULL, dataset, B_FALSE); } + 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); + } + zfs_close(zhp); return 0; @@ -301,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; @@ -347,10 +357,20 @@ process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share, impl_share = find_share(impl_handle, pathname); 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) { @@ -446,6 +466,9 @@ sa_fini(sa_handle_t handle) /* remove item from the linked list */ *pcurr = next; +// DEBUG +fprintf(stderr, "libshare.c:sa_fini(): Calling sa_disable_share(%s:%s)\n", + impl_share->dataset, impl_share->sharepath); sa_disable_share(impl_share, NULL); free_share(impl_share); @@ -502,11 +525,6 @@ sa_enable_share(sa_share_t share, char *protocol) boolean_t found_protocol; sa_fstype_t *fstype; -#ifdef DEBUG - fprintf(stderr, "sa_enable_share: share->sharepath=%s, protocol=%s\n", - impl_share->sharepath, protocol); -#endif - assert(impl_share->handle != NULL); ret = SA_OK; @@ -543,17 +561,15 @@ sa_disable_share(sa_share_t share, char *protocol) boolean_t found_protocol; sa_fstype_t *fstype; -#ifdef DEBUG - fprintf(stderr, "sa_disable_share: share->sharepath=%s, protocol=%s\n", - impl_share->sharepath, protocol); -#endif - ret = SA_OK; found_protocol = B_FALSE; fstype = fstypes; while (fstype != NULL) { if (protocol == NULL || strcmp(fstype->name, protocol) == 0) { +// DEBUG +fprintf(stderr, " libshare.c:sa_disable_share(): calling fstype->ops->disable_share() (%s:%s)\n", + impl_share->dataset, impl_share->sharepath); rc = fstype->ops->disable_share(impl_share); if (rc == SA_OK) { @@ -701,11 +717,6 @@ sa_parse_legacy_options(sa_group_t group, char *options, char *proto) { sa_fstype_t *fstype; -#ifdef DEBUG - fprintf(stderr, "sa_parse_legacy_options: options=%s, proto=%s\n", - options, proto); -#endif - fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, proto) != 0) { @@ -791,12 +802,6 @@ sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; sa_share_impl_t impl_share = (sa_share_impl_t)share; -#ifdef DEBUG - fprintf(stderr, "sa_zfs_process_share: mountpoint=%s, proto=%s, " - "shareopts=%s, sourcestr=%s, dataset=%s\n", mountpoint, proto, - shareopts, sourcestr, dataset); -#endif - return process_share(impl_handle, impl_share, mountpoint, NULL, proto, shareopts, NULL, dataset, B_FALSE); } diff --git a/lib/libshare/nfs.c b/lib/libshare/nfs.c index 22e306d4370f..426926a4d979 100644 --- a/lib/libshare/nfs.c +++ b/lib/libshare/nfs.c @@ -514,7 +514,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; @@ -585,7 +585,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/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 44fdadd17277..546cdc01b0f0 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -1000,6 +1000,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 @@ -1026,7 +1027,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); @@ -1052,12 +1054,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 6758f6a0946e..7be0c47d48df 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,14 +136,29 @@ 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; + + switch (proto) { + case PROTO_ISCSI: + while (target != NULL) { + if (strcmp(mountpoint, target->path) == 0) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:is_shared(PROTO_ISCSI): mountpoint=%s (%d:%s)\n", + mountpoint, target->tid, target->path); + return (SHARED_ISCSI); + } + + 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; @@ -163,6 +189,7 @@ is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) } } } + } return (SHARED_NOT_SHARED); } @@ -579,9 +606,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); @@ -592,14 +616,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)); } @@ -612,16 +634,30 @@ 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 */ +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_is_shared_proto(ZFS_IS_VOLUME()): name=%s\n", zfs_get_name(zhp)); + if (asprintf(&mountpoint, "/dev/zvol/%s", + zfs_get_name(zhp)) < 0) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_is_shared_proto(): asprintf() < 0 => returning SHARED_NOT_SHARED\n"); + return (SHARED_NOT_SHARED); + } + } else if (!zfs_is_mounted(zhp, &mountpoint)) return (SHARED_NOT_SHARED); if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_is_shared_proto(): is_shared() returned %d (mountpoint=%s)\n", rc, mountpoint); if (where != NULL) *where = mountpoint; else free(mountpoint); return (rc); } else { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_is_shared_proto(): !is_shared() => SHARED_NOT_SHARED (mountpoint=%s)\n", mountpoint); free(mountpoint); return (SHARED_NOT_SHARED); } @@ -641,6 +677,15 @@ 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) +{ +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_is_shared_iscsi(): Calling zfs_is_shared_proto()\n"); + return (zfs_is_shared_proto(zhp, where, + PROTO_ISCSI) != SHARED_NOT_SHARED); +} + /* * zfs_init_libshare(zhandle, service) * @@ -709,7 +754,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 @@ -724,7 +769,11 @@ 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) { @@ -814,6 +863,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) { @@ -836,6 +891,8 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, * value. */ mntpt = zfs_strdup(hdl, mountpoint); +// DEBUG +fprintf(stderr, "unshare_one(hdl, %s, %s, proto): mntpt=%s\n", name, mountpoint, mntpt); /* make sure libshare initialized */ if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { @@ -849,17 +906,25 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, free(mntpt); /* don't need the copy anymore */ if (share != NULL) { +// DEBUG +fprintf(stderr, "unshare_one(): share != NULL, calling sa_disable_share()\n"); err = sa_disable_share(share, proto_table[proto].p_name); if (err != SA_OK) { +// DEBUG +fprintf(stderr, "unshare_one(): sa_disable_share() didn't return SA_OK\n"); return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), name, sa_errorstr(err))); } } else { +// DEBUG +fprintf(stderr, "unshare_one(): share == NULL\n"); return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), name)); } +// DEBUG +fprintf(stderr, "unshare_one(): done, returning 0\n"); return (0); } @@ -872,8 +937,42 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, { libzfs_handle_t *hdl = zhp->zfs_hdl; struct mnttab entry; - char *mntpt = NULL; + char *mntpt = NULL, *mnt = NULL; + iscsi_target_t *target = iscsi_targets; + +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(zhp, %s, proto), name=%s\n", + mountpoint, zfs_get_name(zhp)); + switch (*proto) { + case PROTO_ISCSI: + if (mountpoint == NULL) { + /* TODO: check whether this is sane */ +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(PROTO_ISCSI)): name=%s\n", zfs_get_name(zhp)); + if (asprintf(&mnt, "/dev/zvol/%s", zfs_get_name(zhp)) < 0) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(PROTO_ISCSI): asprintf() < 0 => returning -1\n"); + return (-1); + } + + mountpoint = strdup(mnt); + } + +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(PROTO_ISCSI)): name=%s, path=%s\n", + zfs_get_name(zhp), mountpoint); + while (target != NULL) { + if (strcmp(mountpoint, target->path) == 0) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(PROTO_ISCSI): name=%s, path=%s (%d:%s)\n", + zfs_get_name(zhp), mountpoint, target->tid, target->path); + iscsi_disable_share_one(target->tid); + } + target = target->next; + } + break; + default: /* check to see if need to unmount the filesystem */ rewind(zhp->zfs_hdl->libzfs_mnttab); if (mountpoint != NULL) @@ -881,6 +980,8 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(zhp, %s, proto) - inside big if()\n", mountpoint); zfs_share_proto_t *curr_proto; if (mountpoint == NULL) @@ -889,9 +990,15 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(zhp, %s, proto) - inside big if()/Calling is_shared(hdl, %s, curr_proto)\n", + mountpoint, mntpt); if (is_shared(hdl, mntpt, *curr_proto) && unshare_one(hdl, zhp->zfs_name, mntpt, *curr_proto) != 0) { +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_proto(zhp, %s, proto) - inside big if()/is_shared()+unshare_one(hdl, %s)\n", + mountpoint, zhp->zfs_name); if (mntpt != NULL) free(mntpt); return (-1); @@ -900,6 +1007,7 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, } if (mntpt != NULL) free(mntpt); + } return (0); } @@ -916,6 +1024,14 @@ 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) +{ +// DEBUG +fprintf(stderr, " libzfs_mount.c:zfs_unshare_iscsi(): Calling zfs_unshare_proto(zhp, %s)\n", mountpoint); + return (zfs_unshare_proto(zhp, mountpoint, iscsi_only)); +} + /* * Same as zfs_unmountall(), but for NFS and SMB unshares. */ @@ -947,6 +1063,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 5f6763c49010..de70748b45b2 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -137,6 +137,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/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 9afe3d900850..7eb3795ecd74 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -308,6 +308,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(8M) options", + "SHAREISCSI"); /* readonly number properties */ zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY, diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index c8ff0359553c..6d03213a9cca 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -5047,9 +5047,9 @@ _init(void) tsd_create(&zfs_fsyncer_key, NULL); tsd_create(&rrw_tsd_key, NULL); - printk(KERN_NOTICE "ZFS: Loaded module v%s%s, " + printk(KERN_NOTICE "ZFS: Loaded module v%s-%s%s, " "ZFS pool version %s, ZFS filesystem version %s\n", - ZFS_META_VERSION, ZFS_DEBUG_STR, + ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR, SPA_VERSION_STRING, ZPL_VERSION_STRING); return (0);