summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorGordon Ross <gwr@nexenta.com>2017-08-12 10:54:18 -0400
committerGordon Ross <gwr@nexenta.com>2019-03-14 10:38:30 -0400
commit8329232e00f1048795bae53acb230316243aadb5 (patch)
tree0d9a71c0dd22bd5288debd1dcc2cd3f0e7131d67 /usr/src/lib
parentebee07ff4f102cbd3179db7c5070283da35a79f3 (diff)
downloadillumos-joyent-8329232e00f1048795bae53acb230316243aadb5.tar.gz
9874 Add fksmbcl development tool
Reviewed by: Evan Layton <evan.layton@nexenta.com> Reviewed by: Matt Barden <matt.barden@nexenta.com> Approved by: Joshua M. Clulow <josh@sysmgr.org>
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile2
-rw-r--r--usr/src/lib/libfakekernel/Makefile.com7
-rw-r--r--usr/src/lib/libfakekernel/common/copy.c30
-rw-r--r--usr/src/lib/libfakekernel/common/cred.c60
-rw-r--r--usr/src/lib/libfakekernel/common/kmisc.c13
-rw-r--r--usr/src/lib/libfakekernel/common/mapfile-vers12
-rw-r--r--usr/src/lib/libfakekernel/common/printf.c29
-rw-r--r--usr/src/lib/libfakekernel/common/rwlock.c1
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cmn_err.h8
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cred.h5
-rw-r--r--usr/src/lib/libfakekernel/common/sys/cyclic.h87
-rw-r--r--usr/src/lib/libfakekernel/common/uio.c4
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com16
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h8
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_api.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c49
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c14
-rw-r--r--usr/src/lib/libsmbfs/smb/findvc.c6
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_wk.c12
-rw-r--r--usr/src/lib/libsmbfs/smb/keychain.c6
-rw-r--r--usr/src/lib/libsmbfs/smb/lgrep.awk68
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers16
-rw-r--r--usr/src/lib/libsmbfs/smb/print.c11
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c12
-rw-r--r--usr/src/lib/libsmbfs/smb/rq.c9
-rw-r--r--usr/src/lib/smbclnt/Makefile24
-rw-r--r--usr/src/lib/smbclnt/Makefile.lib51
-rw-r--r--usr/src/lib/smbclnt/Makefile.smbclnt66
-rw-r--r--usr/src/lib/smbclnt/Makefile.subdirs43
-rw-r--r--usr/src/lib/smbclnt/Makefile.targ50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/Makefile16
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/Makefile.com106
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/amd64/Makefile21
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c133
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c105
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c45
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c432
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c48
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c90
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c263
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c1377
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c160
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h314
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c163
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h45
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb19
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers121
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h67
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h183
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h50
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h70
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h65
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h141
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h622
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h116
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h1452
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/i386/Makefile18
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/sparc/Makefile18
-rw-r--r--usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile23
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/Makefile16
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/Makefile.com137
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile23
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c432
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c96
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c173
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c108
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c195
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c124
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c340
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c123
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c203
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c96
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c91
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c2155
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c2026
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c76
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c235
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h73
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs19
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers68
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/i386/Makefile20
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile20
-rw-r--r--usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile24
84 files changed, 13791 insertions, 142 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 8c5142641d..bc68f6fc34 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -265,6 +265,7 @@ SUBDIRS += \
rpcsec_gss \
sasl_plugins \
scsi \
+ smbclnt \
smbsrv \
smhba \
sun_fc \
@@ -697,6 +698,7 @@ raidcfg_plugins: libraidcfg librcm libcfgadm libpicl libpicltree
rpcsec_gss: libgss
sasl_plugins: pkcs11 libgss libsasl
scsi: libfru libumem libdevid libdevinfo
+smbclnt: libfakekernel pkcs11
smbsrv: libxnet libpthread librt libshare libidmap pkcs11 libsqlite \
libcryptoutil libreparse libcmdutils libresolv2 libsmbfs \
libuuid libfakekernel libads libgss libldap5 krb5 libmlrpc
diff --git a/usr/src/lib/libfakekernel/Makefile.com b/usr/src/lib/libfakekernel/Makefile.com
index ef1abe4072..f9135717e6 100644
--- a/usr/src/lib/libfakekernel/Makefile.com
+++ b/usr/src/lib/libfakekernel/Makefile.com
@@ -56,10 +56,15 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CSTD = $(CSTD_GNU99)
C99LMODE = -Xc99=%all
+CFLAGS += $(CCVERBOSE)
+
# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also Note: intentionally override CPPFLAGS, not +=
CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common
-CFLAGS += $(CCVERBOSE)
CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
CPPFLAGS += -D_FILE_OFFSET_BITS=64
diff --git a/usr/src/lib/libfakekernel/common/copy.c b/usr/src/lib/libfakekernel/common/copy.c
index b1eb215b5c..77bf2e8415 100644
--- a/usr/src/lib/libfakekernel/common/copy.c
+++ b/usr/src/lib/libfakekernel/common/copy.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
@@ -20,6 +20,20 @@
#include <sys/errno.h>
int
+copyin(const void *u, void *k, size_t s)
+{
+ bcopy(u, k, s);
+ return (0);
+}
+
+int
+copyout(const void *k, void *u, size_t s)
+{
+ bcopy(k, u, s);
+ return (0);
+}
+
+int
copyinstr(const char *src, char *dst, size_t max_len, size_t *copied)
{
return (copystr(src, dst, max_len, copied));
@@ -48,3 +62,17 @@ ovbcopy(const void *src, void *dst, size_t len)
{
(void) memmove(dst, src, len);
}
+
+/* ARGSUSED */
+int
+ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
+{
+ return (copyin(buf, kernbuf, size));
+}
+
+/* ARGSUSED */
+int
+ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
+{
+ return (copyout(buf, kernbuf, size));
+}
diff --git a/usr/src/lib/libfakekernel/common/cred.c b/usr/src/lib/libfakekernel/common/cred.c
index 1563f02ac9..0920599d0a 100644
--- a/usr/src/lib/libfakekernel/common/cred.c
+++ b/usr/src/lib/libfakekernel/common/cred.c
@@ -10,28 +10,51 @@
*/
/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 RackTop Systems.
*/
-
#include <sys/types.h>
#include <sys/time.h>
#include <sys/thread.h>
#include <sys/cred.h>
+#include <sys/sid.h>
+#include <strings.h>
+
+/*
+ * This library does not implement real credentials. All contexts
+ * use an opaque cred_t object, and all activity happens in the
+ * context of the user who runs the program.
+ */
+
+extern struct zone zone0;
struct cred {
+ uid_t cr_uid;
+ ksid_t *cr_ksid;
uint32_t pad[100];
};
cred_t cred0;
cred_t *kcred = &cred0;
+/*
+ * Note that fksmbd uses CRED() for SMB user logons, but uses
+ * zone_kcred() for operations done internally by the server.
+ * Let CRED() (_curcred()) return &cred1, so it's different from
+ * kcred, otherwise tests like: (cred == kcred) are always true.
+ * Also, only cred1 will have a ksid (not kcred).
+ * The UID and SID are both "nobody".
+ */
+ksiddomain_t ksdom1 = {1, 5, "S-1-0", {0}};
+ksid_t ksid1 = { 60001, 0, 0, &ksdom1};
+cred_t cred1 = { 60001, &ksid1 };
+
cred_t *
_curcred(void)
{
/* Thread-specific data? */
- return (&cred0);
+ return (&cred1);
}
/*ARGSUSED*/
@@ -50,14 +73,14 @@ crhold(cred_t *cr)
uid_t
crgetuid(const cred_t *cr)
{
- return (0);
+ return (cr->cr_uid);
}
/*ARGSUSED*/
uid_t
crgetruid(const cred_t *cr)
{
- return (0);
+ return (cr->cr_uid);
}
/*ARGSUSED*/
@@ -81,8 +104,35 @@ crgetgroups(const cred_t *cr)
return (NULL);
}
+/*ARGSUSED*/
+zoneid_t
+crgetzoneid(const cred_t *cr)
+{
+ return (GLOBAL_ZONEID);
+}
+
+/*ARGSUSED*/
+struct zone *
+crgetzone(const cred_t *cr)
+{
+ return (&zone0);
+}
+
cred_t *
zone_kcred(void)
{
return (kcred);
}
+
+/*ARGSUSED*/
+ksid_t *
+crgetsid(const cred_t *cr, int i)
+{
+ return (cr->cr_ksid);
+}
+
+cred_t *
+ddi_get_cred(void)
+{
+ return (_curcred());
+}
diff --git a/usr/src/lib/libfakekernel/common/kmisc.c b/usr/src/lib/libfakekernel/common/kmisc.c
index 2849552a66..5feaa66a28 100644
--- a/usr/src/lib/libfakekernel/common/kmisc.c
+++ b/usr/src/lib/libfakekernel/common/kmisc.c
@@ -30,9 +30,12 @@
#include <fakekernel.h>
pri_t minclsyspri = 60;
+extern zone_t zone0;
/* Some kernel code takes the address of this. */
-proc_t p0;
+proc_t p0 = {
+ .p_zone = &zone0, 0
+};
proc_t *
_curproc(void)
@@ -99,11 +102,10 @@ ddi_strtoul(const char *str, char **endp, int base, unsigned long *res)
}
int
-ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *res)
+ddi_strtoull(const char *str, char **endp, int base, u_longlong_t *res)
{
- char *end;
-
- *res = strtoull(str, &end, base);
+ errno = 0;
+ *res = strtoull(str, endp, base);
if (*res == 0)
return (errno);
return (0);
@@ -116,6 +118,7 @@ delay(clock_t ticks)
(void) poll(0, 0, msec);
}
+/* ARGSUSED */
int
issig(int why)
{
diff --git a/usr/src/lib/libfakekernel/common/mapfile-vers b/usr/src/lib/libfakekernel/common/mapfile-vers
index 42af216580..7f7422c63c 100644
--- a/usr/src/lib/libfakekernel/common/mapfile-vers
+++ b/usr/src/lib/libfakekernel/common/mapfile-vers
@@ -42,7 +42,9 @@ SYMBOL_VERSION SUNWprivate_1.1 {
aok { FLAGS = NODIRECT };
boot_time;
cmn_err;
+ copyin;
copyinstr;
+ copyout;
copystr;
cyclic_add;
@@ -55,6 +57,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
crgetgid;
crgetngroups;
crgetgroups;
+ crgetzone;
+ crgetzoneid;
crhold;
cv_broadcast;
@@ -69,12 +73,16 @@ SYMBOL_VERSION SUNWprivate_1.1 {
cv_wait;
cv_wait_sig;
+ ddi_copyin;
+ ddi_copyout;
+ ddi_get_cred;
ddi_get_lbolt64;
ddi_get_lbolt;
ddi_get_pid;
ddi_strtoul;
ddi_strtoull;
+ debug_enter;
delay;
fm_panic;
@@ -196,7 +204,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
strfree;
system_taskq;
- system_taskq_fini;
+ system_taskq_fini;
system_taskq_init;
taskq_create;
taskq_create_proc;
@@ -225,8 +233,10 @@ SYMBOL_VERSION SUNWprivate_1.1 {
vcmn_err;
vmem_qcache_reap;
vpanic;
+ vzprintf;
zone0;
zone_kcred;
+ zprintf;
zthread_create;
zthread_exit;
diff --git a/usr/src/lib/libfakekernel/common/printf.c b/usr/src/lib/libfakekernel/common/printf.c
index c8f459dd8c..bbf350b75e 100644
--- a/usr/src/lib/libfakekernel/common/printf.c
+++ b/usr/src/lib/libfakekernel/common/printf.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 RackTop Systems.
* Copyright (c) 2018, Joyent, Inc.
*/
@@ -36,6 +36,7 @@
#include <fakekernel.h>
void abort(void) __NORETURN;
+void debug_enter(char *);
char *volatile panicstr;
va_list panicargs;
@@ -100,6 +101,24 @@ fakekernel_cprintf(const char *fmt, va_list adx, int flags,
fakekernel_putlog(bufp, len, flags);
}
+/* ARGSUSED */
+void
+vzprintf(zoneid_t zoneid, const char *fmt, va_list adx)
+{
+ fakekernel_cprintf(fmt, adx, SL_CONSOLE | SL_NOTE, "", "");
+}
+
+/*PRINTFLIKE2*/
+void
+zprintf(zoneid_t zoneid, const char *fmt, ...)
+{
+ va_list adx;
+
+ va_start(adx, fmt);
+ vzprintf(zoneid, fmt, adx);
+ va_end(adx);
+}
+
/*
* "User-level crash dump", if you will.
*/
@@ -116,6 +135,7 @@ vpanic(const char *fmt, va_list adx)
/* Call libc`assfail() so that mdb ::status works */
(void) vsnprintf(panicbuf, sizeof (panicbuf), fmt, adx);
+ debug_enter(panicbuf);
(void) assfail(panicbuf, "(panic)", 0);
abort(); /* avoid "noreturn" warnings */
@@ -164,3 +184,10 @@ cmn_err(int ce, const char *fmt, ...)
vcmn_err(ce, fmt, adx);
va_end(adx);
}
+
+/* ARGSUSED */
+void
+debug_enter(char *str)
+{
+ /* Just a place for a break point. */
+}
diff --git a/usr/src/lib/libfakekernel/common/rwlock.c b/usr/src/lib/libfakekernel/common/rwlock.c
index 17b4ca604d..edc9bfd092 100644
--- a/usr/src/lib/libfakekernel/common/rwlock.c
+++ b/usr/src/lib/libfakekernel/common/rwlock.c
@@ -23,7 +23,6 @@
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/param.h>
-#include <sys/synch32.h>
#include <sys/thread.h>
/* avoiding synch.h */
diff --git a/usr/src/lib/libfakekernel/common/sys/cmn_err.h b/usr/src/lib/libfakekernel/common/sys/cmn_err.h
index c77b22b868..b9818f58c5 100644
--- a/usr/src/lib/libfakekernel/common/sys/cmn_err.h
+++ b/usr/src/lib/libfakekernel/common/sys/cmn_err.h
@@ -64,6 +64,10 @@ extern void cmn_err(int, const char *, ...)
extern void vcmn_err(int, const char *, __va_list)
__KVPRINTFLIKE(2);
+/*PRINTFLIKE3*/
+extern void zcmn_err(zoneid_t, int, const char *, ...)
+ __KPRINTFLIKE(3);
+
/*PRINTFLIKE1*/
extern void panic(const char *, ...)
__KPRINTFLIKE(1) __NORETURN;
@@ -71,6 +75,10 @@ extern void panic(const char *, ...)
extern void vpanic(const char *, __va_list)
__KVPRINTFLIKE(1) __NORETURN;
+/*PRINTFLIKE2*/
+extern void zprintf(zoneid_t, const char *, ...)
+ __KPRINTFLIKE(2);
+
#endif /* !_ASM && (_KERNEL || _FAKE_KERNEL) */
#ifdef __cplusplus
diff --git a/usr/src/lib/libfakekernel/common/sys/cred.h b/usr/src/lib/libfakekernel/common/sys/cred.h
index d544e04275..a338214843 100644
--- a/usr/src/lib/libfakekernel/common/sys/cred.h
+++ b/usr/src/lib/libfakekernel/common/sys/cred.h
@@ -27,7 +27,7 @@
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
@@ -66,6 +66,8 @@ extern void cred_init(void);
extern void crhold(cred_t *);
extern void crfree(cred_t *);
+extern int groupmember(gid_t, const cred_t *);
+
extern cred_t *zone_kcred(void);
extern uid_t crgetuid(const cred_t *);
@@ -75,6 +77,7 @@ extern gid_t crgetgid(const cred_t *);
extern gid_t crgetrgid(const cred_t *);
extern gid_t crgetsgid(const cred_t *);
extern zoneid_t crgetzoneid(const cred_t *);
+extern struct zone *crgetzone(const cred_t *);
extern projid_t crgetprojid(const cred_t *);
extern const gid_t *crgetgroups(const cred_t *);
diff --git a/usr/src/lib/libfakekernel/common/sys/cyclic.h b/usr/src/lib/libfakekernel/common/sys/cyclic.h
new file mode 100644
index 0000000000..56589ae7f1
--- /dev/null
+++ b/usr/src/lib/libfakekernel/common/sys/cyclic.h
@@ -0,0 +1,87 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 RackTop Systems.
+ */
+
+#ifndef _SYS_CYCLIC_H
+#define _SYS_CYCLIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ASM
+#include <sys/time.h>
+#endif /* !_ASM */
+
+#define CY_LOW_LEVEL 0
+#define CY_LOCK_LEVEL 1
+#define CY_HIGH_LEVEL 2
+#define CY_SOFT_LEVELS 2
+#define CY_LEVELS 3
+
+#ifndef _ASM
+
+typedef uintptr_t cyclic_id_t;
+typedef int cyc_index_t;
+typedef int cyc_cookie_t;
+typedef uint16_t cyc_level_t;
+typedef void (*cyc_func_t)(void *);
+typedef void *cyb_arg_t;
+
+#define CYCLIC_NONE ((cyclic_id_t)0)
+
+typedef struct cyc_handler {
+ cyc_func_t cyh_func;
+ void *cyh_arg;
+ cyc_level_t cyh_level;
+} cyc_handler_t;
+
+typedef struct cyc_time {
+ hrtime_t cyt_when;
+ hrtime_t cyt_interval;
+} cyc_time_t;
+
+#define CY_INFINITY INT64_MAX
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
+extern void cyclic_remove(cyclic_id_t);
+extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
+extern hrtime_t cyclic_getres();
+
+extern void cyclic_suspend();
+extern void cyclic_resume();
+
+#endif /* _KERNEL || _FAKE_KERNEL */
+
+#endif /* !_ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CYCLIC_H */
diff --git a/usr/src/lib/libfakekernel/common/uio.c b/usr/src/lib/libfakekernel/common/uio.c
index 3048faff58..99cb4e04e8 100644
--- a/usr/src/lib/libfakekernel/common/uio.c
+++ b/usr/src/lib/libfakekernel/common/uio.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -42,10 +42,10 @@ uiomove(void *p, size_t n, enum uio_rw rw, struct uio *uio)
}
switch (uio->uio_segflg) {
- case UIO_USERSPACE:
case UIO_USERISPACE:
return (EINVAL);
+ case UIO_USERSPACE:
case UIO_SYSSPACE:
if (rw == UIO_READ)
bcopy(p, iov->iov_base, cnt);
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
index 160494aff1..3a5c62c46c 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -111,23 +111,21 @@ CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
-I$(SRC)/uts/common \
-I$(SRC)/common/smbclnt
+# This is pretty mature code, so let's just ignore these.
+LINTCHECKFLAGS += -erroff=E_INCONS_ARG_DECL2
+LINTCHECKFLAGS += -erroff=E_INCONS_VAL_TYPE_DECL2
+LINTCHECKFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2
+LINTCHECKFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+
# Debugging
${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
-# Filter out the less important lint.
-# See lgrep.awk
-LGREP = $(AWK) -f $(SRCDIR)/lgrep.awk
-LTAIL += 2>&1 | $(LGREP)
-
all: $(LIBS)
-lint: lintcheck_t
+lint: lintcheck
include ../../Makefile.targ
-lintcheck_t: $$(SRCS)
- $(LINT.c) $(LINTCHECKFLAGS) $(SRCS) $(LDLIBS) $(LTAIL)
-
objs/%.o pics/%.o: $(CMNDIR)/%.c
$(COMPILE.c) -o $@ $<
$(POST_PROCESS_O)
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index c1dc6886ac..1f6e062e74 100644
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -136,8 +136,8 @@ struct smb_ctx {
#define ct_owner ct_iod_ssn.iod_ossn.ssn_owner
#define ct_srvaddr ct_iod_ssn.iod_ossn.ssn_srvaddr
#define ct_domain ct_iod_ssn.iod_ossn.ssn_domain
-#define ct_user ct_iod_ssn.iod_ossn.ssn_user
-#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname
+#define ct_user ct_iod_ssn.iod_ossn.ssn_user
+#define ct_srvname ct_iod_ssn.iod_ossn.ssn_srvname
#define ct_authflags ct_iod_ssn.iod_authflags
#define ct_nthash ct_iod_ssn.iod_nthash
#define ct_lmhash ct_iod_ssn.iod_lmhash
@@ -181,6 +181,8 @@ struct smb_ctx {
int smb_ctx_init(struct smb_ctx *);
void smb_ctx_done(struct smb_ctx *);
int smb_open_driver(void);
+int nsmb_ioctl(int, int, void *);
+int nsmb_close(int);
int smb_ctx_gethandle(struct smb_ctx *);
int smb_ctx_findvc(struct smb_ctx *);
diff --git a/usr/src/lib/libsmbfs/smb/acl_api.c b/usr/src/lib/libsmbfs/smb/acl_api.c
index 052539316b..92a3262f79 100644
--- a/usr/src/lib/libsmbfs/smb/acl_api.c
+++ b/usr/src/lib/libsmbfs/smb/acl_api.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -83,6 +85,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
return (error);
m = mbp->mb_top;
+ bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = 0;
@@ -91,7 +94,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
/*
* This does the OTW Get.
*/
- if (ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
+ if (nsmb_ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
error = errno;
goto errout;
}
@@ -120,6 +123,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
if (mbp->mb_top != m)
mb_initm(mbp, m);
+ bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = m->m_len;
@@ -128,7 +132,7 @@ smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
/*
* This does the OTW Set.
*/
- if (ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
+ if (nsmb_ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
error = errno;
return (error);
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 9455a92344..e28599e28f 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -333,7 +333,12 @@ smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
cf_opt_lock();
/* Careful: no return/goto before cf_opt_unlock! */
while (error == 0) {
- opt = cf_getopt(argc, argv, STDPARAM_OPT);
+ /*
+ * Leading ':' tells this to skip unknown opts.
+ * Just get -A and -U here so we know the user
+ * for config file parsing.
+ */
+ opt = cf_getopt(argc, argv, ":AU:");
if (opt == -1)
break;
arg = cf_optarg;
@@ -398,7 +403,7 @@ smb_ctx_done(struct smb_ctx *ctx)
rpc_cleanup_smbctx(ctx);
if (ctx->ct_dev_fd != -1) {
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
}
if (ctx->ct_door_fd != -1) {
@@ -1147,6 +1152,10 @@ smb_ctx_resolve(struct smb_ctx *ctx)
return (0);
}
+/*
+ * Note: The next three have NODIRECT binding so the
+ * "fksmbcl" development tool can provide its own.
+ */
int
smb_open_driver()
{
@@ -1164,6 +1173,19 @@ smb_open_driver()
}
int
+nsmb_close(int fd)
+{
+ return (close(fd));
+}
+
+int
+nsmb_ioctl(int fd, int cmd, void *arg)
+{
+ return (ioctl(fd, cmd, arg));
+}
+
+
+int
smb_ctx_gethandle(struct smb_ctx *ctx)
{
int fd, err;
@@ -1171,7 +1193,7 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
if (ctx->ct_dev_fd != -1) {
rpc_cleanup_smbctx(ctx);
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
ctx->ct_flags &= ~SMBCF_SSNACTIVE;
}
@@ -1187,12 +1209,12 @@ smb_ctx_gethandle(struct smb_ctx *ctx)
/*
* Check the driver version (paranoia)
*/
- if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
+ if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0)
version = 0;
if (version != NSMB_VERSION) {
smb_error(dgettext(TEXT_DOMAIN,
"incorrect driver version"), 0);
- close(fd);
+ nsmb_close(fd);
return (ENODEV);
}
@@ -1221,6 +1243,15 @@ smb_ctx_get_ssn(struct smb_ctx *ctx)
DPRINT("found an existing VC");
} else {
/*
+ * If we're authenticating (real user, not NULL session)
+ * and we don't yet have a password, return EAUTH and
+ * the caller will prompt for it and call again.
+ */
+ if (ctx->ct_user[0] != '\0' &&
+ ctx->ct_password[0] == '\0')
+ return (EAUTH);
+
+ /*
* This calls the IOD to create a new session.
*/
DPRINT("setup a new VC");
@@ -1272,7 +1303,7 @@ smb_ctx_get_tree(struct smb_ctx *ctx)
*
* The driver does the actual TCON call.
*/
- if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
+ if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
err = errno;
goto out;
}
@@ -1303,7 +1334,7 @@ smb_ctx_flags2(struct smb_ctx *ctx)
{
uint16_t flags2;
- if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
smb_error(dgettext(TEXT_DOMAIN,
"can't get flags2 for a session"), errno);
return (-1);
@@ -1321,7 +1352,7 @@ smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
if (len < SMBIOC_HASH_SZ)
return (EINVAL);
- if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
+ if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
return (errno);
return (0);
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
index 8ca9d2cee1..b104502d9c 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -33,7 +33,7 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -65,7 +65,7 @@
int
smb_fh_close(int fd)
{
- return (close(fd));
+ return (nsmb_close(fd));
}
int
@@ -96,7 +96,7 @@ smb_fh_ntcreate(
goto errout;
}
from_fd = ctx->ct_dev_fd;
- if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
err = errno;
goto errout;
}
@@ -111,7 +111,7 @@ smb_fh_ntcreate(
ioc.ioc_share_acc = share_acc;
ioc.ioc_open_disp = open_disp;
ioc.ioc_creat_opts = create_opts;
- if (ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_NTCREATE, &ioc) == -1) {
err = errno;
goto errout;
}
@@ -120,7 +120,7 @@ smb_fh_ntcreate(
errout:
if (new_fd != -1)
- close(new_fd);
+ nsmb_close(new_fd);
errno = err;
return (-1);
}
@@ -214,7 +214,7 @@ smb_fh_read(int fd, off64_t offset, size_t count,
rwrq.ioc_base = dst;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(fd, SMBIOC_READ, &rwrq) == -1) {
+ if (nsmb_ioctl(fd, SMBIOC_READ, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
@@ -231,7 +231,7 @@ smb_fh_write(int fd, off64_t offset, size_t count,
rwrq.ioc_base = (char *)src;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- if (ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) {
+ if (nsmb_ioctl(fd, SMBIOC_WRITE, &rwrq) == -1) {
return (-1);
}
return (rwrq.ioc_cnt);
diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c
index 63c6cce242..9d9ccd678c 100644
--- a/usr/src/lib/libsmbfs/smb/findvc.c
+++ b/usr/src/lib/libsmbfs/smb/findvc.c
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -76,7 +78,7 @@ findvc(struct smb_ctx *ctx, struct addrinfo *ai)
bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
- if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
return (errno);
return (0);
@@ -137,7 +139,7 @@ int
smb_ctx_kill(struct smb_ctx *ctx)
{
- if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
return (errno);
return (0);
diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c
index 53f3c515be..8b56fdaf18 100644
--- a/usr/src/lib/libsmbfs/smb/iod_wk.c
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -69,7 +69,7 @@ smb_iod_work(smb_ctx_t *ctx)
DPRINT("server: %s", ctx->ct_srvname);
- /* Calle should have opened these */
+ /* Caller should have opened these */
if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) {
err = EINVAL;
goto out;
@@ -96,7 +96,7 @@ smb_iod_work(smb_ctx_t *ctx)
* Next state is normally RECONNECT.
*/
DPRINT("state: idle");
- if (ioctl(ctx->ct_dev_fd,
+ if (nsmb_ioctl(ctx->ct_dev_fd,
SMBIOC_IOD_IDLE, &vcst) == -1) {
err = errno;
DPRINT("ioc_idle: err %d", err);
@@ -132,7 +132,7 @@ smb_iod_work(smb_ctx_t *ctx)
* then get ready to try again.
* Next state is normally IDLE.
*/
- if (ioctl(ctx->ct_dev_fd,
+ if (nsmb_ioctl(ctx->ct_dev_fd,
SMBIOC_IOD_RCFAIL, &vcst) == -1) {
err = errno;
DPRINT("ioc_rcfail: err %d", err);
@@ -142,7 +142,7 @@ smb_iod_work(smb_ctx_t *ctx)
case SMBIOD_ST_VCACTIVE:
DPRINT("state: active");
- if (ioctl(ctx->ct_dev_fd,
+ if (nsmb_ioctl(ctx->ct_dev_fd,
SMBIOC_IOD_WORK, work) == -1) {
err = errno;
DPRINT("ioc_work: err %d", err);
@@ -176,7 +176,7 @@ out:
ctx->ct_tran_fd = -1;
}
if (ctx->ct_dev_fd != -1) {
- close(ctx->ct_dev_fd);
+ nsmb_close(ctx->ct_dev_fd);
ctx->ct_dev_fd = -1;
}
diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c
index fd9bcc9496..3a89fbd550 100644
--- a/usr/src/lib/libsmbfs/smb/keychain.c
+++ b/usr/src/lib/libsmbfs/smb/keychain.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,7 +128,7 @@ smbfs_keychain_cmn(
}
err = 0;
- if (ioctl(fd, cmd, &pk) < 0) {
+ if (nsmb_ioctl(fd, cmd, &pk) < 0) {
err = errno;
goto out;
}
@@ -142,7 +142,7 @@ smbfs_keychain_cmn(
out:
if (fd != -1)
- close(fd);
+ nsmb_close(fd);
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/lgrep.awk b/usr/src/lib/libsmbfs/smb/lgrep.awk
deleted file mode 100644
index fe6e8fa0b9..0000000000
--- a/usr/src/lib/libsmbfs/smb/lgrep.awk
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# 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 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# Copyright 2012 Milan Jurik. All rights reserved.
-#
-
-# This is a "lint tail" that removes all the
-# uninteresting lines from our lint output.
-# It's nawk because sed doesn't do (a|b).
-# Also comments are easier here.
-
-# There's no lintlib for krb5 yet (CR 6911968)
-/: Warning: -lkrb5 not found/ { next; }
-/: Warning: library -lkrb5 not found/ { next; }
-
-# Kill noise from xti.h with _XOPEN_SOURCE vs not. (CR 6911717)
-/: _xti_.* .E_INCONS_ARG_DECL2./ { next; }
-/: _xti_.* .E_INCONS_ARG_USED2./ { next; }
-/: _xti_.* .E_INCONS_VAL_TYPE_DECL2./ { next; }
-
-# This is third-party code we'd rather not "fix"
-/\/spnego.c.* .E_STMT_NOT_REACHED./ { next; }
-
-# The mb_put/md_get functions are intentionally used both
-# with and without return value checks. Not a concern.
-/: mb_put_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: md_get_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# The rc_get* functions clear the out arg even on failure,
-# so most callers don't need to check the return value.
-/: rc_get[a-z]* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# These have uninteresting return values, usually ignored.
-/: (n|sm)b_ctx_readrcsection .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: nls_str_(lower|upper) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: rc_(close|freesect) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-# Other functions for which we often ignore return values.
-/: [a-z]*close .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: [a-z]*flush .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: [a-z]*printf .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: mem(cpy|move|set) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: mutex_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-/: str[ln]?(cat|cpy) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; }
-
-{ print; }
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index 8f0c3905c6..8d658ab937 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -19,7 +19,7 @@
#
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -36,6 +36,11 @@
# MAPFILE HEADER END
#
+#
+# Note that several things in here are NODIRECT so that the
+# "fksmbcl" development tool can provide its own versions.
+#
+
$mapfile_version 2
SYMBOL_VERSION SUNWprivate {
@@ -60,6 +65,9 @@ SYMBOL_VERSION SUNWprivate {
nls_str_toloc;
nls_str_upper;
+ nsmb_close { FLAGS = NODIRECT };
+ nsmb_ioctl { FLAGS = NODIRECT };
+
smb_close_rcfile;
smb_ctx_alloc;
@@ -72,6 +80,7 @@ SYMBOL_VERSION SUNWprivate {
smb_ctx_gethandle;
smb_ctx_init;
smb_ctx_kill;
+ smb_ctx_newvc { FLAGS = NODIRECT };
smb_ctx_opt;
smb_ctx_parseunc;
smb_ctx_readrc;
@@ -108,10 +117,11 @@ SYMBOL_VERSION SUNWprivate {
smb_getprogname;
smb_iod_connect;
smb_iod_door_path;
- smb_iod_open_door;
- smb_iod_start;
+ smb_iod_open_door { FLAGS = NODIRECT };
+ smb_iod_start { FLAGS = NODIRECT };
smb_iod_work;
smb_lib_init;
+ smb_open_driver { FLAGS = NODIRECT };
smb_open_printer;
smb_open_rcfile;
smb_simplecrypt;
diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c
index c59bef81b4..80fcab7d10 100644
--- a/usr/src/lib/libsmbfs/smb/print.c
+++ b/usr/src/lib/libsmbfs/smb/print.c
@@ -1,5 +1,4 @@
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2000, Boris Popov
* All rights reserved.
*
@@ -33,6 +32,10 @@
* $Id: print.c,v 1.1.1.3 2001/07/06 22:38:43 conrad Exp $
*/
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
@@ -75,7 +78,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
if (new_fd < 0)
return (errno);
from_fd = ctx->ct_dev_fd;
- if (ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_DUP_DEV, &from_fd) == -1) {
err = errno;
goto errout;
}
@@ -88,7 +91,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
ioc.ioc_prmode = mode;
strlcpy(ioc.ioc_title, title, SMBIOC_MAX_NAME);
- if (ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) {
+ if (nsmb_ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) {
err = errno;
goto errout;
}
@@ -96,7 +99,7 @@ smb_open_printer(struct smb_ctx *ctx, const char *title,
return (new_fd);
errout:
- close(new_fd);
+ nsmb_close(new_fd);
errno = err;
return (-1);
}
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c
index 22ca0fc420..56335d0954 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile.c
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c
@@ -31,6 +31,9 @@
*
* $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
*/
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
#include <fcntl.h>
#include <sys/types.h>
@@ -343,11 +346,10 @@ set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
{
int now, new;
#ifdef DEBUG
- char *from;
+ char *from = "SMF";
- if (smb_debug)
- from = (home_nsmbrc) ?
- "user file" : "SMF";
+ if (home_nsmbrc != 0)
+ from = "user file";
#endif
if (strcmp(rkp->rk_name, "minauth") == 0) {
@@ -485,7 +487,7 @@ rc_parse(struct rcfile *rcp)
set_value(rcp, rsp, rkp, buf);
state = stNewLine;
rkp = NULL;
- } /* while */
+ } /* while */
if (c == EOF && state == stGetValue) {
*next = 0;
set_value(rcp, rsp, rkp, buf);
diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c
index c4e929eff9..f6004dfa06 100644
--- a/usr/src/lib/libsmbfs/smb/rq.c
+++ b/usr/src/lib/libsmbfs/smb/rq.c
@@ -1,5 +1,4 @@
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2000, Boris Popov
* All rights reserved.
*
@@ -33,6 +32,10 @@
* $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
*/
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
@@ -266,7 +269,7 @@ smb_rq_simple(struct smb_rq *rqp)
/*
* Call the driver
*/
- if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
+ if (nsmb_ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
return (errno);
/*
@@ -312,7 +315,7 @@ smb_t2_request(int dev_fd, int setupcount, uint16_t *setup,
krq->ioc_rparam = rparam;
krq->ioc_rdata = rdata;
- if (ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) {
+ if (nsmb_ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) {
return (errno);
}
diff --git a/usr/src/lib/smbclnt/Makefile b/usr/src/lib/smbclnt/Makefile
new file mode 100644
index 0000000000..4425611834
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile
@@ -0,0 +1,24 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.lib
+
+SUBDIRS = \
+ libfknsmb \
+ libfksmbfs
+
+libfksmbfs: libfknsmb
+
+include ./Makefile.subdirs
diff --git a/usr/src/lib/smbclnt/Makefile.lib b/usr/src/lib/smbclnt/Makefile.lib
new file mode 100644
index 0000000000..67528308d3
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.lib
@@ -0,0 +1,51 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Common Makefile definitions for smbclnt
+#
+
+# We reset the Makefile.lib macros ROOTLIBDIR to refer to usr/lib/smbfs.
+# For 64 bit, we reset ROOTLIBDIR64 to refer to usr/lib/smbfs/$(MACH64).
+# Install the userland library header files under /usr/include/netsmb
+ROOTSMBHDRDIR= $(ROOTHDRDIR)/netsmb
+ROOTSMBHDRS= $(HDRS:%=$(ROOTSMBHDRDIR)/%)
+
+ROOTLIBDIR = $(ROOT)/usr/lib/smbfs
+ROOTLIBDIR64 = $(ROOT)/usr/lib/smbfs/$(MACH64)
+
+SRCDIR= ../common
+LIBS= $(DYNLIB) $(LINTLIB)
+
+CSTD = $(CSTD_GNU99)
+
+CPPFLAGS += -I$(SRCDIR) -I.
+LDLIBS32 += -L$(ROOT)/usr/lib/smbfs
+LDLIBS64 += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+CLEANFILES += $(OBJECTS:%_ndr.o=%_ndr.c)
diff --git a/usr/src/lib/smbclnt/Makefile.smbclnt b/usr/src/lib/smbclnt/Makefile.smbclnt
new file mode 100644
index 0000000000..4df97c6daa
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.smbclnt
@@ -0,0 +1,66 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Toplevel Makefile included by each subdirectory. Responsible for the 'check'
+# and 'install_h' targets, as well as descending into the architecture directory
+# to actually build the library.
+#
+
+include ../../Makefile.lib
+include ../Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+HDRDIR= common
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: install_h $(SUBDIRS)
+
+check: $(CHECKHDRS)
+
+install_h: $(ROOTSMBHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET)
+
+FRC:
+
+$(ROOTSMBHDRDIR)/%: common/%
+ $(INS.file)
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/Makefile.subdirs b/usr/src/lib/smbclnt/Makefile.subdirs
new file mode 100644
index 0000000000..66720e53ee
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.subdirs
@@ -0,0 +1,43 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+.KEEP_STATE:
+
+all := TARGET = all
+check := TARGET = check
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+install_h := TARGET = install_h
+lint := TARGET = lint
+
+all check clean clobber install install_h lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; VERSION='$(VERSION)' $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/smbclnt/Makefile.targ b/usr/src/lib/smbclnt/Makefile.targ
new file mode 100644
index 0000000000..4c910e3565
--- /dev/null
+++ b/usr/src/lib/smbclnt/Makefile.targ
@@ -0,0 +1,50 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# Common targets for smbclnt Makefiles
+#
+
+pics/%.o: $(SRC)/common/smbclnt/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: # skip
+
+$(ROOTLIBS): $(ROOTLIBDIR)
+
+$(ROOTLIBDIR):
+ $(INS.dir)
+
+$(ROOTLIBS64): $(ROOTLIBDIR64)
+
+$(ROOTLIBDIR64):
+ $(INS.dir)
diff --git a/usr/src/lib/smbclnt/libfknsmb/Makefile b/usr/src/lib/smbclnt/libfknsmb/Makefile
new file mode 100644
index 0000000000..ee4ab9faf7
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.smbclnt
diff --git a/usr/src/lib/smbclnt/libfknsmb/Makefile.com b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
new file mode 100644
index 0000000000..3c79d72974
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
@@ -0,0 +1,106 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+LIBRARY = libfknsmb.a
+VERS = .1
+
+OBJS_LOCAL = \
+ fksmb_sign_pkcs.o \
+ fake_ddi.o \
+ fake_fio.o \
+ fake_kmem.o \
+ fake_ktli.o \
+ fake_pkey.o \
+ fake_policy.o \
+ fake_sdt.o \
+ fake_softc.o \
+ fake_stream.o \
+ fake_strsubr.o
+
+# See also: $SRC/uts/common/Makefile.files
+# NB: Intentionally ommitted, compared w/ the above:
+# smb_dev.o smb_pass.o smb_sign_kcf.o
+#
+OBJS_NSMB = \
+ smb_dev.o \
+ smb_conn.o \
+ smb_iod.o \
+ smb_rq.o \
+ smb_sign.o \
+ smb_smb.o \
+ smb_subrs.o \
+ smb_time.o \
+ smb_tran.o \
+ smb_trantcp.o \
+ smb_usr.o \
+ subr_mchain.o
+
+OBJECTS = \
+ $(OBJS_LOCAL) \
+ $(OBJS_NSMB)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+# Force SOURCEDEBUG
+CSOURCEDEBUGFLAGS = -g
+CCSOURCEDEBUGFLAGS = -g
+STRIP_STABS = :
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also, like Makefile.uts, reset CPPFLAGS
+CPPFLAGS.first += -I../../../libfakekernel/common
+CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common/fs/smbclnt
+INCS += -I$(SRC)/uts/common
+
+CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CERRWARN += -_gcc=-Wno-switch
+
+LDLIBS += $(MACH_LDLIBS)
+LDLIBS += -lfakekernel -lpkcs11 -lnsl -lc
+
+NSMB_DIR=$(SRC)/uts/common/fs/smbclnt/netsmb
+SRCS= $(OBJS_LOCAL:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_NSMB:%.o=$(NSMB_DIR)/%.c)
+
+all:
+
+pics/%.o: $(NSMB_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile b/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile
new file mode 100644
index 0000000000..441f9285b5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/amd64/Makefile
@@ -0,0 +1,21 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c
new file mode 100644
index 0000000000..4dc0faf984
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_ddi.c
@@ -0,0 +1,133 @@
+/*
+ * 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) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * UNIX Device Driver Interface functions
+ * (excerpts)
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/ddi.h>
+#include <sys/mkdev.h>
+#include <sys/debug.h>
+
+#ifndef NODEV32
+#define NODEV32 (dev32_t)(-1)
+#endif /* NODEV32 */
+
+/*
+ * return internal major number corresponding to device
+ * number (new format) argument
+ */
+major_t
+getmajor(dev_t dev)
+{
+#ifdef _LP64
+ return ((major_t)((dev >> NBITSMINOR64) & MAXMAJ64));
+#else
+ return ((major_t)((dev >> NBITSMINOR) & MAXMAJ));
+#endif
+}
+
+/*
+ * return internal minor number corresponding to device
+ * number (new format) argument
+ */
+minor_t
+getminor(dev_t dev)
+{
+#ifdef _LP64
+ return ((minor_t)(dev & MAXMIN64));
+#else
+ return ((minor_t)(dev & MAXMIN));
+#endif
+}
+
+/*
+ * encode external major and minor number arguments into a
+ * new format device number
+ */
+dev_t
+makedevice(major_t maj, minor_t minor)
+{
+#ifdef _LP64
+ return (((dev_t)maj << NBITSMINOR64) | (minor & MAXMIN64));
+#else
+ return (((dev_t)maj << NBITSMINOR) | (minor & MAXMIN));
+#endif
+}
+
+/*
+ * Compress 'long' device number encoding to 32-bit device number
+ * encoding. If it won't fit, we return failure, but set the
+ * device number to 32-bit NODEV for the sake of our callers.
+ */
+int
+cmpldev(dev32_t *dst, dev_t dev)
+{
+#if defined(_LP64)
+ if (dev == NODEV) {
+ *dst = NODEV32;
+ } else {
+ major_t major = dev >> L_BITSMINOR;
+ minor_t minor = dev & L_MAXMIN;
+
+ if (major > L_MAXMAJ32 || minor > L_MAXMIN32) {
+ *dst = NODEV32;
+ return (0);
+ }
+
+ *dst = (dev32_t)((major << L_BITSMINOR32) | minor);
+ }
+#else
+ *dst = (dev32_t)dev;
+#endif
+ return (1);
+}
+
+/*
+ * Expand 32-bit dev_t's to long dev_t's. Expansion always "fits"
+ * into the return type, but we're careful to expand NODEV explicitly.
+ */
+dev_t
+expldev(dev32_t dev32)
+{
+#ifdef _LP64
+ if (dev32 == NODEV32)
+ return (NODEV);
+ return (makedevice((dev32 >> L_BITSMINOR32) & L_MAXMAJ32,
+ dev32 & L_MAXMIN32));
+#else
+ return ((dev_t)dev32);
+#endif
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c
new file mode 100644
index 0000000000..18f8fa2255
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_fio.c
@@ -0,0 +1,105 @@
+/*
+ * 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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * The kTLI "shim" over in ./fake_ktli.c uses getf(), releasef() to
+ * represent an open socket FD in "fake" vnode_t and file_t objects.
+ * This implements minimal getf()/releasef() shims for that purpose.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+
+#define FAKEFDS 256
+
+kmutex_t ftlock;
+file_t *ftab[FAKEFDS];
+
+file_t *
+getf(int fd)
+{
+ file_t *fp;
+ vnode_t *vp;
+
+ if (fd >= FAKEFDS)
+ return (NULL);
+
+ mutex_enter(&ftlock);
+ if ((fp = ftab[fd]) != NULL) {
+ fp->f_count++;
+ mutex_exit(&ftlock);
+ return (fp);
+ }
+
+ fp = kmem_zalloc(sizeof (*fp), KM_SLEEP);
+ vp = kmem_zalloc(sizeof (*vp), KM_SLEEP);
+ vp->v_fd = fd;
+ fp->f_vnode = vp;
+ fp->f_count = 1;
+ ftab[fd] = fp;
+
+ mutex_exit(&ftlock);
+
+ return (fp);
+}
+
+void
+releasef(int fd)
+{
+ file_t *fp;
+ vnode_t *vp;
+
+ mutex_enter(&ftlock);
+ if ((fp = ftab[fd]) == NULL) {
+ mutex_exit(&ftlock);
+ return;
+ }
+ fp->f_count--;
+ if (fp->f_count > 0) {
+ mutex_exit(&ftlock);
+ return;
+ }
+ ftab[fd] = NULL;
+ mutex_exit(&ftlock);
+
+ vp = fp->f_vnode;
+ kmem_free(vp, sizeof (*vp));
+ kmem_free(fp, sizeof (*fp));
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c
new file mode 100644
index 0000000000..21453f410d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_kmem.c
@@ -0,0 +1,45 @@
+/*
+ * 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) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+
+static size_t availmem = (1<<24);
+
+size_t
+kmem_avail(void)
+{
+ return (availmem);
+}
+
+size_t
+kmem_maxavail(void)
+{
+ return (availmem);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c
new file mode 100644
index 0000000000..3011de2e77
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c
@@ -0,0 +1,432 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Kernel TLI-like functions
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/proc.h>
+#include <sys/file.h>
+#include <sys/filio.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+#include <sys/cmn_err.h>
+#include <sys/errno.h>
+#include <sys/kmem.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/tihdr.h>
+#include <sys/timod.h>
+#include <sys/tiuser.h>
+#include <sys/t_kuser.h>
+
+#include <errno.h>
+#include <stropts.h>
+#include <unistd.h>
+
+#include "fake_xti.h"
+
+/* Size of mblks for tli_recv */
+#define FKTLI_RCV_SZ 4096
+
+/*
+ * Translate a TLI error into a system error as best we can.
+ */
+static const int tli_errs[] = {
+ 0, /* no error */
+ EADDRNOTAVAIL, /* TBADADDR */
+ ENOPROTOOPT, /* TBADOPT */
+ EACCES, /* TACCES */
+ EBADF, /* TBADF */
+ EADDRNOTAVAIL, /* TNOADDR */
+ EPROTO, /* TOUTSTATE */
+ EPROTO, /* TBADSEQ */
+ ENOSYS, /* TSYSERR */
+ EPROTO, /* TLOOK */
+ EMSGSIZE, /* TBADDATA */
+ EMSGSIZE, /* TBUFOVFLW */
+ EPROTO, /* TFLOW */
+ EWOULDBLOCK, /* TNODATA */
+ EPROTO, /* TNODIS */
+ EPROTO, /* TNOUDERR */
+ EINVAL, /* TBADFLAG */
+ EPROTO, /* TNOREL */
+ EOPNOTSUPP, /* TNOTSUPPORT */
+ EPROTO, /* TSTATECHNG */
+};
+
+static int
+tlitosyserr(int terr)
+{
+ if (terr < 0 || (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))))
+ return (EPROTO);
+ else
+ return (tli_errs[terr]);
+}
+
+/*
+ * Note: This implementation is specific to the needs of the callers in
+ * uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+ */
+/* ARGSUSED */
+int
+t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
+{
+ boolean_t madefp = B_FALSE;
+ vnode_t *vp;
+ TIUSER *tiu;
+ int fd;
+ int rc;
+
+ *tiptr = NULL;
+
+ if (fp == NULL) {
+ /*
+ * create a socket endpoint
+ * dev is actualy AF
+ */
+ char *devnm;
+ switch (rdev) {
+ case AF_INET:
+ devnm = "/dev/tcp";
+ break;
+ case AF_INET6:
+ devnm = "/dev/tcp6";
+ break;
+ default:
+ cmn_err(CE_NOTE, "t_kopen: bad device");
+ return (EINVAL);
+ }
+
+ fd = t_open(devnm, O_RDWR, NULL);
+ if (fd < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kopen: t_open terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+
+ /*
+ * allocate a file pointer...
+ */
+ fp = getf(fd);
+ madefp = B_TRUE;
+ }
+ vp = fp->f_vnode;
+ fd = vp->v_fd;
+
+ tiu = kmem_zalloc(sizeof (*tiu), KM_SLEEP);
+ rc = t_getinfo(fd, &tiu->tp_info);
+ if (rc < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kopen: t_getinfo terr=%d", rc);
+ kmem_free(tiu, sizeof (*tiu));
+ if (madefp) {
+ releasef(fd);
+ (void) t_close(fd);
+ }
+ return (tlitosyserr(rc));
+ }
+
+ tiu->fp = fp;
+ tiu->flags = madefp ? MADE_FP : 0;
+ *tiptr = tiu;
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+t_kclose(TIUSER *tiptr, int callclosef)
+{
+ file_t *fp;
+
+ fp = (tiptr->flags & MADE_FP) ? tiptr->fp : NULL;
+
+ kmem_free(tiptr, TIUSERSZ);
+
+ if (fp != NULL) {
+ vnode_t *vp = fp->f_vnode;
+ int fd = vp->v_fd;
+ releasef(fd);
+ (void) t_close(fd);
+ }
+
+ return (0);
+}
+
+int
+t_kbind(TIUSER *tiptr, struct t_bind *req, struct t_bind *ret)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_bind(vp->v_fd, req, ret) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kbind: t_bind terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+int
+t_kunbind(TIUSER *tiptr)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_unbind(vp->v_fd) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kunbind: t_unbind terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+int
+t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_connect(vp->v_fd, sndcall, rcvcall) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_kconnect: t_connect terr=%d", rc);
+ if (rc == TLOOK) {
+ /* Probably got a RST. */
+ rc = ECONNREFUSED;
+ } else {
+ rc = tlitosyserr(rc);
+ }
+ return (rc);
+ }
+ return (0);
+}
+
+int
+t_koptmgmt(TIUSER *tiptr, struct t_optmgmt *req, struct t_optmgmt *ret)
+{
+ file_t *fp = tiptr->fp;
+ vnode_t *vp = fp->f_vnode;
+ int rc;
+
+ if (t_optmgmt(vp->v_fd, req, ret) < 0) {
+ rc = t_errno;
+ cmn_err(CE_NOTE, "t_koptmgmt: t_optmgmt terr=%d", rc);
+ return (tlitosyserr(rc));
+ }
+ return (0);
+}
+
+/*
+ * Poll for an input event.
+ *
+ * timo is measured in ticks
+ */
+int
+t_kspoll(TIUSER *tiptr, int timo, int waitflg, int *events)
+{
+ struct pollfd pfds[1];
+ file_t *fp;
+ vnode_t *vp;
+ clock_t timout; /* milliseconds */
+ int n;
+
+ fp = tiptr->fp;
+ vp = fp->f_vnode;
+
+ if (events == NULL || ((waitflg & READWAIT) == 0))
+ return (EINVAL);
+
+ /* Convert from ticks to milliseconds */
+ if (timo < 0)
+ timout = -1;
+ else
+ timout = TICK_TO_MSEC(timo);
+
+ pfds[0].fd = vp->v_fd;
+ pfds[0].events = POLLIN;
+ pfds[0].revents = 0;
+
+ errno = 0;
+ n = poll(pfds, 1, timout);
+ if (n < 0)
+ return (errno);
+ if (n == 0)
+ return (ETIME);
+ *events = pfds[0].revents;
+ return (0);
+}
+
+/*
+ * Send the message, return zero or errno.
+ * Always free's the message, even on error.
+ */
+int
+tli_send(TIUSER *tiptr, mblk_t *bp, int fmode)
+{
+ struct strbuf ctlbuf;
+ struct strbuf databuf;
+ mblk_t *m;
+ int flg, n, rc;
+ vnode_t *vp;
+
+ if (bp == NULL)
+ return (0);
+ vp = tiptr->fp->f_vnode;
+
+ switch (bp->b_datap->db_type) {
+ case M_DATA:
+ for (m = bp; m != NULL; m = m->b_cont) {
+ n = MBLKL(m);
+ flg = (m->b_cont != NULL) ? T_MORE : 0;
+ rc = t_snd(vp->v_fd, (void *) m->b_rptr, n, flg);
+ if (rc != n) {
+ rc = EIO;
+ goto out;
+ }
+ }
+ rc = 0;
+ break;
+
+ /*
+ * May get M_PROTO/T_DISCON_REQ from nb_snddis()
+ */
+ case M_PROTO:
+ case M_PCPROTO:
+ ctlbuf.len = MBLKL(bp);
+ ctlbuf.maxlen = MBLKL(bp);
+ ctlbuf.buf = (char *)bp->b_rptr;
+ if (bp->b_cont == NULL) {
+ bzero(&databuf, sizeof (databuf));
+ } else {
+ m = bp->b_cont;
+ databuf.len = MBLKL(m);
+ databuf.maxlen = MBLKL(m);
+ databuf.buf = (char *)m->b_rptr;
+ }
+ if (putmsg(vp->v_fd, &ctlbuf, &databuf, 0) < 0) {
+ rc = errno;
+ cmn_err(CE_NOTE, "tli_send: putmsg err=%d", rc);
+ } else {
+ rc = 0;
+ }
+ break;
+
+ default:
+ rc = EIO;
+ break;
+ }
+
+out:
+ freemsg(bp);
+ return (rc);
+}
+
+int
+tli_recv(TIUSER *tiptr, mblk_t **bp, int fmode)
+{
+ mblk_t *mtop = NULL;
+ mblk_t *m;
+ vnode_t *vp;
+ int error;
+ int flags;
+ int nread;
+ int n;
+
+ vp = tiptr->fp->f_vnode;
+
+
+
+ /*
+ * Get an mblk for the data
+ */
+ nread = FKTLI_RCV_SZ;
+ m = allocb_wait(nread, 0, 0, &error);
+ ASSERT(m != NULL);
+
+ if (mtop == NULL)
+ mtop = m;
+
+again:
+ flags = 0;
+ n = t_rcv(vp->v_fd, (void *) m->b_rptr, nread, &flags);
+ if (n < 0) {
+ n = t_errno;
+ cmn_err(CE_NOTE, "tli_recv: t_rcv terr=%d", n);
+ error = tlitosyserr(n);
+ goto errout;
+ }
+ if (n == 0) {
+ error = ENOTCONN;
+ goto errout;
+ }
+ ASSERT(n > 0 && n <= nread);
+ m->b_wptr = m->b_rptr + n;
+
+ if (flags & T_MORE) {
+ mblk_t *mtail = m;
+ m = allocb_wait(nread, 0, 0, &error);
+ ASSERT(m != NULL);
+ mtail->b_cont = m;
+ goto again;
+ }
+
+ *bp = mtop;
+ return (0);
+
+errout:
+ if (m == mtop) {
+ freemsg(mtop);
+ return (error);
+ }
+
+ /* got some data, so return it. */
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c
new file mode 100644
index 0000000000..b7944f8dca
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_pkey.c
@@ -0,0 +1,48 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * pkey stubs
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/errno.h>
+
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_pass.h>
+
+void
+smb_pkey_init()
+{
+}
+
+void
+smb_pkey_fini()
+{
+}
+
+int
+smb_pkey_idle()
+{
+ return (0);
+}
+
+/* ARGSUSED */
+int
+smb_pkey_ioctl(int cmd, intptr_t arg, int flags, cred_t *cr)
+{
+ return (ENOTTY);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c
new file mode 100644
index 0000000000..4531e86bae
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_policy.c
@@ -0,0 +1,90 @@
+/*
+ * 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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/errno.h>
+#include <sys/policy.h>
+
+/* ARGSUSED */
+int
+secpolicy_fs_allowed_mount(const char *fsname)
+{
+ return (0);
+}
+
+int
+secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner,
+ mode_t curmode, mode_t wantmode)
+{
+ mode_t mode;
+
+ mode = ~curmode & wantmode;
+
+ if (mode == 0)
+ return (0);
+ return (EACCES);
+}
+
+int
+secpolicy_vnode_owner(const cred_t *cr, uid_t owner)
+{
+ /* cr->cr_uid */
+ if (owner == crgetruid(cr))
+ return (0);
+
+ return (EPERM);
+}
+
+int
+secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
+ const struct vattr *ovap, int flags,
+ int unlocked_access(void *, int, cred_t *),
+ void *node)
+{
+ int mask = vap->va_mask;
+
+ if (mask & AT_SIZE) {
+ if (vp->v_type == VDIR)
+ return (EISDIR);
+ }
+ if (mask & AT_MODE)
+ return (EACCES);
+ if (mask & (AT_UID|AT_GID))
+ return (EACCES);
+
+ return (0);
+}
+
+int
+secpolicy_vnode_setdac(const cred_t *cred, uid_t owner)
+{
+ if (owner == crgetuid(cred))
+ return (0);
+
+ return (EPERM);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c
new file mode 100644
index 0000000000..bc88864843
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_sdt.c
@@ -0,0 +1,50 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/cmn_err.h>
+#include <sys/sdt.h>
+
+/*
+ * See: DTRACE_PROBE... in sys/sdt.h
+ */
+
+int fknsmb_dtrace_log = 0;
+
+void
+smb_dtrace1(const char *n, long v1)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace1: %s,"
+ " 0x%lx\n", n, v1);
+ }
+}
+
+void
+smb_dtrace2(const char *n, long v1, long v2)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace2: %s,"
+ " 0x%lx, 0x%lx\n", n, v1, v2);
+ }
+}
+
+void
+smb_dtrace3(const char *n, long v1, long v2, long v3)
+{
+ if (fknsmb_dtrace_log) {
+ cmn_err(CE_CONT, "dtrace3: %s,"
+ " 0x%lx, 0x%lx, 0x%lx\n", n, v1, v2, v3);
+ }
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c
new file mode 100644
index 0000000000..2d990ed3f8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_softc.c
@@ -0,0 +1,263 @@
+
+/*
+ * 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/debug.h>
+#include <sys/sunddi.h>
+
+#define MIN_N_ITEMS 8
+
+typedef struct i_ddi_soft_state {
+ void **array; /* the array of pointers */
+ kmutex_t lock; /* serialize access to this struct */
+ size_t size; /* how many bytes per state struct */
+ size_t n_items; /* how many structs herein */
+ void *next; /* unused */
+} i_ddi_soft_state;
+
+
+void *
+ddi_get_soft_state(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void *ret = NULL;
+
+ ASSERT((ss != NULL) && (item >= 0));
+
+ mutex_enter(&ss->lock);
+
+ if (item < ss->n_items && ss->array != NULL)
+ ret = ss->array[item];
+
+ mutex_exit(&ss->lock);
+
+ return (ret);
+}
+
+
+int
+ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
+{
+ i_ddi_soft_state *ss;
+
+ if (state_p == NULL || size == 0)
+ return (EINVAL);
+
+ ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
+ mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
+ ss->size = size;
+
+ if (n_items < MIN_N_ITEMS)
+ ss->n_items = MIN_N_ITEMS;
+ else {
+ ss->n_items = n_items;
+ }
+
+ ASSERT(ss->n_items >= n_items);
+
+ ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
+
+ *state_p = ss;
+ return (0);
+}
+
+/*
+ * Allocate a state structure of size 'size' to be associated
+ * with item 'item'.
+ *
+ * In this implementation, the array is extended to
+ * allow the requested offset, if needed.
+ */
+int
+ddi_soft_state_zalloc(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void **array;
+ void *new_element;
+
+ if ((state == NULL) || (item < 0))
+ return (DDI_FAILURE);
+
+ mutex_enter(&ss->lock);
+ if (ss->size == 0) {
+ mutex_exit(&ss->lock);
+ cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle: %s",
+ "fake");
+ return (DDI_FAILURE);
+ }
+
+ array = ss->array; /* NULL if ss->n_items == 0 */
+ ASSERT(ss->n_items != 0 && array != NULL);
+
+ /*
+ * refuse to tread on an existing element
+ */
+ if (item < ss->n_items && array[item] != NULL) {
+ mutex_exit(&ss->lock);
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Allocate a new element to plug in
+ */
+ new_element = kmem_zalloc(ss->size, KM_SLEEP);
+
+ /*
+ * Check if the array is big enough, if not, grow it.
+ */
+ if (item >= ss->n_items) {
+ void **new_array;
+ size_t new_n_items;
+
+ /*
+ * Allocate a new array of the right length, copy
+ * all the old pointers to the new array, then
+ * if it exists at all, put the old array on the
+ * dirty list.
+ *
+ * Note that we can't kmem_free() the old array.
+ *
+ * Why -- well the 'get' operation is 'mutex-free', so we
+ * can't easily catch a suspended thread that is just about
+ * to dereference the array we just grew out of. So we
+ * cons up a header and put it on a list of 'dirty'
+ * pointer arrays. (Dirty in the sense that there may
+ * be suspended threads somewhere that are in the middle
+ * of referencing them). Fortunately, we -can- garbage
+ * collect it all at ddi_soft_state_fini time.
+ */
+ new_n_items = ss->n_items;
+ while (new_n_items < (1 + item))
+ new_n_items <<= 1; /* double array size .. */
+
+ ASSERT(new_n_items >= (1 + item)); /* sanity check! */
+
+ new_array = kmem_zalloc(new_n_items * sizeof (void *),
+ KM_SLEEP);
+ /*
+ * Copy the pointers into the new array
+ */
+ bcopy(array, new_array, ss->n_items * sizeof (void *));
+
+ /*
+ * Free the old array now. Note that
+ * ddi_get_soft_state takes the mutex.
+ */
+ kmem_free(ss->array, ss->n_items * sizeof (void *));
+
+ ss->array = (array = new_array);
+ ss->n_items = new_n_items;
+ }
+
+ ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
+
+ array[item] = new_element;
+
+ mutex_exit(&ss->lock);
+ return (DDI_SUCCESS);
+}
+
+void
+ddi_soft_state_free(void *state, int item)
+{
+ i_ddi_soft_state *ss = (i_ddi_soft_state *)state;
+ void **array;
+ void *element;
+ static char msg[] = "ddi_soft_state_free:";
+
+ if (ss == NULL) {
+ cmn_err(CE_WARN, "%s null handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ element = NULL;
+
+ mutex_enter(&ss->lock);
+
+ if ((array = ss->array) == NULL || ss->size == 0) {
+ cmn_err(CE_WARN, "%s bad handle: %s",
+ msg, "fake");
+ } else if (item < 0 || item >= ss->n_items) {
+ cmn_err(CE_WARN, "%s item %d not in range [0..%lu]: %s",
+ msg, item, (ulong_t)ss->n_items - 1, "fake");
+ } else if (array[item] != NULL) {
+ element = array[item];
+ array[item] = NULL;
+ }
+
+ mutex_exit(&ss->lock);
+
+ if (element)
+ kmem_free(element, ss->size);
+}
+
+/*
+ * Free the entire set of pointers, and any
+ * soft state structures contained therein.
+ *
+ * Note that we don't grab the ss->lock mutex, even though
+ * we're inspecting the various fields of the data structure.
+ *
+ * There is an implicit assumption that this routine will
+ * never run concurrently with any of the above on this
+ * particular state structure i.e. by the time the driver
+ * calls this routine, there should be no other threads
+ * running in the driver.
+ */
+void
+ddi_soft_state_fini(void **state_p)
+{
+ i_ddi_soft_state *ss;
+ int item;
+ static char msg[] = "ddi_soft_state_fini:";
+
+ if (state_p == NULL ||
+ (ss = (i_ddi_soft_state *)(*state_p)) == NULL) {
+ cmn_err(CE_WARN, "%s null handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ if (ss->size == 0) {
+ cmn_err(CE_WARN, "%s bad handle: %s",
+ msg, "fake");
+ return;
+ }
+
+ if (ss->n_items > 0) {
+ for (item = 0; item < ss->n_items; item++)
+ ddi_soft_state_free(ss, item);
+ kmem_free(ss->array, ss->n_items * sizeof (void *));
+ }
+
+ mutex_destroy(&ss->lock);
+ kmem_free(ss, sizeof (*ss));
+
+ *state_p = NULL;
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c
new file mode 100644
index 0000000000..d89a732d69
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_stream.c
@@ -0,0 +1,1377 @@
+/*
+ * 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) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/thread.h>
+#include <sys/sysmacros.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/conf.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/atomic.h>
+#include <sys/errno.h>
+#include <sys/vtrace.h>
+#include <sys/ftrace.h>
+#include <sys/ontrap.h>
+#include <sys/sdt.h>
+#include <sys/strft.h>
+
+/*
+ * This file contains selected functions from io/stream.c
+ * needed by this library, mostly unmodified.
+ */
+
+/*
+ * STREAMS message allocator: principles of operation
+ * (See usr/src/uts/common/io/stream.c)
+ */
+#define DBLK_MAX_CACHE 73728
+#define DBLK_CACHE_ALIGN 64
+#define DBLK_MIN_SIZE 8
+#define DBLK_SIZE_SHIFT 3
+
+#ifdef _BIG_ENDIAN
+#define DBLK_RTFU_SHIFT(field) \
+ (8 * (&((dblk_t *)0)->db_struioflag - &((dblk_t *)0)->field))
+#else
+#define DBLK_RTFU_SHIFT(field) \
+ (8 * (&((dblk_t *)0)->field - &((dblk_t *)0)->db_ref))
+#endif
+
+#define DBLK_RTFU(ref, type, flags, uioflag) \
+ (((ref) << DBLK_RTFU_SHIFT(db_ref)) | \
+ ((type) << DBLK_RTFU_SHIFT(db_type)) | \
+ (((flags) | (ref - 1)) << DBLK_RTFU_SHIFT(db_flags)) | \
+ ((uioflag) << DBLK_RTFU_SHIFT(db_struioflag)))
+#define DBLK_RTFU_REF_MASK (DBLK_REFMAX << DBLK_RTFU_SHIFT(db_ref))
+#define DBLK_RTFU_WORD(dbp) (*((uint32_t *)&(dbp)->db_ref))
+#define MBLK_BAND_FLAG_WORD(mp) (*((uint32_t *)&(mp)->b_band))
+
+static size_t dblk_sizes[] = {
+#ifdef _LP64
+ 16, 80, 144, 208, 272, 336, 528, 1040, 1488, 1936, 2576, 3856,
+ 8192, 12048, 16384, 20240, 24576, 28432, 32768, 36624,
+ 40960, 44816, 49152, 53008, 57344, 61200, 65536, 69392,
+#else
+ 64, 128, 320, 576, 1088, 1536, 1984, 2624, 3904,
+ 8192, 12096, 16384, 20288, 24576, 28480, 32768, 36672,
+ 40960, 44864, 49152, 53056, 57344, 61248, 65536, 69440,
+#endif
+ DBLK_MAX_CACHE, 0
+};
+
+static struct kmem_cache *dblk_cache[DBLK_MAX_CACHE / DBLK_MIN_SIZE];
+static struct kmem_cache *mblk_cache;
+static struct kmem_cache *dblk_esb_cache;
+
+static void dblk_lastfree(mblk_t *mp, dblk_t *dbp);
+static mblk_t *allocb_oversize(size_t size, int flags);
+static int allocb_tryhard_fails;
+static void frnop_func(void *arg);
+frtn_t frnop = { frnop_func };
+static void bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp);
+
+/*
+ * Patchable mblk/dblk kmem_cache flags.
+ */
+int dblk_kmem_flags = 0;
+int mblk_kmem_flags = 0;
+
+static int
+dblk_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+ ssize_t msg_size = (ssize_t)cdrarg;
+ size_t index;
+
+ ASSERT(msg_size != 0);
+
+ index = (msg_size - 1) >> DBLK_SIZE_SHIFT;
+
+ ASSERT(index < (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT));
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+ if ((msg_size & PAGEOFFSET) == 0) {
+ dbp->db_base = kmem_alloc(msg_size, kmflags);
+ if (dbp->db_base == NULL) {
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+ return (-1);
+ }
+ } else {
+ dbp->db_base = (unsigned char *)&dbp[1];
+ }
+
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = dblk_cache[index];
+ dbp->db_lim = dbp->db_base + msg_size;
+ dbp->db_free = dbp->db_lastfree = dblk_lastfree;
+ dbp->db_frtnp = NULL;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dblk_esb_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = dblk_esb_cache;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+static int
+bcache_dblk_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ dblk_t *dbp = buf;
+ bcache_t *bcp = cdrarg;
+
+ if ((dbp->db_mblk = kmem_cache_alloc(mblk_cache, kmflags)) == NULL)
+ return (-1);
+
+ dbp->db_base = kmem_cache_alloc(bcp->buffer_cache, kmflags);
+ if (dbp->db_base == NULL) {
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+ return (-1);
+ }
+
+ dbp->db_mblk->b_datap = dbp;
+ dbp->db_cache = (void *)bcp;
+ dbp->db_lim = dbp->db_base + bcp->size;
+ dbp->db_free = dbp->db_lastfree = bcache_dblk_lastfree;
+ dbp->db_frtnp = NULL;
+ dbp->db_fthdr = NULL;
+ dbp->db_credp = NULL;
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+ return (0);
+}
+
+/*ARGSUSED*/
+static void
+dblk_destructor(void *buf, void *cdrarg)
+{
+ dblk_t *dbp = buf;
+ ssize_t msg_size = (ssize_t)cdrarg;
+
+ ASSERT(dbp->db_mblk->b_datap == dbp);
+ ASSERT(msg_size != 0);
+ ASSERT(dbp->db_struioflag == 0);
+ ASSERT(dbp->db_struioun.cksum.flags == 0);
+
+ if ((msg_size & PAGEOFFSET) == 0) {
+ kmem_free(dbp->db_base, msg_size);
+ }
+
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+}
+
+static void
+bcache_dblk_destructor(void *buf, void *cdrarg)
+{
+ dblk_t *dbp = buf;
+ bcache_t *bcp = cdrarg;
+
+ kmem_cache_free(bcp->buffer_cache, dbp->db_base);
+
+ ASSERT(dbp->db_mblk->b_datap == dbp);
+ ASSERT(dbp->db_struioflag == 0);
+ ASSERT(dbp->db_struioun.cksum.flags == 0);
+
+ kmem_cache_free(mblk_cache, dbp->db_mblk);
+}
+
+/* Needed in the ASSERT below */
+#ifdef DEBUG
+#ifdef _KERNEL
+#define KMEM_SLAB_T_SZ sizeof (kmem_slab_t)
+#else /* _KERNEL */
+#define KMEM_SLAB_T_SZ 64 /* fakekernel */
+#endif /* _KERNEL */
+#endif /* DEBUG */
+
+void
+streams_msg_init(void)
+{
+ char name[40];
+ size_t size;
+ size_t lastsize = DBLK_MIN_SIZE;
+ size_t *sizep;
+ struct kmem_cache *cp;
+ size_t tot_size;
+ int offset;
+
+ mblk_cache = kmem_cache_create("streams_mblk", sizeof (mblk_t), 32,
+ NULL, NULL, NULL, NULL, NULL, mblk_kmem_flags);
+
+ for (sizep = dblk_sizes; (size = *sizep) != 0; sizep++) {
+
+ if ((offset = (size & PAGEOFFSET)) != 0) {
+ /*
+ * We are in the middle of a page, dblk should
+ * be allocated on the same page
+ */
+ tot_size = size + sizeof (dblk_t);
+ ASSERT((offset + sizeof (dblk_t) + KMEM_SLAB_T_SZ)
+ < PAGESIZE);
+ ASSERT((tot_size & (DBLK_CACHE_ALIGN - 1)) == 0);
+
+ } else {
+
+ /*
+ * buf size is multiple of page size, dblk and
+ * buffer are allocated separately.
+ */
+
+ ASSERT((size & (DBLK_CACHE_ALIGN - 1)) == 0);
+ tot_size = sizeof (dblk_t);
+ }
+
+ (void) sprintf(name, "streams_dblk_%ld", (long)size);
+ cp = kmem_cache_create(name, tot_size, DBLK_CACHE_ALIGN,
+ dblk_constructor, dblk_destructor, NULL, (void *)(size),
+ NULL, dblk_kmem_flags);
+
+ while (lastsize <= size) {
+ dblk_cache[(lastsize - 1) >> DBLK_SIZE_SHIFT] = cp;
+ lastsize += DBLK_MIN_SIZE;
+ }
+ }
+
+ dblk_esb_cache = kmem_cache_create("streams_dblk_esb", sizeof (dblk_t),
+ DBLK_CACHE_ALIGN, dblk_esb_constructor, dblk_destructor, NULL,
+ (void *)sizeof (dblk_t), NULL, dblk_kmem_flags);
+
+ /* fthdr_cache, ftblk_cache, mmd_init... */
+}
+
+/*ARGSUSED*/
+mblk_t *
+allocb(size_t size, uint_t pri)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+ size_t index;
+
+ index = (size - 1) >> DBLK_SIZE_SHIFT;
+
+ if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
+ if (size != 0) {
+ mp = allocb_oversize(size, KM_NOSLEEP);
+ goto out;
+ }
+ index = 0;
+ }
+
+ if ((dbp = kmem_cache_alloc(dblk_cache[index], KM_NOSLEEP)) == NULL) {
+ mp = NULL;
+ goto out;
+ }
+
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&dbp->db_fthdr, FTEV_ALLOCB, size);
+out:
+ FTRACE_1("allocb(): mp=0x%p", (uintptr_t)mp);
+
+ return (mp);
+}
+
+/*
+ * Allocate an mblk taking db_credp and db_cpid from the template.
+ * Allow the cred to be NULL.
+ */
+mblk_t *
+allocb_tmpl(size_t size, const mblk_t *tmpl)
+{
+ mblk_t *mp = allocb(size, 0);
+
+ if (mp != NULL) {
+ dblk_t *src = tmpl->b_datap;
+ dblk_t *dst = mp->b_datap;
+ cred_t *cr;
+ pid_t cpid;
+
+ cr = msg_getcred(tmpl, &cpid);
+ if (cr != NULL)
+ crhold(dst->db_credp = cr);
+ dst->db_cpid = cpid;
+ dst->db_type = src->db_type;
+ }
+ return (mp);
+}
+
+mblk_t *
+allocb_cred(size_t size, cred_t *cr, pid_t cpid)
+{
+ mblk_t *mp = allocb(size, 0);
+
+ ASSERT(cr != NULL);
+ if (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ crhold(dbp->db_credp = cr);
+ dbp->db_cpid = cpid;
+ }
+ return (mp);
+}
+
+mblk_t *
+allocb_cred_wait(size_t size, uint_t flags, int *error, cred_t *cr, pid_t cpid)
+{
+ mblk_t *mp = allocb_wait(size, 0, flags, error);
+
+ ASSERT(cr != NULL);
+ if (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ crhold(dbp->db_credp = cr);
+ dbp->db_cpid = cpid;
+ }
+
+ return (mp);
+}
+
+/*
+ * Extract the db_cred (and optionally db_cpid) from a message.
+ * We find the first mblk which has a non-NULL db_cred and use that.
+ * If none found we return NULL.
+ * Does NOT get a hold on the cred.
+ */
+cred_t *
+msg_getcred(const mblk_t *mp, pid_t *cpidp)
+{
+ cred_t *cr = NULL;
+
+ while (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ cr = dbp->db_credp;
+ if (cr == NULL) {
+ mp = mp->b_cont;
+ continue;
+ }
+ if (cpidp != NULL)
+ *cpidp = dbp->db_cpid;
+
+ /* DEBUG check for only one db_credp */
+ return (cr);
+ }
+ if (cpidp != NULL)
+ *cpidp = NOPID;
+ return (NULL);
+}
+
+/*
+ * Variant of msg_getcred which, when a cred is found
+ * 1. Returns with a hold on the cred
+ * 2. Clears the first cred in the mblk.
+ * This is more efficient to use than a msg_getcred() + crhold() when
+ * the message is freed after the cred has been extracted.
+ *
+ * The caller is responsible for ensuring that there is no other reference
+ * on the message since db_credp can not be cleared when there are other
+ * references.
+ */
+cred_t *
+msg_extractcred(mblk_t *mp, pid_t *cpidp)
+{
+ cred_t *cr = NULL;
+
+ while (mp != NULL) {
+ dblk_t *dbp = mp->b_datap;
+
+ cr = dbp->db_credp;
+ if (cr == NULL) {
+ mp = mp->b_cont;
+ continue;
+ }
+ ASSERT(dbp->db_ref == 1);
+ dbp->db_credp = NULL;
+ if (cpidp != NULL)
+ *cpidp = dbp->db_cpid;
+
+ /* DEBUG check for only one db_credp */
+ return (cr);
+ }
+ return (NULL);
+}
+
+/* _KERNEL msg_getlabel() */
+
+void
+freeb(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+
+ ASSERT(dbp->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+ FTRACE_1("freeb(): mp=0x%lx", (uintptr_t)mp);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
+
+ dbp->db_free(mp, dbp);
+}
+
+void
+freemsg(mblk_t *mp)
+{
+ FTRACE_1("freemsg(): mp=0x%lx", (uintptr_t)mp);
+ while (mp) {
+ dblk_t *dbp = mp->b_datap;
+ mblk_t *mp_cont = mp->b_cont;
+
+ ASSERT(dbp->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_FREEB, dbp->db_ref);
+
+ dbp->db_free(mp, dbp);
+ mp = mp_cont;
+ }
+}
+
+/*
+ * Reallocate a block for another use. Try hard to use the old block.
+ * If the old data is wanted (copy), leave b_wptr at the end of the data,
+ * otherwise return b_wptr = b_rptr.
+ *
+ * This routine is private and unstable.
+ */
+mblk_t *
+reallocb(mblk_t *mp, size_t size, uint_t copy)
+{
+ mblk_t *mp1;
+ unsigned char *old_rptr;
+ ptrdiff_t cur_size;
+
+ if (mp == NULL)
+ return (allocb(size, BPRI_HI));
+
+ cur_size = mp->b_wptr - mp->b_rptr;
+ old_rptr = mp->b_rptr;
+
+ ASSERT(mp->b_datap->db_ref != 0);
+
+ if (mp->b_datap->db_ref == 1 && MBLKSIZE(mp) >= size) {
+ /*
+ * If the data is wanted and it will fit where it is, no
+ * work is required.
+ */
+ if (copy && mp->b_datap->db_lim - mp->b_rptr >= size)
+ return (mp);
+
+ mp->b_wptr = mp->b_rptr = mp->b_datap->db_base;
+ mp1 = mp;
+ } else if ((mp1 = allocb_tmpl(size, mp)) != NULL) {
+ /* XXX other mp state could be copied too, db_flags ... ? */
+ mp1->b_cont = mp->b_cont;
+ } else {
+ return (NULL);
+ }
+
+ if (copy) {
+ bcopy(old_rptr, mp1->b_rptr, cur_size);
+ mp1->b_wptr = mp1->b_rptr + cur_size;
+ }
+
+ if (mp != mp1)
+ freeb(mp);
+
+ return (mp1);
+}
+
+static void
+dblk_lastfree(mblk_t *mp, dblk_t *dbp)
+{
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+
+ /* Reset the struioflag and the checksum flag fields */
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ /* and the COOKED and/or UIOA flag(s) */
+ dbp->db_flags &= ~(DBLK_COOKED | DBLK_UIOA);
+
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+static void
+dblk_decref(mblk_t *mp, dblk_t *dbp)
+{
+ if (dbp->db_ref != 1) {
+ uint32_t rtfu = atomic_add_32_nv(&DBLK_RTFU_WORD(dbp),
+ -(1 << DBLK_RTFU_SHIFT(db_ref)));
+ /*
+ * atomic_add_32_nv() just decremented db_ref, so we no longer
+ * have a reference to the dblk, which means another thread
+ * could free it. Therefore we cannot examine the dblk to
+ * determine whether ours was the last reference. Instead,
+ * we extract the new and minimum reference counts from rtfu.
+ * Note that all we're really saying is "if (ref != refmin)".
+ */
+ if (((rtfu >> DBLK_RTFU_SHIFT(db_ref)) & DBLK_REFMAX) !=
+ ((rtfu >> DBLK_RTFU_SHIFT(db_flags)) & DBLK_REFMIN)) {
+ kmem_cache_free(mblk_cache, mp);
+ return;
+ }
+ }
+ dbp->db_mblk = mp;
+ dbp->db_free = dbp->db_lastfree;
+ dbp->db_lastfree(mp, dbp);
+}
+
+mblk_t *
+dupb(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+ mblk_t *new_mp;
+ uint32_t oldrtfu, newrtfu;
+
+ if ((new_mp = kmem_cache_alloc(mblk_cache, KM_NOSLEEP)) == NULL)
+ goto out;
+
+ new_mp->b_next = new_mp->b_prev = new_mp->b_cont = NULL;
+ new_mp->b_rptr = mp->b_rptr;
+ new_mp->b_wptr = mp->b_wptr;
+ new_mp->b_datap = dbp;
+ new_mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(new_mp) = MBLK_BAND_FLAG_WORD(mp);
+
+ STR_FTEVENT_MBLK(mp, caller(), FTEV_DUPB, dbp->db_ref);
+
+ dbp->db_free = dblk_decref;
+ do {
+ ASSERT(dbp->db_ref > 0);
+ oldrtfu = DBLK_RTFU_WORD(dbp);
+ newrtfu = oldrtfu + (1 << DBLK_RTFU_SHIFT(db_ref));
+ /*
+ * If db_ref is maxed out we can't dup this message anymore.
+ */
+ if ((oldrtfu & DBLK_RTFU_REF_MASK) == DBLK_RTFU_REF_MASK) {
+ kmem_cache_free(mblk_cache, new_mp);
+ new_mp = NULL;
+ goto out;
+ }
+ } while (atomic_cas_32(&DBLK_RTFU_WORD(dbp), oldrtfu, newrtfu) !=
+ oldrtfu);
+
+out:
+ FTRACE_1("dupb(): new_mp=0x%lx", (uintptr_t)new_mp);
+ return (new_mp);
+}
+
+/*ARGSUSED*/
+static void
+frnop_func(void *arg)
+{
+}
+
+/*
+ * Generic esballoc used to implement the four flavors: [d]esballoc[a].
+ * and allocb_oversize
+ */
+static mblk_t *
+gesballoc(unsigned char *base, size_t size, uint32_t db_rtfu, frtn_t *frp,
+ void (*lastfree)(mblk_t *, dblk_t *), int kmflags)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+
+ ASSERT(base != NULL && frp != NULL);
+
+ if ((dbp = kmem_cache_alloc(dblk_esb_cache, kmflags)) == NULL) {
+ mp = NULL;
+ goto out;
+ }
+
+ mp = dbp->db_mblk;
+ dbp->db_base = base;
+ dbp->db_lim = base + size;
+ dbp->db_free = dbp->db_lastfree = lastfree;
+ dbp->db_frtnp = frp;
+ DBLK_RTFU_WORD(dbp) = db_rtfu;
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+
+out:
+ FTRACE_1("gesballoc(): mp=0x%lx", (uintptr_t)mp);
+ return (mp);
+}
+
+static void
+bcache_dblk_lastfree(mblk_t *mp, dblk_t *dbp)
+{
+ bcache_t *bcp = dbp->db_cache;
+
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ mutex_enter(&bcp->mutex);
+ kmem_cache_free(bcp->dblk_cache, dbp);
+ bcp->alloc--;
+
+ if (bcp->alloc == 0 && bcp->destroy != 0) {
+ kmem_cache_destroy(bcp->dblk_cache);
+ kmem_cache_destroy(bcp->buffer_cache);
+ mutex_exit(&bcp->mutex);
+ mutex_destroy(&bcp->mutex);
+ kmem_free(bcp, sizeof (bcache_t));
+ } else {
+ mutex_exit(&bcp->mutex);
+ }
+}
+
+bcache_t *
+bcache_create(char *name, size_t size, uint_t align)
+{
+ bcache_t *bcp;
+ char buffer[255];
+
+ ASSERT((align & (align - 1)) == 0);
+
+ if ((bcp = kmem_alloc(sizeof (bcache_t), KM_NOSLEEP)) == NULL)
+ return (NULL);
+
+ bcp->size = size;
+ bcp->align = align;
+ bcp->alloc = 0;
+ bcp->destroy = 0;
+
+ mutex_init(&bcp->mutex, NULL, MUTEX_DRIVER, NULL);
+
+ (void) sprintf(buffer, "%s_buffer_cache", name);
+ bcp->buffer_cache = kmem_cache_create(buffer, size, align, NULL, NULL,
+ NULL, NULL, NULL, 0);
+ (void) sprintf(buffer, "%s_dblk_cache", name);
+ bcp->dblk_cache = kmem_cache_create(buffer, sizeof (dblk_t),
+ DBLK_CACHE_ALIGN, bcache_dblk_constructor, bcache_dblk_destructor,
+ NULL, (void *)bcp, NULL, 0);
+
+ return (bcp);
+}
+
+void
+bcache_destroy(bcache_t *bcp)
+{
+ ASSERT(bcp != NULL);
+
+ mutex_enter(&bcp->mutex);
+ if (bcp->alloc == 0) {
+ kmem_cache_destroy(bcp->dblk_cache);
+ kmem_cache_destroy(bcp->buffer_cache);
+ mutex_exit(&bcp->mutex);
+ mutex_destroy(&bcp->mutex);
+ kmem_free(bcp, sizeof (bcache_t));
+ } else {
+ bcp->destroy++;
+ mutex_exit(&bcp->mutex);
+ }
+}
+
+/*ARGSUSED*/
+mblk_t *
+bcache_allocb(bcache_t *bcp, uint_t pri)
+{
+ dblk_t *dbp;
+ mblk_t *mp = NULL;
+
+ ASSERT(bcp != NULL);
+
+ mutex_enter(&bcp->mutex);
+ if (bcp->destroy != 0) {
+ mutex_exit(&bcp->mutex);
+ goto out;
+ }
+
+ if ((dbp = kmem_cache_alloc(bcp->dblk_cache, KM_NOSLEEP)) == NULL) {
+ mutex_exit(&bcp->mutex);
+ goto out;
+ }
+ bcp->alloc++;
+ mutex_exit(&bcp->mutex);
+
+ ASSERT(((uintptr_t)(dbp->db_base) & (bcp->align - 1)) == 0);
+
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&dbp->db_fthdr, FTEV_BCALLOCB, bcp->size);
+out:
+ FTRACE_1("bcache_allocb(): mp=0x%p", (uintptr_t)mp);
+
+ return (mp);
+}
+
+static void
+dblk_lastfree_oversize(mblk_t *mp, dblk_t *dbp)
+{
+ ASSERT(dbp->db_mblk == mp);
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ /* set credp and projid to be 'unspecified' before returning to cache */
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ kmem_free(dbp->db_base, dbp->db_lim - dbp->db_base);
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+static mblk_t *
+allocb_oversize(size_t size, int kmflags)
+{
+ mblk_t *mp;
+ void *buf;
+
+ size = P2ROUNDUP(size, DBLK_CACHE_ALIGN);
+ if ((buf = kmem_alloc(size, kmflags)) == NULL)
+ return (NULL);
+ if ((mp = gesballoc(buf, size, DBLK_RTFU(1, M_DATA, 0, 0),
+ &frnop, dblk_lastfree_oversize, kmflags)) == NULL)
+ kmem_free(buf, size);
+
+ if (mp != NULL)
+ STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBIG, size);
+
+ return (mp);
+}
+
+mblk_t *
+allocb_tryhard(size_t target_size)
+{
+ size_t size;
+ mblk_t *bp;
+
+ for (size = target_size; size < target_size + 512;
+ size += DBLK_CACHE_ALIGN)
+ if ((bp = allocb(size, BPRI_HI)) != NULL)
+ return (bp);
+ allocb_tryhard_fails++;
+ return (NULL);
+}
+
+/*
+ * This routine is consolidation private for STREAMS internal use
+ * This routine may only be called from sync routines (i.e., not
+ * from put or service procedures). It is located here (rather
+ * than strsubr.c) so that we don't have to expose all of the
+ * allocb() implementation details in header files.
+ */
+mblk_t *
+allocb_wait(size_t size, uint_t pri, uint_t flags, int *error)
+{
+ dblk_t *dbp;
+ mblk_t *mp;
+ size_t index;
+
+ index = (size -1) >> DBLK_SIZE_SHIFT;
+
+ if (flags & STR_NOSIG) {
+ if (index >= (DBLK_MAX_CACHE >> DBLK_SIZE_SHIFT)) {
+ if (size != 0) {
+ mp = allocb_oversize(size, KM_SLEEP);
+ FTRACE_1("allocb_wait (NOSIG): mp=0x%lx",
+ (uintptr_t)mp);
+ return (mp);
+ }
+ index = 0;
+ }
+
+ dbp = kmem_cache_alloc(dblk_cache[index], KM_SLEEP);
+ mp = dbp->db_mblk;
+ DBLK_RTFU_WORD(dbp) = DBLK_RTFU(1, M_DATA, 0, 0);
+ mp->b_next = mp->b_prev = mp->b_cont = NULL;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+ mp->b_queue = NULL;
+ MBLK_BAND_FLAG_WORD(mp) = 0;
+ STR_FTALLOC(&DB_FTHDR(mp), FTEV_ALLOCBW, size);
+
+ FTRACE_1("allocb_wait (NOSIG): mp=0x%lx", (uintptr_t)mp);
+
+ } else {
+ while ((mp = allocb(size, pri)) == NULL) {
+ if ((*error = strwaitbuf(size, BPRI_HI)) != 0)
+ return (NULL);
+ }
+ }
+
+ return (mp);
+}
+
+/*
+ * Call function 'func' with 'arg' when a class zero block can
+ * be allocated with priority 'pri'.
+ */
+bufcall_id_t
+esbbcall(uint_t pri, void (*func)(void *), void *arg)
+{
+ return (bufcall(1, pri, func, arg));
+}
+
+/*
+ * Allocates an iocblk (M_IOCTL) block. Properly sets the credentials
+ * ioc_id, rval and error of the struct ioctl to set up an ioctl call.
+ * This provides consistency for all internal allocators of ioctl.
+ */
+mblk_t *
+mkiocb(uint_t cmd)
+{
+ struct iocblk *ioc;
+ mblk_t *mp;
+
+ /*
+ * Allocate enough space for any of the ioctl related messages.
+ */
+ if ((mp = allocb(sizeof (union ioctypes), BPRI_MED)) == NULL)
+ return (NULL);
+
+ bzero(mp->b_rptr, sizeof (union ioctypes));
+
+ /*
+ * Set the mblk_t information and ptrs correctly.
+ */
+ mp->b_wptr += sizeof (struct iocblk);
+ mp->b_datap->db_type = M_IOCTL;
+
+ /*
+ * Fill in the fields.
+ */
+ ioc = (struct iocblk *)mp->b_rptr;
+ ioc->ioc_cmd = cmd;
+ ioc->ioc_cr = kcred;
+ ioc->ioc_id = getiocseqno();
+ ioc->ioc_flag = IOC_NATIVE;
+ return (mp);
+}
+
+/*
+ * test if block of given size can be allocated with a request of
+ * the given priority.
+ * 'pri' is no longer used, but is retained for compatibility.
+ */
+/* ARGSUSED */
+int
+testb(size_t size, uint_t pri)
+{
+ return ((size + sizeof (dblk_t)) <= kmem_avail());
+}
+
+/* _KERNEL: bufcall, unbufcall */
+
+/*
+ * Duplicate a message block by block (uses dupb), returning
+ * a pointer to the duplicate message.
+ * Returns a non-NULL value only if the entire message
+ * was dup'd.
+ */
+mblk_t *
+dupmsg(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (!bp || !(nbp = head = dupb(bp)))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if (!(nbp->b_cont = dupb(bp->b_cont))) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+#define DUPB_NOLOAN(bp) \
+ ((((bp)->b_datap->db_struioflag & STRUIO_ZC) != 0) ? \
+ copyb((bp)) : dupb((bp)))
+
+mblk_t *
+dupmsg_noloan(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (bp == NULL || DB_TYPE(bp) != M_DATA ||
+ ((nbp = head = DUPB_NOLOAN(bp)) == NULL))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if ((nbp->b_cont = DUPB_NOLOAN(bp->b_cont)) == NULL) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+/*
+ * Copy data from message and data block to newly allocated message and
+ * data block. Returns new message block pointer, or NULL if error.
+ * The alignment of rptr (w.r.t. word alignment) will be the same in the copy
+ * as in the original even when db_base is not word aligned. (bug 1052877)
+ */
+mblk_t *
+copyb(mblk_t *bp)
+{
+ mblk_t *nbp;
+ dblk_t *dp, *ndp;
+ uchar_t *base;
+ size_t size;
+ size_t unaligned;
+
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+
+ dp = bp->b_datap;
+ if (dp->db_fthdr != NULL)
+ STR_FTEVENT_MBLK(bp, caller(), FTEV_COPYB, 0);
+
+ /*
+ * Special handling for Multidata message; this should be
+ * removed once a copy-callback routine is made available.
+ */
+ if (dp->db_type == M_MULTIDATA) {
+ /* _KERNEL mmd_copy stuff */
+ return (NULL);
+ }
+
+ size = dp->db_lim - dp->db_base;
+ unaligned = P2PHASE((uintptr_t)dp->db_base, sizeof (uint_t));
+ if ((nbp = allocb_tmpl(size + unaligned, bp)) == NULL)
+ return (NULL);
+ nbp->b_flag = bp->b_flag;
+ nbp->b_band = bp->b_band;
+ ndp = nbp->b_datap;
+
+ /*
+ * Well, here is a potential issue. If we are trying to
+ * trace a flow, and we copy the message, we might lose
+ * information about where this message might have been.
+ * So we should inherit the FT data. On the other hand,
+ * a user might be interested only in alloc to free data.
+ * So I guess the real answer is to provide a tunable.
+ */
+ STR_FTEVENT_MBLK(nbp, caller(), FTEV_COPYB, 1);
+
+ base = ndp->db_base + unaligned;
+ bcopy(dp->db_base, ndp->db_base + unaligned, size);
+
+ nbp->b_rptr = base + (bp->b_rptr - dp->db_base);
+ nbp->b_wptr = nbp->b_rptr + MBLKL(bp);
+
+ return (nbp);
+}
+
+/*
+ * Copy data from message to newly allocated message using new
+ * data blocks. Returns a pointer to the new message, or NULL if error.
+ */
+mblk_t *
+copymsg(mblk_t *bp)
+{
+ mblk_t *head, *nbp;
+
+ if (!bp || !(nbp = head = copyb(bp)))
+ return (NULL);
+
+ while (bp->b_cont) {
+ if (!(nbp->b_cont = copyb(bp->b_cont))) {
+ freemsg(head);
+ return (NULL);
+ }
+ nbp = nbp->b_cont;
+ bp = bp->b_cont;
+ }
+ return (head);
+}
+
+/*
+ * link a message block to tail of message
+ */
+void
+linkb(mblk_t *mp, mblk_t *bp)
+{
+ ASSERT(mp && bp);
+
+ for (; mp->b_cont; mp = mp->b_cont)
+ ;
+ mp->b_cont = bp;
+}
+
+/*
+ * unlink a message block from head of message
+ * return pointer to new message.
+ * NULL if message becomes empty.
+ */
+mblk_t *
+unlinkb(mblk_t *bp)
+{
+ mblk_t *bp1;
+
+ bp1 = bp->b_cont;
+ bp->b_cont = NULL;
+ return (bp1);
+}
+
+/*
+ * remove a message block "bp" from message "mp"
+ *
+ * Return pointer to new message or NULL if no message remains.
+ * Return -1 if bp is not found in message.
+ */
+mblk_t *
+rmvb(mblk_t *mp, mblk_t *bp)
+{
+ mblk_t *tmp;
+ mblk_t *lastp = NULL;
+
+ ASSERT(mp && bp);
+ for (tmp = mp; tmp; tmp = tmp->b_cont) {
+ if (tmp == bp) {
+ if (lastp)
+ lastp->b_cont = tmp->b_cont;
+ else
+ mp = tmp->b_cont;
+ tmp->b_cont = NULL;
+ return (mp);
+ }
+ lastp = tmp;
+ }
+ return ((mblk_t *)-1);
+}
+
+/*
+ * Concatenate and align first len bytes of common
+ * message type. Len == -1, means concat everything.
+ * Returns 1 on success, 0 on failure
+ * After the pullup, mp points to the pulled up data.
+ */
+int
+pullupmsg(mblk_t *mp, ssize_t len)
+{
+ mblk_t *bp, *b_cont;
+ dblk_t *dbp;
+ ssize_t n;
+
+ ASSERT(mp->b_datap->db_ref > 0);
+ ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
+
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (0);
+
+ if (len == -1) {
+ if (mp->b_cont == NULL && str_aligned(mp->b_rptr))
+ return (1);
+ len = xmsgsize(mp);
+ } else {
+ ssize_t first_mblk_len = mp->b_wptr - mp->b_rptr;
+ ASSERT(first_mblk_len >= 0);
+ /*
+ * If the length is less than that of the first mblk,
+ * we want to pull up the message into an aligned mblk.
+ * Though not part of the spec, some callers assume it.
+ */
+ if (len <= first_mblk_len) {
+ if (str_aligned(mp->b_rptr))
+ return (1);
+ len = first_mblk_len;
+ } else if (xmsgsize(mp) < len)
+ return (0);
+ }
+
+ if ((bp = allocb_tmpl(len, mp)) == NULL)
+ return (0);
+
+ dbp = bp->b_datap;
+ *bp = *mp; /* swap mblks so bp heads the old msg... */
+ mp->b_datap = dbp; /* ... and mp heads the new message */
+ mp->b_datap->db_mblk = mp;
+ bp->b_datap->db_mblk = bp;
+ mp->b_rptr = mp->b_wptr = dbp->db_base;
+
+ do {
+ ASSERT(bp->b_datap->db_ref > 0);
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ n = MIN(bp->b_wptr - bp->b_rptr, len);
+ ASSERT(n >= 0); /* allow zero-length mblk_t's */
+ if (n > 0)
+ bcopy(bp->b_rptr, mp->b_wptr, (size_t)n);
+ mp->b_wptr += n;
+ bp->b_rptr += n;
+ len -= n;
+ if (bp->b_rptr != bp->b_wptr)
+ break;
+ b_cont = bp->b_cont;
+ freeb(bp);
+ bp = b_cont;
+ } while (len && bp);
+
+ mp->b_cont = bp; /* tack on whatever wasn't pulled up */
+
+ return (1);
+}
+
+/*
+ * Concatenate and align at least the first len bytes of common message
+ * type. Len == -1 means concatenate everything. The original message is
+ * unaltered. Returns a pointer to a new message on success, otherwise
+ * returns NULL.
+ */
+mblk_t *
+msgpullup(mblk_t *mp, ssize_t len)
+{
+ mblk_t *newmp;
+ ssize_t totlen;
+ ssize_t n;
+
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (NULL);
+
+ totlen = xmsgsize(mp);
+
+ if ((len > 0) && (len > totlen))
+ return (NULL);
+
+ /*
+ * Copy all of the first msg type into one new mblk, then dupmsg
+ * and link the rest onto this.
+ */
+
+ len = totlen;
+
+ if ((newmp = allocb_tmpl(len, mp)) == NULL)
+ return (NULL);
+
+ newmp->b_flag = mp->b_flag;
+ newmp->b_band = mp->b_band;
+
+ while (len > 0) {
+ n = mp->b_wptr - mp->b_rptr;
+ ASSERT(n >= 0); /* allow zero-length mblk_t's */
+ if (n > 0)
+ bcopy(mp->b_rptr, newmp->b_wptr, n);
+ newmp->b_wptr += n;
+ len -= n;
+ mp = mp->b_cont;
+ }
+
+ if (mp != NULL) {
+ newmp->b_cont = dupmsg(mp);
+ if (newmp->b_cont == NULL) {
+ freemsg(newmp);
+ return (NULL);
+ }
+ }
+
+ return (newmp);
+}
+
+/*
+ * Trim bytes from message
+ * len > 0, trim from head
+ * len < 0, trim from tail
+ * Returns 1 on success, 0 on failure.
+ */
+int
+adjmsg(mblk_t *mp, ssize_t len)
+{
+ mblk_t *bp;
+ mblk_t *save_bp = NULL;
+ mblk_t *prev_bp;
+ mblk_t *bcont;
+ unsigned char type;
+ ssize_t n;
+ int fromhead;
+ int first;
+
+ ASSERT(mp != NULL);
+ /*
+ * We won't handle Multidata message, since it contains
+ * metadata which this function has no knowledge of; we
+ * assert on DEBUG, and return failure otherwise.
+ */
+ ASSERT(mp->b_datap->db_type != M_MULTIDATA);
+ if (mp->b_datap->db_type == M_MULTIDATA)
+ return (0);
+
+ if (len < 0) {
+ fromhead = 0;
+ len = -len;
+ } else {
+ fromhead = 1;
+ }
+
+ if (xmsgsize(mp) < len)
+ return (0);
+
+ if (fromhead) {
+ first = 1;
+ while (len) {
+ ASSERT(mp->b_wptr >= mp->b_rptr);
+ n = MIN(mp->b_wptr - mp->b_rptr, len);
+ mp->b_rptr += n;
+ len -= n;
+
+ /*
+ * If this is not the first zero length
+ * message remove it
+ */
+ if (!first && (mp->b_wptr == mp->b_rptr)) {
+ bcont = mp->b_cont;
+ freeb(mp);
+ mp = save_bp->b_cont = bcont;
+ } else {
+ save_bp = mp;
+ mp = mp->b_cont;
+ }
+ first = 0;
+ }
+ } else {
+ type = mp->b_datap->db_type;
+ while (len) {
+ bp = mp;
+ save_bp = NULL;
+
+ /*
+ * Find the last message of same type
+ */
+ while (bp && bp->b_datap->db_type == type) {
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ prev_bp = save_bp;
+ save_bp = bp;
+ bp = bp->b_cont;
+ }
+ if (save_bp == NULL)
+ break;
+ n = MIN(save_bp->b_wptr - save_bp->b_rptr, len);
+ save_bp->b_wptr -= n;
+ len -= n;
+
+ /*
+ * If this is not the first message
+ * and we have taken away everything
+ * from this message, remove it
+ */
+
+ if ((save_bp != mp) &&
+ (save_bp->b_wptr == save_bp->b_rptr)) {
+ bcont = save_bp->b_cont;
+ freeb(save_bp);
+ prev_bp->b_cont = bcont;
+ }
+ }
+ }
+ return (1);
+}
+
+/*
+ * get number of data bytes in message
+ */
+size_t
+msgdsize(mblk_t *bp)
+{
+ size_t count = 0;
+
+ for (; bp; bp = bp->b_cont)
+ if (bp->b_datap->db_type == M_DATA) {
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ count += bp->b_wptr - bp->b_rptr;
+ }
+ return (count);
+}
+
+/* getq() etc to EOF removed */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c b/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c
new file mode 100644
index 0000000000..e49313c37c
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_strsubr.c
@@ -0,0 +1,160 @@
+/*
+ * 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) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <sys/atomic.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/cmn_err.h>
+
+#include <sys/strft.h>
+
+int str_ftnever = 0;
+
+static void mblk_free(mblk_t *);
+static void esballoc_mblk_free(mblk_t *);
+
+/*
+ * A few things from os/strsubr.c
+ */
+
+int
+strwaitbuf(size_t size, int pri)
+{
+ return (0);
+}
+
+/*
+ * Return size of message of block type (bp->b_datap->db_type)
+ */
+size_t
+xmsgsize(mblk_t *bp)
+{
+ unsigned char type;
+ size_t count = 0;
+
+ type = bp->b_datap->db_type;
+
+ for (; bp; bp = bp->b_cont) {
+ if (type != bp->b_datap->db_type)
+ break;
+ ASSERT(bp->b_wptr >= bp->b_rptr);
+ count += bp->b_wptr - bp->b_rptr;
+ }
+ return (count);
+}
+
+/* ARGSUSED */
+bufcall_id_t
+bufcall(size_t size, uint_t pri, void (*func)(void *), void *arg)
+{
+ cmn_err(CE_NOTE, "bufcall() called!");
+ return ("fake bufcall id");
+}
+
+/* ARGSUSED */
+void
+unbufcall(bufcall_id_t id)
+{
+}
+
+/* ARGSUSED */
+void
+freebs_enqueue(mblk_t *mp, dblk_t *dbp)
+{
+ /*
+ * Won't bother with esb_queue_t async free here.
+ * Rather just free this mblk directly.
+ */
+ esballoc_mblk_free(mp);
+}
+
+static void
+esballoc_mblk_free(mblk_t *mp)
+{
+ mblk_t *nextmp;
+
+ for (; mp != NULL; mp = nextmp) {
+ nextmp = mp->b_next;
+ mp->b_next = NULL;
+ mblk_free(mp);
+ }
+}
+
+static void
+mblk_free(mblk_t *mp)
+{
+ dblk_t *dbp = mp->b_datap;
+ frtn_t *frp = dbp->db_frtnp;
+
+ mp->b_next = NULL;
+ if (dbp->db_fthdr != NULL)
+ str_ftfree(dbp);
+
+ ASSERT(dbp->db_fthdr == NULL);
+ frp->free_func(frp->free_arg);
+ ASSERT(dbp->db_mblk == mp);
+
+ if (dbp->db_credp != NULL) {
+ crfree(dbp->db_credp);
+ dbp->db_credp = NULL;
+ }
+ dbp->db_cpid = -1;
+ dbp->db_struioflag = 0;
+ dbp->db_struioun.cksum.flags = 0;
+
+ kmem_cache_free(dbp->db_cache, dbp);
+}
+
+/* ARGSUSED */
+mblk_t *
+mmd_copy(mblk_t *bp, int flags)
+{
+ return (NULL);
+}
+
+/*
+ * A little bit from os/streamio.c
+ */
+
+static volatile uint32_t ioc_id;
+
+int
+getiocseqno(void)
+{
+ uint32_t i;
+
+ i = atomic_inc_32_nv(&ioc_id);
+
+ return ((int)i);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h b/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h
new file mode 100644
index 0000000000..d58b5454c4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fake_xti.h
@@ -0,0 +1,314 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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 2014 Garrett D'Amore <garrett@damore.org>
+ */
+/* Copyright (c) 1996 Sun Microsystems, Inc. */
+/* All Rights Reserved */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _XTI_H
+#define _XTI_H
+
+#include <sys/types.h>
+
+/*
+ * The following include file has declarations needed by both the kernel
+ * level transport providers and the user level library. This file includes
+ * it to expose its namespaces to XTI user level interface.
+ */
+#include <sys/tpicommon.h>
+
+/*
+ * Include XTI interface level options management declarations
+ */
+#include <sys/xti_xtiopt.h>
+
+#if !defined(_XPG5)
+
+/*
+ * Include declarations related to OSI transport and management data
+ * structures, and the Internet Protocol Suite.
+ * Note: The older Unix95/XNS4 XTI spec required these to be
+ * exposed through the generic interface header.
+ */
+#include <sys/xti_osi.h>
+#include <sys/xti_inet.h>
+
+#endif /* !defined(_XPG5) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The following t_errno error codes are included in the namespace by
+ * inclusion of <sys/tpicommon.h> above. The english language error strings
+ * associated with the error values are reproduced here for easy reference.
+ *
+ * Error Value Error message string
+ * ---- ----- --------------------
+ * TBADADDR 1 Incorrect address format
+ * TBADOPT 2 Incorrect options format
+ * TACCES 3 Illegal permissions
+ * TBADF 4 Illegal file descriptor
+ * TNOADDR 5 Couldn't allocate address
+ * TOUTSTATE 6 Routine will place interface out of state
+ * TBADSEQ 7 Illegal called/calling sequence number
+ * TSYSERR 8 System error
+ * TLOOK 9 An event requires attention
+ * TBADDATA 10 Illegal amount of data
+ * TBUFOVFLW 11 Buffer not large enough
+ * TFLOW 12 Can't send message - (blocked)
+ * TNODATA 13 No message currently available
+ * TNODIS 14 Disconnect message not found
+ * TNOUDERR 15 Unitdata error message not found
+ * TBADFLAG 16 Incorrect flags specified
+ * TNOREL 17 Orderly release message not found
+ * TNOTSUPPORT 18 Primitive not supported by provider
+ * TSTATECHNG 19 State is in process of changing
+ * TNOSTRUCTYPE 20 Unsupported structure type requested
+ * TBADNAME 21 Invalid transport provider name
+ * TBADQLEN 22 Listener queue length limit is zero
+ * TADDRBUSY 23 Transport address is in use
+ * TINDOUT 24 Outstanding connection indications
+ * TPROVMISMATCH 25 Listener-acceptor transport provider mismatch
+ * TRESQLEN 26 Connection acceptor has listen queue length
+ * limit greater than zero
+ * TRESADDR 27 Connection acceptor-listener addresses not
+ * same but required by transport
+ * TQFULL 28 Incoming connection queue is full
+ * TPROTO 29 Protocol error on transport primitive
+ *
+ */
+
+/*
+ * The following are the events returned by t_look
+ */
+#define T_LISTEN 0x0001 /* connection indication received */
+#define T_CONNECT 0x0002 /* connect confirmation received */
+#define T_DATA 0x0004 /* normal data received */
+#define T_EXDATA 0x0008 /* expedited data received */
+#define T_DISCONNECT 0x0010 /* disconnect received */
+#define T_UDERR 0x0040 /* data gram error indication */
+#define T_ORDREL 0x0080 /* orderly release indication */
+#define T_GODATA 0x0100 /* sending normal data is again possible */
+#define T_GOEXDATA 0x0200 /* sending expedited data is again possible */
+
+/*
+ * Flags for data primitives
+ */
+#define T_MORE 0x001 /* more data */
+#define T_EXPEDITED 0x002 /* expedited data */
+#define T_PUSH 0x004 /* send data immediately */
+
+/*
+ * XTI error return
+ */
+#if defined(_REENTRANT) || defined(_TS_ERRNO)
+extern int *__t_errno();
+#define t_errno (*(__t_errno()))
+#else
+#error "extern int t_errno?"
+#endif /* defined(_REENTRANT) || defined(_TS_ERRNO) */
+
+
+/*
+ * The following are for t_sysconf()
+ */
+#ifndef T_IOV_MAX
+#define T_IOV_MAX 16 /* Maximum number of scatter/gather buffers */
+#endif /* Should be <= IOV_MAX */
+
+#ifndef _SC_T_IOV_MAX
+#define _SC_T_IOV_MAX 79 /* Should be same in <unistd.h> for use by */
+#endif /* sysconf() */
+
+struct t_iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+/*
+ * Translate source level interface to binary entry point names.
+ *
+ * Note: This is done to maintain co-existence of TLI and XTI
+ * interfaces which have identical names for most functions but
+ * different semantics. The XTI names are moved to the different
+ * prefix space in the ABI. The #ifdef is required to make use of
+ * of the compiler feature to allow redefinition of external names
+ * where available. Otherwise a simple #define is used when this
+ * header is used with other compilers.
+ * The use of #define also has the effect of renaming all names (not
+ * just function names) to the new name. The TLI function names
+ * (e.g. t_bind) can have identical names for structure names
+ * (e.g struct t_bind). Therefore, this redefinition of names needs
+ * to be before all structure and function name declarations in the header.
+ */
+
+#ifdef __PRAGMA_REDEFINE_EXTNAME
+
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#pragma redefine_extname t_accept _xti_accept
+#else
+#pragma redefine_extname t_accept _xti_xns5_accept
+#endif
+#pragma redefine_extname t_alloc _xti_alloc
+#pragma redefine_extname t_bind _xti_bind
+#pragma redefine_extname t_close _xti_close
+#pragma redefine_extname t_connect _xti_connect
+#pragma redefine_extname t_error _xti_error
+#pragma redefine_extname t_free _xti_free
+#pragma redefine_extname t_getinfo _xti_getinfo
+#pragma redefine_extname t_getstate _xti_getstate
+#pragma redefine_extname t_getprotaddr _xti_getprotaddr
+#pragma redefine_extname t_listen _xti_listen
+#pragma redefine_extname t_look _xti_look
+#pragma redefine_extname t_open _xti_open
+#pragma redefine_extname t_optmgmt _xti_optmgmt
+#pragma redefine_extname t_rcv _xti_rcv
+#pragma redefine_extname t_rcvconnect _xti_rcvconnect
+#pragma redefine_extname t_rcvdis _xti_rcvdis
+#pragma redefine_extname t_rcvrel _xti_rcvrel
+#pragma redefine_extname t_rcvreldata _xti_rcvreldata
+#pragma redefine_extname t_rcvudata _xti_rcvudata
+#pragma redefine_extname t_rcvuderr _xti_rcvuderr
+#pragma redefine_extname t_rcvv _xti_rcvv
+#pragma redefine_extname t_rcvvudata _xti_rcvvudata
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#pragma redefine_extname t_snd _xti_snd
+#else
+#pragma redefine_extname t_snd _xti_xns5_snd
+#endif
+#pragma redefine_extname t_snddis _xti_snddis
+#pragma redefine_extname t_sndrel _xti_sndrel
+#pragma redefine_extname t_sndreldata _xti_sndreldata
+#pragma redefine_extname t_sndudata _xti_sndudata
+#pragma redefine_extname t_sndv _xti_sndv
+#pragma redefine_extname t_sndvudata _xti_sndvudata
+#pragma redefine_extname t_strerror _xti_strerror
+#pragma redefine_extname t_sync _xti_sync
+#pragma redefine_extname t_sysconf _xti_sysconf
+#pragma redefine_extname t_unbind _xti_unbind
+
+#else /* __PRAGMA_REDEFINE_EXTNAME */
+
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#define t_accept _xti_accept
+#else
+#define t_accept _xti_xns5_accept
+#endif
+#define t_alloc _xti_alloc
+#define t_bind(a,b,c) _xti_bind(a,b,c)
+#define t_close _xti_close
+#define t_connect _xti_connect
+#define t_error _xti_error
+#define t_free _xti_free
+#define t_getinfo _xti_getinfo
+#define t_getstate _xti_getstate
+#define t_getprotaddr _xti_getprotaddr
+#define t_listen _xti_listen
+#define t_look _xti_look
+#define t_open _xti_open
+#define t_optmgmt(a,b,c) _xti_optmgmt(a,b,c)
+#define t_rcv _xti_rcv
+#define t_rcvconnect _xti_rcvconnect
+#define t_rcvdis _xti_rcvdis
+#define t_rcvrel _xti_rcvrel
+#define t_rcvreldata _xti_rcvreldata
+#define t_rcvudata _xti_rcvudata
+#define t_rcvuderr _xti_rcvuderr
+#define t_rcvv _xti_rcvv
+#define t_rcvvudata _xti_rcvvudata
+#if defined(_XOPEN_SOURCE) && !defined(_XPG5)
+#define t_snd _xti_snd
+#else
+#define t_snd _xti_xns5_snd
+#endif
+#define t_snddis _xti_snddis
+#define t_sndrel _xti_sndrel
+#define t_sndreldata _xti_sndreldata
+#define t_sndudata _xti_sndudata
+#define t_sndv _xti_sndv
+#define t_sndvudata _xti_sndvudata
+#define t_strerror _xti_strerror
+#define t_sync _xti_sync
+#define t_sysconf _xti_sysconf
+#define t_unbind _xti_unbind
+
+#endif /* __PRAGMA_REDEFINE_EXTNAME */
+
+/*
+ * All the rest of the standard xti.h removed because the structs:
+ * netbuf, t_info, t_opthdr, t_optmgmt, t_bind, t_call, ...
+ * all conflict with definitions in tiuser.h which we need
+ * for the (simulated) kernel interfaces in fake_ktli.c.
+ *
+ * The XTI library functions below would normally be defined by
+ * including tiuser.h after the defines above, which we can't.
+ */
+
+int _xti_accept(int, int, struct t_call *);
+int _xti_xns5_accept(int, int, struct t_call *);
+char *_xti_alloc(int, int, int);
+int _xti_bind(int, struct t_bind *, struct t_bind *);
+int _xti_close(int);
+int _xti_connect(int, struct t_call *, struct t_call *);
+int _xti_error(char *);
+int _xti_free(char *, int);
+int _xti_getinfo(int, struct t_info *);
+int _xti_getprotaddr(int, struct t_bind *, struct t_bind *);
+int _xti_getstate(int);
+int _xti_listen(int, struct t_call *);
+int _xti_look(int);
+int _xti_open(char *, int, struct t_info *);
+int _xti_optmgmt(int, struct t_optmgmt *, struct t_optmgmt *);
+int _xti_rcv(int, char *, unsigned int, int *);
+int _xti_rcvconnect(int, struct t_call *);
+int _xti_rcvdis(int, struct t_discon *);
+int _xti_rcvrel(int);
+int _xti_rcvreldata(int, struct t_discon *);
+int _xti_rcvudata(int, struct t_unitdata *, int *);
+int _xti_rcvuderr(int, struct t_uderr *);
+int _xti_rcvv(int, struct t_iovec *, unsigned int, int *);
+int _xti_rcvvudata(int, struct t_unitdata *, struct t_iovec *,
+ unsigned int, int *);
+int _xti_snd(int, char *, unsigned int, int);
+int _xti_xns5_snd(int, char *, unsigned int, int);
+int _xti_snddis(int, struct t_call *);
+int _xti_sndrel(int);
+int _xti_sndreldata(int, struct t_discon *);
+int _xti_sndudata(int, struct t_unitdata *);
+int _xti_sndv(int, const struct t_iovec *, unsigned int, int);
+int _xti_sndvudata(int, struct t_unitdata *, struct t_iovec *, unsigned int);
+char *_xti_strerror(int);
+int _xti_sync(int);
+int _xti_sysconf(int);
+int _xti_unbind(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XTI_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
new file mode 100644
index 0000000000..24bb8fccbc
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
@@ -0,0 +1,163 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Helper functions for SMB signing using PKCS#11
+ *
+ * There are two implementations of these functions:
+ * This one (for user space) and another for kernel.
+ * See: uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <netsmb/smb_signing.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+
+/*
+ * SMB1 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb_md5_getmech(smb_sign_mech_t *mech)
+{
+ mech->mechanism = CKM_MD5;
+ mech->pParameter = NULL;
+ mech->ulParameterLen = 0;
+ return (0);
+}
+
+/*
+ * Start PKCS#11 session.
+ */
+int
+smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
+{
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = C_DigestInit(*ctxp, mech);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
+{
+ CK_RV rv;
+
+ rv = C_DigestUpdate(ctx, buf, len);
+ if (rv != CKR_OK)
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Get the final digest.
+ */
+int
+smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ CK_ULONG len = MD5_DIGEST_LENGTH;
+ CK_RV rv;
+
+ rv = C_DigestFinal(ctx, digest16, &len);
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * SMB2 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb2_hmac_getmech(smb_sign_mech_t *mech)
+{
+ mech->mechanism = CKM_SHA256_HMAC;
+ mech->pParameter = NULL;
+ mech->ulParameterLen = 0;
+ return (0);
+}
+
+/*
+ * Start PKCS#11 session, load the key.
+ */
+int
+smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
+ uint8_t *key, size_t key_len)
+{
+ CK_OBJECT_HANDLE hkey = 0;
+ CK_RV rv;
+
+ rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
+ key, key_len, &hkey);
+ if (rv != CKR_OK)
+ return (-1);
+
+ rv = C_SignInit(*ctxp, mech, hkey);
+ (void) C_DestroyObject(*ctxp, hkey);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
+{
+ CK_RV rv;
+
+ rv = C_SignUpdate(ctx, in, len);
+ if (rv != CKR_OK)
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
+
+/*
+ * Note, the SMB2 signature is the first 16 bytes of the
+ * 32-byte SHA256 HMAC digest.
+ */
+int
+smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ uint8_t full_digest[SHA256_DIGEST_LENGTH];
+ CK_ULONG len = SHA256_DIGEST_LENGTH;
+ CK_RV rv;
+
+ rv = C_SignFinal(ctx, full_digest, &len);
+ if (rv == CKR_OK)
+ bcopy(full_digest, digest16, 16);
+
+ (void) C_CloseSession(ctx);
+
+ return (rv == CKR_OK ? 0 : -1);
+}
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h b/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h
new file mode 100644
index 0000000000..b3d15510be
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/libfknsmb.h
@@ -0,0 +1,45 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _LIBFKNSMB_H_
+#define _LIBFKNSMB_H_
+
+#include <sys/types.h>
+#include <sys/types32.h>
+#include <sys/cred.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct smb_share;
+
+extern const uint32_t nsmb_version;
+extern void streams_msg_init(void);
+
+int nsmb_drv_init(void);
+int nsmb_drv_fini(void);
+/* These are dev32_t because they're cast to int in user code. */
+int nsmb_drv_ioctl(dev32_t dev, int cmd, intptr_t arg, int flags);
+int nsmb_drv_open(dev32_t *dev, int flags, int otyp);
+int nsmb_drv_close(dev32_t dev, int flags, int otyp);
+int smb_dev2share(int fd, struct smb_share **sspp);
+void nsmb_drv_load(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFKNSMB_H_ */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb b/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb
new file mode 100644
index 0000000000..8ba9f62607
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/llib-lfknsmb
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfknsmb.h>
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
new file mode 100644
index 0000000000..1123cc1e85
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
@@ -0,0 +1,121 @@
+#
+# 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ kmem_avail;
+ kmem_maxavail;
+
+ nsmb_drv_close;
+ nsmb_drv_fini;
+ nsmb_drv_init;
+ nsmb_drv_ioctl;
+ nsmb_drv_load;
+ nsmb_drv_open;
+
+ nsmb_version;
+
+ m_fixhdr;
+ mb_done;
+ mb_init;
+ mb_initm;
+ mb_put_mem;
+ mb_put_padbyte;
+ mb_put_uint16le;
+ mb_put_uint32le;
+ mb_put_uint64le;
+ mb_put_uint8;
+ mb_reserve;
+
+ md_done;
+ md_get_mbuf;
+ md_get_mem;
+ md_get_uint16le;
+ md_get_uint32le;
+ md_get_uint64le;
+ md_get_uint8;
+ md_initm;
+
+ secpolicy_fs_allowed_mount;
+ secpolicy_vnode_access2;
+ secpolicy_vnode_owner;
+ secpolicy_vnode_setattr;
+ secpolicy_vnode_setdac;
+
+ smb_credinit;
+ smb_credrele;
+ smb_dev2share;
+ smb_dos2unixtime;
+ smb_errmsg;
+ smb_nt_alloc;
+ smb_nt_done;
+ smb_nt_request;
+ smb_put_dmem;
+ smb_rq_alloc;
+ smb_rq_bend;
+ smb_rq_bstart;
+ smb_rq_done;
+ smb_rq_init;
+ smb_rq_simple;
+ smb_rq_simple_timed;
+ smb_rq_wend;
+ smb_rq_wstart;
+ smb_rwuio;
+ smb_share_kill;
+ smb_share_rele;
+ smb_smb_close;
+ smb_smb_ntcreate;
+ smb_t2_alloc;
+ smb_t2_done;
+ smb_t2_request;
+ smb_time_NT2local;
+ smb_time_local2NT;
+ smb_time_local2server;
+ smb_time_server2local;
+ smb_time_unix2dos;
+ smb_timo_append;
+ smb_timo_open;
+ smb_timo_read;
+ smb_timo_write;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h
new file mode 100644
index 0000000000..68979ca9d4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/ftrace.h
@@ -0,0 +1,67 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_FTRACE_H
+#define _SYS_FTRACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Constants used by both asm and non-asm code.
+ */
+
+/*
+ * Flags determining the state of tracing -
+ * both for the "ftrace_state" variable, and for the per-CPU variable
+ * "cpu[N]->cpu_ftrace_state".
+ */
+#define FTRACE_READY 0x00000001
+#define FTRACE_ENABLED 0x00000002
+
+#include <sys/types.h>
+#include <sys/sdt.h>
+
+/*
+ * The record of a single event.
+ * ftrace_record_t;
+ */
+
+#define FTRACE_0(fmt) \
+ DTRACE_PROBE1(ftrace0, char *, fmt)
+#define FTRACE_1(fmt, d1) \
+ DTRACE_PROBE2(ftrace1, char *, fmt, uintptr_t, d1)
+
+// #define FTRACE_START() ftrace_start()
+// #define FTRACE_STOP() ftrace_stop()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FTRACE_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h
new file mode 100644
index 0000000000..64a48897c3
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/kidmap.h
@@ -0,0 +1,183 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Windows to Solaris Identity Mapping kernel API
+ * This header defines an API to map Windows SIDs to
+ * Solaris UID and GIDs and versa visa.
+ */
+
+#ifndef _SYS_KIDMAP_H
+#define _SYS_KIDMAP_H
+
+#include <sys/idmap.h>
+#include <sys/door.h>
+#include <sys/zone.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The ifdef's for these two accomodate duplicate definitions in
+ * lib/libidmap/common/idmap.h (the real one). In this code we
+ * simulate a kernel environment in user space using the real
+ * idmap library, so need to be able to use both headers.
+ */
+
+/* Return status */
+#ifndef _IDMAP_STAT_TYPE
+#define _IDMAP_STAT_TYPE
+typedef int32_t idmap_stat;
+#endif /* _IDMAP_STAT_TYPE */
+
+/* Opaque get handle */
+#ifndef _IDMAP_GET_HANDLE_T
+#define _IDMAP_GET_HANDLE_T
+typedef struct idmap_get_handle idmap_get_handle_t;
+#endif /* _IDMAP_GET_HANDLE_T */
+
+/*
+ * In all the routines a Windows SID is handled as a
+ * string SID prefix plus a RID. For example
+ *
+ * S-1-5-5-12-34-568 will be passed as SID prefix
+ * S-1-5-5-12-34 and RID 568
+ *
+ * Certain routines returns pointers to a SID prefix string.
+ * These strings are stored internally and should not be modified
+ * or freed.
+ */
+
+
+/*
+ * The following routines are simple get ID mapping routines.
+ */
+
+
+idmap_stat
+kidmap_getuidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ uid_t *uid);
+
+idmap_stat
+kidmap_getgidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ gid_t *gid);
+
+idmap_stat
+kidmap_getpidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
+ uid_t *pid, int *is_user);
+
+idmap_stat
+kidmap_getsidbyuid(zone_t *zone, uid_t uid, const char **sid_prefix,
+ uint32_t *rid);
+
+idmap_stat
+kidmap_getsidbygid(zone_t *zone, gid_t gid, const char **sid_prefix,
+ uint32_t *rid);
+
+
+
+/*
+ * The following routines provide a batch interface for mapping IDs.
+ */
+
+/*
+ * Create a batch "get mapping" handle for batch mappings.
+ */
+idmap_get_handle_t *
+kidmap_get_create(zone_t *zone);
+
+/*
+ * These routines queue the request to the "get mapping" handle
+ */
+
+idmap_stat
+kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *uid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ gid_t *gid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle,
+ const char *sid_prefix, uint32_t rid,
+ uid_t *pid, int *is_user, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+idmap_stat
+kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
+ const char **sid_prefix, uint32_t *rid, idmap_stat *stat);
+
+/*
+ * Process the queued "get mapping" requests. The results (i.e.
+ * status and identity) will be available in the data areas
+ * provided by individual requests.
+ */
+idmap_stat
+kidmap_get_mappings(idmap_get_handle_t *get_handle);
+
+/*
+ * Destroy the "get mapping" handle
+ */
+void
+kidmap_get_destroy(idmap_get_handle_t *get_handle);
+
+#ifdef _KERNEL
+/*
+ * Functions that do the hard part of door registration/unregistration
+ * for the idmap_reg()/idmap_unreg() syscalls
+ */
+int idmap_reg_dh(zone_t *zone, door_handle_t dh);
+int idmap_unreg_dh(zone_t *zone, door_handle_t dh);
+
+/*
+ * Function needed by allocids() to ensure only the daemon that owns
+ * the door gets ephemeral IDS
+ */
+door_handle_t idmap_get_door(zone_t *zone);
+
+/*
+ * Function used by system call allocids() to purge the
+ * ID mapping cache
+ */
+void idmap_purge_cache(zone_t *zone);
+
+#endif /* _KERNEL */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_KIDMAP_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h
new file mode 100644
index 0000000000..7ca0d9c3fa
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/policy.h
@@ -0,0 +1,50 @@
+/*
+ * 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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_POLICY_H
+#define _SYS_POLICY_H
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/fs/snode.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int secpolicy_fs_allowed_mount(const char *);
+int secpolicy_vnode_owner(const cred_t *, uid_t);
+int secpolicy_vnode_access2(const cred_t *, vnode_t *, uid_t, mode_t, mode_t);
+int secpolicy_vnode_setattr(cred_t *, struct vnode *, struct vattr *,
+ const struct vattr *, int, int (void *, int, cred_t *), void *);
+int secpolicy_vnode_setdac(const cred_t *, uid_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_POLICY_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h
new file mode 100644
index 0000000000..c79ea68cec
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/sdt.h
@@ -0,0 +1,70 @@
+/*
+ * 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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_SDT_H
+#define _SYS_SDT_H
+
+#include <sys/stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * DTrace SDT probes have different signatures in userland than they do in
+ * kernel. If we're compiling for user mode (libfksmbsrv) define them as
+ * either no-op (for the SMB dtrace provider) or libfksmbsrv functions for
+ * the other SDT probe sites.
+ */
+#ifndef _KERNEL
+
+extern void smb_dtrace1(const char *, long);
+extern void smb_dtrace2(const char *, long, long);
+extern void smb_dtrace3(const char *, long, long, long);
+
+/*
+ * These are for the few (specialized) dtrace SDT probes sprinkled
+ * through the smbclnt code. In libfknsmb map these to functions.
+ */
+
+#undef DTRACE_PROBE1
+#define DTRACE_PROBE1(n, t1, a1) \
+ smb_dtrace1(#n, (long)a1)
+
+#undef DTRACE_PROBE2
+#define DTRACE_PROBE2(n, t1, a1, t2, a2) \
+ smb_dtrace2(#n, (long)a1, (long)a2)
+
+#undef DTRACE_PROBE3
+#define DTRACE_PROBE3(n, t1, a1, t2, a2, t3, a3) \
+ smb_dtrace3(#n, (long)a1, (long)a2, (long)a3)
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SYS_SDT_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h
new file mode 100644
index 0000000000..a293118e9d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/strft.h
@@ -0,0 +1,65 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_STRFT_H
+#define _SYS_STRFT_H
+
+#include <sys/sdt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define FTEV_ALLOCB 0x0000
+#define FTEV_ESBALLOC 0x0001
+#define FTEV_DESBALLOC 0x0002
+#define FTEV_ESBALLOCA 0x0003
+#define FTEV_DESBALLOCA 0x0004
+#define FTEV_ALLOCBIG 0x0005
+#define FTEV_ALLOCBW 0x0006
+#define FTEV_BCALLOCB 0x0007
+#define FTEV_FREEB 0x0008
+#define FTEV_DUPB 0x0009
+#define FTEV_COPYB 0x000A
+
+#define STR_FTALLOC(hpp, e, d) \
+ DTRACE_PROBE3(str__ftalloc, void *, hpp, ushort_t, e, ushort_t, d)
+
+/* Skip the 2nd arg (p) which is: caller() */
+#define STR_FTEVENT_MBLK(mp, p, e, d) \
+ DTRACE_PROBE3(str__ftevent, void *, mp, ushort_t, e, ushort_t, d)
+
+#define str_ftfree(dbp) ((void)(dbp))
+
+extern int str_ftnever, str_ftstack;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_STRFT_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h
new file mode 100644
index 0000000000..f901e79566
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/sunddi.h
@@ -0,0 +1,141 @@
+/*
+ * 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_SUNDDI_H
+#define _SYS_SUNDDI_H
+
+/*
+ * Sun Specific DDI definitions (fakekernel version)
+ * The real sunddi.h has become a "kitchen sink" full of
+ * includes we don't want, and lots of places include it.
+ * Rather than fight that battle now, provide this one
+ * with just the str*, mem*, and kiconv* functions.
+ * Some day, re-factor: sunddi.h, systm.h
+ */
+
+#include <sys/isa_defs.h>
+#include <sys/dditypes.h>
+#include <sys/time.h>
+#include <sys/cmn_err.h>
+
+#include <sys/kmem.h>
+#include <sys/nvpair.h>
+#include <sys/thread.h>
+#include <sys/stream.h>
+
+#include <sys/u8_textprep.h>
+#include <sys/kiconv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DDI_SUCCESS (0) /* successful return */
+#define DDI_FAILURE (-1) /* unsuccessful return */
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+extern char *ddi_strdup(const char *str, int flag);
+extern char *strdup(const char *str);
+extern void strfree(char *str);
+
+extern size_t strlen(const char *) __PURE;
+extern size_t strnlen(const char *, size_t) __PURE;
+extern char *strcpy(char *, const char *);
+extern char *strncpy(char *, const char *, size_t);
+
+/* Need to be consistent with <string.h> C++ definition for strchr() */
+#if __cplusplus >= 199711L
+extern const char *strchr(const char *, int);
+#else
+extern char *strchr(const char *, int);
+#endif /* __cplusplus >= 199711L */
+
+#define DDI_STRSAME(s1, s2) ((*(s1) == *(s2)) && (strcmp((s1), (s2)) == 0))
+extern int strcmp(const char *, const char *) __PURE;
+extern int strncmp(const char *, const char *, size_t) __PURE;
+extern char *strncat(char *, const char *, size_t);
+extern size_t strlcat(char *, const char *, size_t);
+extern size_t strlcpy(char *, const char *, size_t);
+extern size_t strspn(const char *, const char *);
+extern size_t strcspn(const char *, const char *);
+extern int bcmp(const void *, const void *, size_t) __PURE;
+extern int stoi(char **);
+extern void numtos(ulong_t, char *);
+extern void bcopy(const void *, void *, size_t);
+extern void bzero(void *, size_t);
+
+extern void *memcpy(void *, const void *, size_t);
+extern void *memset(void *, int, size_t);
+extern void *memmove(void *, const void *, size_t);
+extern int memcmp(const void *, const void *, size_t) __PURE;
+
+/* Need to be consistent with <string.h> C++ definition for memchr() */
+#if __cplusplus >= 199711L
+extern const void *memchr(const void *, int, size_t);
+#else
+extern void *memchr(const void *, int, size_t);
+#endif /* __cplusplus >= 199711L */
+
+extern int ddi_strtol(const char *, char **, int, long *);
+extern int ddi_strtoul(const char *, char **, int, unsigned long *);
+extern int ddi_strtoll(const char *, char **, int, longlong_t *);
+extern int ddi_strtoull(const char *, char **, int, u_longlong_t *);
+
+extern int ddi_copyin(const void *, void *, size_t, int);
+extern int ddi_copyout(const void *, void *, size_t, int);
+
+/*
+ * kiconv functions and their macros.
+ */
+#define KICONV_IGNORE_NULL (0x0001)
+#define KICONV_REPLACE_INVALID (0x0002)
+
+extern kiconv_t kiconv_open(const char *, const char *);
+extern size_t kiconv(kiconv_t, char **, size_t *, char **, size_t *, int *);
+extern int kiconv_close(kiconv_t);
+extern size_t kiconvstr(const char *, const char *, char *, size_t *, char *,
+ size_t *, int, int *);
+
+int
+ddi_soft_state_init(void **state_p, size_t size, size_t n_items);
+int
+ddi_soft_state_zalloc(void *state, int item);
+void *
+ddi_get_soft_state(void *state, int item);
+void
+ddi_soft_state_free(void *state, int item);
+void
+ddi_soft_state_fini(void **state_p);
+
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SUNDDI_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h
new file mode 100644
index 0000000000..9906f94a12
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs.h
@@ -0,0 +1,622 @@
+/*
+ * 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ifndef _SYS_VFS_H
+#define _SYS_VFS_H
+
+#include <sys/zone.h>
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/statvfs.h>
+#include <sys/refstr.h>
+#include <sys/avl.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Data associated with mounted file systems.
+ */
+
+/*
+ * Operations vector. This is used internal to the kernel; file systems
+ * supply their list of operations via vfs_setfsops().
+ */
+
+typedef struct vfsops vfsops_t;
+
+/*
+ * File system identifier. Should be unique (at least per machine).
+ */
+typedef struct {
+ int val[2]; /* file system id type */
+} fsid_t;
+
+/*
+ * File identifier. Should be unique per filesystem on a single
+ * machine. This is typically called by a stateless file server
+ * in order to generate "file handles".
+ *
+ * Many underlying file systems cast a struct fid into other
+ * file system dependent structures which may require 4 byte alignment.
+ * Because a fid starts with a short it may not be 4 byte aligned, the
+ * fid_pad will force the alignment.
+ */
+#define MAXFIDSZ 64
+#define OLD_MAXFIDSZ 16
+
+typedef struct fid {
+ union {
+ long fid_pad;
+ struct {
+ ushort_t len; /* length of data in bytes */
+ char data[MAXFIDSZ]; /* data (variable len) */
+ } _fid;
+ } un;
+} fid_t;
+
+#ifdef _SYSCALL32
+/*
+ * Solaris 64 - use old-style cache format with 32-bit aligned fid for on-disk
+ * struct compatibility.
+ */
+typedef struct fid32 {
+ union {
+ int32_t fid_pad;
+ struct {
+ uint16_t len; /* length of data in bytes */
+ char data[MAXFIDSZ]; /* data (variable len) */
+ } _fid;
+ } un;
+} fid32_t;
+#else /* not _SYSCALL32 */
+#define fid32 fid
+typedef fid_t fid32_t;
+#endif /* _SYSCALL32 */
+
+#define fid_len un._fid.len
+#define fid_data un._fid.data
+
+/*
+ * Structure defining a mount option for a filesystem.
+ * option names are found in mntent.h
+ */
+typedef struct mntopt {
+ char *mo_name; /* option name */
+ char **mo_cancel; /* list of options cancelled by this one */
+ char *mo_arg; /* argument string for this option */
+ int mo_flags; /* flags for this mount option */
+ void *mo_data; /* filesystem specific data */
+} mntopt_t;
+
+/*
+ * Flags that apply to mount options
+ */
+
+#define MO_SET 0x01 /* option is set */
+#define MO_NODISPLAY 0x02 /* option not listed in mnttab */
+#define MO_HASVALUE 0x04 /* option takes a value */
+#define MO_IGNORE 0x08 /* option ignored by parser */
+#define MO_DEFAULT MO_SET /* option is on by default */
+#define MO_TAG 0x10 /* flags a tag set by user program */
+#define MO_EMPTY 0x20 /* empty space in option table */
+
+#define VFS_NOFORCEOPT 0x01 /* honor MO_IGNORE (don't set option) */
+#define VFS_DISPLAY 0x02 /* Turn off MO_NODISPLAY bit for opt */
+#define VFS_NODISPLAY 0x04 /* Turn on MO_NODISPLAY bit for opt */
+#define VFS_CREATEOPT 0x08 /* Create the opt if it's not there */
+
+/*
+ * Structure holding mount option strings for the mounted file system.
+ */
+typedef struct mntopts {
+ uint_t mo_count; /* number of entries in table */
+ mntopt_t *mo_list; /* list of mount options */
+} mntopts_t;
+
+/*
+ * The kstat structures associated with the vopstats are kept in an
+ * AVL tree. This is to avoid the case where a file system does not
+ * use a unique fsid_t for each vfs (e.g., namefs). In order to do
+ * this, we need a structure that the AVL tree can use that also
+ * references the kstat.
+ * Note that the vks_fsid is generated from the value reported by
+ * VFS_STATVFS().
+ */
+typedef struct vskstat_anchor vsk_anchor_t;
+
+extern avl_tree_t vskstat_tree;
+extern kmutex_t vskstat_tree_lock;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+/*
+ * Structure per mounted file system. Each mounted file system has
+ * an array of operations and an instance record.
+ *
+ * The file systems are kept on a doubly linked circular list headed by
+ * "rootvfs".
+ * File system implementations should not access this list;
+ * it's intended for use only in the kernel's vfs layer.
+ *
+ * Each zone also has its own list of mounts, containing filesystems mounted
+ * somewhere within the filesystem tree rooted at the zone's rootpath. The
+ * list is doubly linked to match the global list.
+ *
+ * mnttab locking: the in-kernel mnttab uses the vfs_mntpt, vfs_resource and
+ * vfs_mntopts fields in the vfs_t. mntpt and resource are refstr_ts that
+ * are set at mount time and can only be modified during a remount.
+ * It is safe to read these fields if you can prevent a remount on the vfs,
+ * or through the convenience funcs vfs_getmntpoint() and vfs_getresource().
+ * The mntopts field may only be accessed through the provided convenience
+ * functions, as it is protected by the vfs list lock. Modifying a mount
+ * option requires grabbing the vfs list write lock, which can be a very
+ * high latency lock.
+ */
+struct zone; /* from zone.h */
+struct fem_head; /* from fem.h */
+
+typedef struct vfs {
+ struct vfs *vfs_next; /* next VFS in VFS list */
+ struct vfs *vfs_prev; /* prev VFS in VFS list */
+
+/* vfs_op should not be used directly. Accessor functions are provided */
+ vfsops_t *vfs_op; /* operations on VFS */
+
+ struct vnode *vfs_vnodecovered; /* vnode mounted on */
+ uint_t vfs_flag; /* flags */
+ uint_t vfs_bsize; /* native block size */
+ int vfs_fstype; /* file system type index */
+ fsid_t vfs_fsid; /* file system id */
+ void *vfs_data; /* private data */
+ dev_t vfs_dev; /* device of mounted VFS */
+ ulong_t vfs_bcount; /* I/O count (accounting) */
+ struct vfs *vfs_list; /* sync list pointer */
+ struct vfs *vfs_hash; /* hash list pointer */
+ ksema_t vfs_reflock; /* mount/unmount/sync lock */
+ uint_t vfs_count; /* vfs reference count */
+ mntopts_t vfs_mntopts; /* options mounted with */
+ refstr_t *vfs_resource; /* mounted resource name */
+ refstr_t *vfs_mntpt; /* mount point name */
+ time_t vfs_mtime; /* time we were mounted */
+ struct vfs_impl *vfs_implp; /* impl specific data */
+ /*
+ * Zones support. Note that the zone that "owns" the mount isn't
+ * necessarily the same as the zone in which the zone is visible.
+ * That is, vfs_zone and (vfs_zone_next|vfs_zone_prev) may refer to
+ * different zones.
+ */
+ struct zone *vfs_zone; /* zone that owns the mount */
+ struct vfs *vfs_zone_next; /* next VFS visible in zone */
+ struct vfs *vfs_zone_prev; /* prev VFS visible in zone */
+
+ struct fem_head *vfs_femhead; /* fs monitoring */
+ uint32_t vfs_lofi_id; /* ID if lofi mount */
+} vfs_t;
+
+#define vfs_featureset vfs_implp->vi_featureset
+#define vfs_vskap vfs_implp->vi_vskap
+#define vfs_fstypevsp vfs_implp->vi_fstypevsp
+#define vfs_vopstats vfs_implp->vi_vopstats
+#define vfs_hrctime vfs_implp->vi_hrctime
+
+#else // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+typedef struct vfs vfs_t;
+
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VFS flags.
+ */
+#define VFS_RDONLY 0x01 /* read-only vfs */
+#define VFS_NOMNTTAB 0x02 /* vfs not seen in mnttab */
+#define VFS_NOSETUID 0x08 /* setuid disallowed */
+#define VFS_REMOUNT 0x10 /* modify mount options only */
+#define VFS_NOTRUNC 0x20 /* does not truncate long file names */
+#define VFS_UNLINKABLE 0x40 /* unlink(2) can be applied to root */
+#define VFS_PXFS 0x80 /* clustering: global fs proxy vfs */
+#define VFS_UNMOUNTED 0x100 /* file system has been unmounted */
+#define VFS_NBMAND 0x200 /* allow non-blocking mandatory locks */
+#define VFS_XATTR 0x400 /* fs supports extended attributes */
+#define VFS_NODEVICES 0x800 /* device-special files disallowed */
+#define VFS_NOEXEC 0x1000 /* executables disallowed */
+#define VFS_STATS 0x2000 /* file system can collect stats */
+#define VFS_XID 0x4000 /* file system supports extended ids */
+
+#define VFS_NORESOURCE "unspecified_resource"
+#define VFS_NOMNTPT "unspecified_mountpoint"
+
+/*
+ * VFS features are implemented as bits set in the vfs_t.
+ * The vfs_feature_t typedef is a 64-bit number that will translate
+ * into an element in an array of bitmaps and a bit in that element.
+ * Developers must not depend on the implementation of this and
+ * need to use vfs_has_feature()/vfs_set_feature() routines.
+ */
+typedef uint64_t vfs_feature_t;
+
+#define VFSFT_XVATTR 0x100000001 /* Supports xvattr for attrs */
+#define VFSFT_CASEINSENSITIVE 0x100000002 /* Supports case-insensitive */
+#define VFSFT_NOCASESENSITIVE 0x100000004 /* NOT case-sensitive */
+#define VFSFT_DIRENTFLAGS 0x100000008 /* Supports dirent flags */
+#define VFSFT_ACLONCREATE 0x100000010 /* Supports ACL on create */
+#define VFSFT_ACEMASKONACCESS 0x100000020 /* Can use ACEMASK for access */
+#define VFSFT_SYSATTR_VIEWS 0x100000040 /* Supports sysattr view i/f */
+#define VFSFT_ACCESS_FILTER 0x100000080 /* dirents filtered by access */
+#define VFSFT_REPARSE 0x100000100 /* Supports reparse point */
+#define VFSFT_ZEROCOPY_SUPPORTED 0x100000200
+ /* Support loaning /returning cache buffer */
+/*
+ * Argument structure for mount(2).
+ *
+ * Flags are defined in <sys/mount.h>.
+ *
+ * Note that if the MS_SYSSPACE bit is set in flags, the pointer fields in
+ * this structure are to be interpreted as kernel addresses. File systems
+ * should be prepared for this possibility.
+ */
+struct mounta {
+ char *spec;
+ char *dir;
+ int flags;
+ char *fstype;
+ char *dataptr;
+ int datalen;
+ char *optptr;
+ int optlen;
+};
+
+/*
+ * Reasons for calling the vfs_mountroot() operation.
+ */
+enum whymountroot { ROOT_INIT, ROOT_REMOUNT, ROOT_UNMOUNT};
+typedef enum whymountroot whymountroot_t;
+
+/*
+ * Reasons for calling the VFS_VNSTATE():
+ */
+enum vntrans {
+ VNTRANS_EXISTS,
+ VNTRANS_IDLED,
+ VNTRANS_RECLAIMED,
+ VNTRANS_DESTROYED
+};
+typedef enum vntrans vntrans_t;
+
+/*
+ * VFS_OPS defines all the vfs operations. It is used to define
+ * the vfsops structure (below) and the fs_func_p union (vfs_opreg.h).
+ */
+#define VFS_OPS \
+ int (*vfs_mount)(vfs_t *, vnode_t *, struct mounta *, cred_t *); \
+ int (*vfs_unmount)(vfs_t *, int, cred_t *); \
+ int (*vfs_root)(vfs_t *, vnode_t **); \
+ int (*vfs_statvfs)(vfs_t *, statvfs64_t *); \
+ int (*vfs_sync)(vfs_t *, short, cred_t *); \
+ int (*vfs_vget)(vfs_t *, vnode_t **, fid_t *); \
+ int (*vfs_mountroot)(vfs_t *, enum whymountroot); \
+ void (*vfs_freevfs)(vfs_t *); \
+ int (*vfs_vnstate)(vfs_t *, vnode_t *, vntrans_t) /* NB: No ";" */
+
+/*
+ * Operations supported on virtual file system.
+ */
+struct vfsops {
+ VFS_OPS; /* Signature of all vfs operations (vfsops) */
+};
+
+extern int fsop_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
+extern int fsop_unmount(vfs_t *, int, cred_t *);
+extern int fsop_root(vfs_t *, vnode_t **);
+extern int fsop_statfs(vfs_t *, statvfs64_t *);
+extern int fsop_sync(vfs_t *, short, cred_t *);
+extern int fsop_vget(vfs_t *, vnode_t **, fid_t *);
+extern int fsop_mountroot(vfs_t *, enum whymountroot);
+extern void fsop_freefs(vfs_t *);
+extern int fsop_sync_by_kind(int, short, cred_t *);
+extern int fsop_vnstate(vfs_t *, vnode_t *, vntrans_t);
+
+#define VFS_MOUNT(vfsp, mvp, uap, cr) fsop_mount(vfsp, mvp, uap, cr)
+#define VFS_UNMOUNT(vfsp, flag, cr) fsop_unmount(vfsp, flag, cr)
+#define VFS_ROOT(vfsp, vpp) fsop_root(vfsp, vpp)
+#define VFS_STATVFS(vfsp, sp) fsop_statfs(vfsp, sp)
+#define VFS_SYNC(vfsp, flag, cr) fsop_sync(vfsp, flag, cr)
+#define VFS_VGET(vfsp, vpp, fidp) fsop_vget(vfsp, vpp, fidp)
+#define VFS_MOUNTROOT(vfsp, init) fsop_mountroot(vfsp, init)
+#define VFS_FREEVFS(vfsp) fsop_freefs(vfsp)
+#define VFS_VNSTATE(vfsp, vn, ns) fsop_vnstate(vfsp, vn, ns)
+
+#define VFSNAME_MOUNT "mount"
+#define VFSNAME_UNMOUNT "unmount"
+#define VFSNAME_ROOT "root"
+#define VFSNAME_STATVFS "statvfs"
+#define VFSNAME_SYNC "sync"
+#define VFSNAME_VGET "vget"
+#define VFSNAME_MOUNTROOT "mountroot"
+#define VFSNAME_FREEVFS "freevfs"
+#define VFSNAME_VNSTATE "vnstate"
+/*
+ * Filesystem type switch table.
+ */
+
+typedef struct vfssw {
+ char *vsw_name; /* type name -- max len _ST_FSTYPSZ */
+ int (*vsw_init) (int, char *);
+ /* init routine (for non-loadable fs only) */
+ int vsw_flag; /* flags */
+ mntopts_t vsw_optproto; /* mount options table prototype */
+ uint_t vsw_count; /* count of references */
+ kmutex_t vsw_lock; /* lock to protect vsw_count */
+ vfsops_t vsw_vfsops; /* filesystem operations vector */
+} vfssw_t;
+
+/*
+ * Filesystem type definition record. All file systems must export a record
+ * of this type through their modlfs structure. N.B., changing the version
+ * number requires a change in sys/modctl.h.
+ */
+
+typedef struct vfsdef_v5 {
+ int def_version; /* structure version, must be first */
+ char *name; /* filesystem type name */
+ int (*init) (int, char *); /* init routine */
+ int flags; /* filesystem flags */
+ mntopts_t *optproto; /* mount options table prototype */
+} vfsdef_v5;
+
+typedef struct vfsdef_v5 vfsdef_t;
+
+enum {
+ VFSDEF_VERSION = 5
+};
+
+/* Specific to libfksmbfs */
+int fake_installfs(vfsdef_t *);
+int fake_removefs(vfsdef_t *);
+
+/*
+ * flags for vfssw and vfsdef
+ */
+#define VSW_HASPROTO 0x01 /* struct has a mount options prototype */
+#define VSW_CANRWRO 0x02 /* file system can transition from rw to ro */
+#define VSW_CANREMOUNT 0x04 /* file system supports remounts */
+#define VSW_NOTZONESAFE 0x08 /* zone_enter(2) should fail for these files */
+#define VSW_VOLATILEDEV 0x10 /* vfs_dev can change each time fs is mounted */
+#define VSW_STATS 0x20 /* file system can collect stats */
+#define VSW_XID 0x40 /* file system supports extended ids */
+#define VSW_CANLOFI 0x80 /* file system supports lofi mounts */
+#define VSW_ZMOUNT 0x100 /* file system always allowed in a zone */
+#define VSW_MOUNTDEV 0x200 /* file system is mounted via device path */
+
+#define VSW_INSTALLED 0x8000 /* this vsw is associated with a file system */
+
+/*
+ * A flag for vfs_setpath().
+ */
+#define VFSSP_VERBATIM 0x1 /* do not prefix the supplied path */
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * Private vfs data, NOT to be used by a file system implementation.
+ */
+
+#define VFS_FEATURE_MAXSZ 4
+
+typedef struct vfs_impl {
+ /* Counted array - Bitmap of vfs features */
+ uint32_t vi_featureset[VFS_FEATURE_MAXSZ];
+ /*
+ * Support for statistics on the vnode operations
+ */
+ vsk_anchor_t *vi_vskap; /* anchor for vopstats' kstat */
+ vopstats_t *vi_fstypevsp; /* ptr to per-fstype vopstats */
+ vopstats_t vi_vopstats; /* per-mount vnode op stats */
+
+ timespec_t vi_hrctime; /* High-res creation time */
+
+ zone_ref_t vi_zone_ref; /* reference to zone */
+} vfs_impl_t;
+
+/*
+ * Public operations.
+ */
+struct umounta;
+struct statvfsa;
+struct fstatvfsa;
+
+void vfs_freevfsops(vfsops_t *);
+int vfs_freevfsops_by_type(int);
+void vfs_setops(vfs_t *, vfsops_t *);
+vfsops_t *vfs_getops(vfs_t *vfsp);
+int vfs_matchops(vfs_t *, vfsops_t *);
+int vfs_can_sync(vfs_t *vfsp);
+vfs_t *vfs_alloc(int);
+void vfs_free(vfs_t *);
+void vfs_init(vfs_t *vfsp, vfsops_t *, void *);
+void vfsimpl_setup(vfs_t *vfsp);
+void vfsimpl_teardown(vfs_t *vfsp);
+void vn_exists(vnode_t *);
+void vn_idle(vnode_t *);
+void vn_reclaim(vnode_t *);
+void vn_invalid(vnode_t *);
+
+int rootconf(void);
+int domount(char *, struct mounta *, vnode_t *, struct cred *,
+ struct vfs **);
+int dounmount(struct vfs *, int, cred_t *);
+int vfs_lock(struct vfs *);
+int vfs_rlock(struct vfs *);
+void vfs_lock_wait(struct vfs *);
+void vfs_rlock_wait(struct vfs *);
+void vfs_unlock(struct vfs *);
+int vfs_lock_held(struct vfs *);
+struct _kthread *vfs_lock_owner(struct vfs *);
+void sync(void);
+void vfs_sync(int);
+void vfs_mountroot(void);
+void vfs_add(vnode_t *, struct vfs *, int);
+void vfs_remove(struct vfs *);
+
+/* VFS feature routines */
+void vfs_set_feature(vfs_t *, vfs_feature_t);
+void vfs_clear_feature(vfs_t *, vfs_feature_t);
+int vfs_has_feature(vfs_t *, vfs_feature_t);
+void vfs_propagate_features(vfs_t *, vfs_t *);
+
+/* The following functions are not for general use by filesystems */
+
+void vfs_createopttbl(mntopts_t *, const char *);
+void vfs_copyopttbl(const mntopts_t *, mntopts_t *);
+void vfs_mergeopttbl(const mntopts_t *, const mntopts_t *, mntopts_t *);
+void vfs_freeopttbl(mntopts_t *);
+void vfs_parsemntopts(mntopts_t *, char *, int);
+int vfs_buildoptionstr(const mntopts_t *, char *, int);
+struct mntopt *vfs_hasopt(const mntopts_t *, const char *);
+void vfs_mnttab_modtimeupd(void);
+
+void vfs_clearmntopt(struct vfs *, const char *);
+void vfs_setmntopt(struct vfs *, const char *, const char *, int);
+void vfs_setresource(struct vfs *, const char *, uint32_t);
+void vfs_setmntpoint(struct vfs *, const char *, uint32_t);
+refstr_t *vfs_getresource(const struct vfs *);
+refstr_t *vfs_getmntpoint(const struct vfs *);
+int vfs_optionisset(const struct vfs *, const char *, char **);
+int vfs_settag(uint_t, uint_t, const char *, const char *, cred_t *);
+int vfs_clrtag(uint_t, uint_t, const char *, const char *, cred_t *);
+void vfs_syncall(void);
+void vfsinit(void);
+void vfs_unmountall(void);
+void vfs_make_fsid(fsid_t *, dev_t, int);
+void vfs_addmip(dev_t, struct vfs *);
+void vfs_delmip(struct vfs *);
+int vfs_devismounted(dev_t);
+int vfs_devmounting(dev_t, struct vfs *);
+int vfs_opsinuse(vfsops_t *);
+struct vfs *getvfs(fsid_t *);
+struct vfs *vfs_dev2vfsp(dev_t);
+struct vfs *vfs_mntpoint2vfsp(const char *);
+struct vfssw *allocate_vfssw(const char *);
+struct vfssw *vfs_getvfssw(const char *);
+struct vfssw *vfs_getvfsswbyname(const char *);
+struct vfssw *vfs_getvfsswbyvfsops(vfsops_t *);
+void vfs_refvfssw(struct vfssw *);
+void vfs_unrefvfssw(struct vfssw *);
+uint_t vf_to_stf(uint_t);
+void vfs_mnttab_modtime(timespec_t *);
+void vfs_mnttab_poll(timespec_t *, struct pollhead **);
+
+void vfs_list_lock(void);
+void vfs_list_read_lock(void);
+void vfs_list_unlock(void);
+void vfs_list_add(struct vfs *);
+void vfs_list_remove(struct vfs *);
+void vfs_hold(vfs_t *vfsp);
+void vfs_rele(vfs_t *vfsp);
+void fs_freevfs(vfs_t *);
+void vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype);
+
+int vfs_zone_change_safe(vfs_t *);
+
+int vfs_get_lofi(vfs_t *, vnode_t **);
+
+#define VFSHASH(maj, min) (((int)((maj)+(min))) & (vfshsz - 1))
+#define VFS_ON_LIST(vfsp) \
+ ((vfsp)->vfs_next != (vfsp) && (vfsp)->vfs_next != NULL)
+
+/*
+ * Globals.
+ */
+
+extern struct vfssw vfssw[]; /* table of filesystem types */
+extern krwlock_t vfssw_lock;
+extern char rootfstype[]; /* name of root fstype */
+extern const int nfstype; /* # of elements in vfssw array */
+extern vfsops_t *EIO_vfsops; /* operations for vfs being torn-down */
+
+/*
+ * The following variables are private to the the kernel's vfs layer. File
+ * system implementations should not access them.
+ */
+extern struct vfs *rootvfs; /* ptr to root vfs structure */
+typedef struct {
+ struct vfs *rvfs_head; /* head vfs in chain */
+ kmutex_t rvfs_lock; /* mutex protecting this chain */
+ uint32_t rvfs_len; /* length of this chain */
+} rvfs_t;
+extern rvfs_t *rvfs_list;
+extern int vfshsz; /* # of elements in rvfs_head array */
+extern const mntopts_t vfs_mntopts; /* globally recognized options */
+
+#endif /* defined(_KERNEL) */
+
+#define VFS_HOLD(vfsp) { \
+ vfs_hold(vfsp); \
+}
+
+#define VFS_RELE(vfsp) { \
+ vfs_rele(vfsp); \
+}
+
+#define VFS_INIT(vfsp, op, data) { \
+ vfs_init((vfsp), (op), (data)); \
+}
+
+
+#define VFS_INSTALLED(vfsswp) (((vfsswp)->vsw_flag & VSW_INSTALLED) != 0)
+#define ALLOCATED_VFSSW(vswp) ((vswp)->vsw_name[0] != '\0')
+#define RLOCK_VFSSW() (rw_enter(&vfssw_lock, RW_READER))
+#define RUNLOCK_VFSSW() (rw_exit(&vfssw_lock))
+#define WLOCK_VFSSW() (rw_enter(&vfssw_lock, RW_WRITER))
+#define WUNLOCK_VFSSW() (rw_exit(&vfssw_lock))
+#define VFSSW_LOCKED() (RW_LOCK_HELD(&vfssw_lock))
+#define VFSSW_WRITE_LOCKED() (RW_WRITE_HELD(&vfssw_lock))
+/*
+ * VFS_SYNC flags.
+ */
+#define SYNC_ATTR 0x01 /* sync attributes only */
+#define SYNC_CLOSE 0x02 /* close open file */
+#define SYNC_ALL 0x04 /* force to sync all fs */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VFS_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h
new file mode 100644
index 0000000000..cdb6c9c6c5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vfs_opreg.h
@@ -0,0 +1,116 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_VFS_OPREG_H
+#define _SYS_VFS_OPREG_H
+
+#include <sys/vfs.h>
+#include <sys/fem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * The following union allows us to use C99's "designated initializer"
+ * feature so that we can have strong typechecking for the operations
+ * used in the the fs_operation_def structures.
+ */
+
+typedef union fs_func {
+ fs_generic_func_p fs_generic; /* Generic function signature */
+ int (*error)(); /* Signature of error function */
+ VFS_OPS; /* Signatures of all vfs operations (vfsops) */
+ VNODE_OPS; /* Signatures of all vnode operations (vops) */
+ FEM_OPS; /* Signatures of all FEM operations (femops) */
+ FSEM_OPS; /* Signatures of all FSEM ops (fsemops) */
+} fs_func_p;
+
+/*
+ * File systems use arrays of fs_operation_def structures to form
+ * name/value pairs of operations. These arrays get passed to:
+ *
+ * - vn_make_ops() to create vnodeops
+ * - vfs_makefsops()/vfs_setfsops() to create vfsops.
+ */
+typedef struct fs_operation_def {
+ char *name; /* name of operation (NULL at end) */
+ fs_func_p func; /* function implementing operation */
+} fs_operation_def_t;
+
+/*
+ * The operation registration mechanism uses two master tables of operations:
+ * one for vnode operations (vn_ops_table[]) and one for vfs operations
+ * (vfs_ops_table[]). These tables are arrays of fs_operation_trans_def
+ * structures. They contain all of the information necessary for the system
+ * to populate an operations structure (e.g., vnodeops, vfsops).
+ *
+ * File systems call registration routines (vfs_setfsops(), vfs_makefsops(),
+ * and vn_make_ops()) and pass in their operations specification tables
+ * (arrays of fs_operation_def structures). These routines use the master
+ * table(s) of operations to build a vnodeops or vfsops structure.
+ */
+typedef struct fs_operation_trans_def {
+ char *name; /* name of operation (NULL at end) */
+ int offset; /* byte offset within ops vector */
+ fs_generic_func_p defaultFunc; /* default function */
+ fs_generic_func_p errorFunc; /* error function */
+} fs_operation_trans_def_t;
+
+/*
+ * Generic operations vector types (used for vfs/vnode ops registration).
+ */
+
+extern int fs_default(); /* "default" function placeholder */
+extern int fs_error(); /* "error" function placeholder */
+
+int fs_build_vector(void *vector, int *unused_ops,
+ const fs_operation_trans_def_t *translation,
+ const fs_operation_def_t *operations);
+
+/*
+ * Public operations.
+ */
+
+int vn_make_ops(const char *, const struct fs_operation_def *,
+ vnodeops_t **);
+void vn_freevnodeops(vnodeops_t *);
+
+int vfs_setfsops(int, const fs_operation_def_t *, vfsops_t **);
+int vfs_makefsops(const fs_operation_def_t *, vfsops_t **);
+void vfs_freevfsops(vfsops_t *);
+int vfs_freevfsops_by_type(int);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VFS_OPREG_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h b/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h
new file mode 100644
index 0000000000..33e84e68f2
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/sys/vnode.h
@@ -0,0 +1,1452 @@
+/*
+ * 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef _SYS_VNODE_H
+#define _SYS_VNODE_H
+
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/time_impl.h>
+#include <sys/cred.h>
+#include <sys/uio.h>
+#include <sys/resource.h>
+#include <vm/seg_enum.h>
+#include <sys/kstat.h>
+#include <sys/kmem.h>
+#include <sys/list.h>
+#include <sys/avl.h>
+#ifdef _KERNEL
+#include <sys/rwstlock.h>
+#include <sys/buf.h>
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * Statistics for all vnode operations.
+ * All operations record number of ops (since boot/mount/zero'ed).
+ * Certain I/O operations (read, write, readdir) also record number
+ * of bytes transferred.
+ * This appears in two places in the system: one is embedded in each
+ * vfs_t. There is also an array of vopstats_t structures allocated
+ * on a per-fstype basis.
+ */
+
+#define VOPSTATS_STR "vopstats_" /* Initial string for vopstat kstats */
+
+typedef struct vopstats {
+ kstat_named_t nopen; /* VOP_OPEN */
+ kstat_named_t nclose; /* VOP_CLOSE */
+ kstat_named_t nread; /* VOP_READ */
+ kstat_named_t read_bytes;
+ kstat_named_t nwrite; /* VOP_WRITE */
+ kstat_named_t write_bytes;
+ kstat_named_t nioctl; /* VOP_IOCTL */
+ kstat_named_t nsetfl; /* VOP_SETFL */
+ kstat_named_t ngetattr; /* VOP_GETATTR */
+ kstat_named_t nsetattr; /* VOP_SETATTR */
+ kstat_named_t naccess; /* VOP_ACCESS */
+ kstat_named_t nlookup; /* VOP_LOOKUP */
+ kstat_named_t ncreate; /* VOP_CREATE */
+ kstat_named_t nremove; /* VOP_REMOVE */
+ kstat_named_t nlink; /* VOP_LINK */
+ kstat_named_t nrename; /* VOP_RENAME */
+ kstat_named_t nmkdir; /* VOP_MKDIR */
+ kstat_named_t nrmdir; /* VOP_RMDIR */
+ kstat_named_t nreaddir; /* VOP_READDIR */
+ kstat_named_t readdir_bytes;
+ kstat_named_t nsymlink; /* VOP_SYMLINK */
+ kstat_named_t nreadlink; /* VOP_READLINK */
+ kstat_named_t nfsync; /* VOP_FSYNC */
+ kstat_named_t ninactive; /* VOP_INACTIVE */
+ kstat_named_t nfid; /* VOP_FID */
+ kstat_named_t nrwlock; /* VOP_RWLOCK */
+ kstat_named_t nrwunlock; /* VOP_RWUNLOCK */
+ kstat_named_t nseek; /* VOP_SEEK */
+ kstat_named_t ncmp; /* VOP_CMP */
+ kstat_named_t nfrlock; /* VOP_FRLOCK */
+ kstat_named_t nspace; /* VOP_SPACE */
+ kstat_named_t nrealvp; /* VOP_REALVP */
+ kstat_named_t ngetpage; /* VOP_GETPAGE */
+ kstat_named_t nputpage; /* VOP_PUTPAGE */
+ kstat_named_t nmap; /* VOP_MAP */
+ kstat_named_t naddmap; /* VOP_ADDMAP */
+ kstat_named_t ndelmap; /* VOP_DELMAP */
+ kstat_named_t npoll; /* VOP_POLL */
+ kstat_named_t ndump; /* VOP_DUMP */
+ kstat_named_t npathconf; /* VOP_PATHCONF */
+ kstat_named_t npageio; /* VOP_PAGEIO */
+ kstat_named_t ndumpctl; /* VOP_DUMPCTL */
+ kstat_named_t ndispose; /* VOP_DISPOSE */
+ kstat_named_t nsetsecattr; /* VOP_SETSECATTR */
+ kstat_named_t ngetsecattr; /* VOP_GETSECATTR */
+ kstat_named_t nshrlock; /* VOP_SHRLOCK */
+ kstat_named_t nvnevent; /* VOP_VNEVENT */
+ kstat_named_t nreqzcbuf; /* VOP_REQZCBUF */
+ kstat_named_t nretzcbuf; /* VOP_RETZCBUF */
+} vopstats_t;
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * The vnode is the focus of all file activity in UNIX.
+ * A vnode is allocated for each active file, each current
+ * directory, each mounted-on file, and the root.
+ *
+ * Each vnode is usually associated with a file-system-specific node (for
+ * UFS, this is the in-memory inode). Generally, a vnode and an fs-node
+ * should be created and destroyed together as a pair.
+ *
+ * If a vnode is reused for a new file, it should be reinitialized by calling
+ * either vn_reinit() or vn_recycle().
+ *
+ * vn_reinit() resets the entire vnode as if it was returned by vn_alloc().
+ * The caller is responsible for setting up the entire vnode after calling
+ * vn_reinit(). This is important when using kmem caching where the vnode is
+ * allocated by a constructor, for instance.
+ *
+ * vn_recycle() is used when the file system keeps some state around in both
+ * the vnode and the associated FS-node. In UFS, for example, the inode of
+ * a deleted file can be reused immediately. The v_data, v_vfsp, v_op, etc.
+ * remains the same but certain fields related to the previous instance need
+ * to be reset. In particular:
+ * v_femhead
+ * v_path
+ * v_rdcnt, v_wrcnt
+ * v_mmap_read, v_mmap_write
+ */
+
+/*
+ * vnode types. VNON means no type. These values are unrelated to
+ * values in on-disk inodes.
+ */
+typedef enum vtype {
+ VNON = 0,
+ VREG = 1,
+ VDIR = 2,
+ VBLK = 3,
+ VCHR = 4,
+ VLNK = 5,
+ VFIFO = 6,
+ VDOOR = 7,
+ VPROC = 8,
+ VSOCK = 9,
+ VPORT = 10,
+ VBAD = 11
+} vtype_t;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VSD - Vnode Specific Data
+ * Used to associate additional private data with a vnode.
+ */
+struct vsd_node {
+ list_node_t vs_nodes; /* list of all VSD nodes */
+ uint_t vs_nkeys; /* entries in value array */
+ void **vs_value; /* array of value/key */
+};
+
+/*
+ * Many of the fields in the vnode are read-only once they are initialized
+ * at vnode creation time. Other fields are protected by locks.
+ *
+ * IMPORTANT: vnodes should be created ONLY by calls to vn_alloc(). They
+ * may not be embedded into the file-system specific node (inode). The
+ * size of vnodes may change.
+ *
+ * The v_lock protects:
+ * v_flag
+ * v_stream
+ * v_count
+ * v_shrlocks
+ * v_path
+ * v_vsd
+ * v_xattrdir
+ *
+ * A special lock (implemented by vn_vfswlock in vnode.c) protects:
+ * v_vfsmountedhere
+ *
+ * The global flock_lock mutex (in flock.c) protects:
+ * v_filocks
+ *
+ * IMPORTANT NOTE:
+ *
+ * The following vnode fields are considered public and may safely be
+ * accessed by file systems or other consumers:
+ *
+ * v_lock
+ * v_flag
+ * v_count
+ * v_data
+ * v_vfsp
+ * v_stream
+ * v_type
+ * v_rdev
+ *
+ * ALL OTHER FIELDS SHOULD BE ACCESSED ONLY BY THE OWNER OF THAT FIELD.
+ * In particular, file systems should not access other fields; they may
+ * change or even be removed. The functionality which was once provided
+ * by these fields is available through vn_* functions.
+ */
+
+struct fem_head; /* from fem.h */
+
+typedef struct vnode {
+ kmutex_t v_lock; /* protects vnode fields */
+ uint_t v_flag; /* vnode flags (see below) */
+ uint_t v_count; /* reference count */
+ void *v_data; /* private data for fs */
+ struct vfs *v_vfsp; /* ptr to containing VFS */
+ struct stdata *v_stream; /* associated stream */
+ enum vtype v_type; /* vnode type */
+ dev_t v_rdev; /* device (VCHR, VBLK) */
+
+ /* PRIVATE FIELDS BELOW - DO NOT USE */
+
+ struct vfs *v_vfsmountedhere; /* ptr to vfs mounted here */
+ struct vnodeops *v_op; /* vnode operations */
+ krwlock_t v_nbllock; /* sync for NBMAND locks */
+ char *v_path; /* cached path */
+ uint_t v_rdcnt; /* open for read count (VREG only) */
+ uint_t v_wrcnt; /* open for write count (VREG only) */
+ struct vnode *v_xattrdir; /* unnamed extended attr dir (GFS) */
+
+ /* Private to the fake vnode impl. */
+
+ int v_fd;
+ dev_t v_st_dev;
+ ino_t v_st_ino;
+ avl_node_t v_avl_node;
+ int v_vfsrlocks;
+} vnode_t;
+
+#define IS_DEVVP(vp) \
+ ((vp)->v_type == VCHR || (vp)->v_type == VBLK || (vp)->v_type == VFIFO)
+
+#define VNODE_ALIGN 16
+
+/*
+ * vnode flags.
+ */
+#define VROOT 0x01 /* root of its file system */
+#define VNOCACHE 0x02 /* don't keep cache pages on vnode */
+#define VNOMAP 0x04 /* file cannot be mapped/faulted */
+#define VDUP 0x08 /* file should be dup'ed rather then opened */
+#define VNOSWAP 0x10 /* file cannot be used as virtual swap device */
+#define VNOMOUNT 0x20 /* file cannot be covered by mount */
+#define VISSWAP 0x40 /* vnode is being used for swap */
+#define VSWAPLIKE 0x80 /* vnode acts like swap (but may not be) */
+
+#define IS_SWAPVP(vp) (((vp)->v_flag & (VISSWAP | VSWAPLIKE)) != 0)
+
+#else // defined(_KERNEL) || defined(_FAKE_KERNEL)
+typedef struct vnode vnode_t;
+#endif // defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+#if defined(_KERNEL)
+typedef struct vn_vfslocks_entry {
+ rwstlock_t ve_lock;
+ void *ve_vpvfs;
+ struct vn_vfslocks_entry *ve_next;
+ uint32_t ve_refcnt;
+ char pad[64 - sizeof (rwstlock_t) - 2 * sizeof (void *) - \
+ sizeof (uint32_t)];
+} vn_vfslocks_entry_t;
+#endif /* _KERNEL */
+
+/*
+ * The following two flags are used to lock the v_vfsmountedhere field
+ */
+#define VVFSLOCK 0x100
+#define VVFSWAIT 0x200
+
+/*
+ * Used to serialize VM operations on a vnode
+ */
+#define VVMLOCK 0x400
+
+/*
+ * Tell vn_open() not to fail a directory open for writing but
+ * to go ahead and call VOP_OPEN() to let the filesystem check.
+ */
+#define VDIROPEN 0x800
+
+/*
+ * Flag to let the VM system know that this file is most likely a binary
+ * or shared library since it has been mmap()ed EXEC at some time.
+ */
+#define VVMEXEC 0x1000
+
+#define VPXFS 0x2000 /* clustering: global fs proxy vnode */
+
+#define IS_PXFSVP(vp) ((vp)->v_flag & VPXFS)
+
+#define V_XATTRDIR 0x4000 /* attribute unnamed directory */
+
+#define IS_XATTRDIR(vp) ((vp)->v_flag & V_XATTRDIR)
+
+#define V_LOCALITY 0x8000 /* whether locality aware */
+
+/*
+ * Flag that indicates the VM should maintain the v_pages list with all modified
+ * pages on one end and unmodified pages at the other. This makes finding dirty
+ * pages to write back to disk much faster at the expense of taking a minor
+ * fault on the first store instruction which touches a writable page.
+ */
+#define VMODSORT (0x10000)
+#define IS_VMODSORT(vp) \
+ (pvn_vmodsort_supported != 0 && ((vp)->v_flag & VMODSORT) != 0)
+
+#define VISSWAPFS 0x20000 /* vnode is being used for swapfs */
+
+/*
+ * The mdb memstat command assumes that IS_SWAPFSVP only uses the
+ * vnode's v_flag field. If this changes, cache the additional
+ * fields in mdb; see vn_get in mdb/common/modules/genunix/memory.c
+ */
+#define IS_SWAPFSVP(vp) (((vp)->v_flag & VISSWAPFS) != 0)
+
+#define V_SYSATTR 0x40000 /* vnode is a GFS system attribute */
+
+/*
+ * Vnode attributes. A bit-mask is supplied as part of the
+ * structure to indicate the attributes the caller wants to
+ * set (setattr) or extract (getattr).
+ */
+
+/*
+ * Note that va_nodeid and va_nblocks are 64bit data type.
+ * We support large files over NFSV3. With Solaris client and
+ * Server that generates 64bit ino's and sizes these fields
+ * will overflow if they are 32 bit sizes.
+ */
+
+typedef struct vattr {
+ uint_t va_mask; /* bit-mask of attributes */
+ vtype_t va_type; /* vnode type (for create) */
+ mode_t va_mode; /* file access mode */
+ uid_t va_uid; /* owner user id */
+ gid_t va_gid; /* owner group id */
+ dev_t va_fsid; /* file system id (dev for now) */
+ u_longlong_t va_nodeid; /* node id */
+ nlink_t va_nlink; /* number of references to file */
+ u_offset_t va_size; /* file size in bytes */
+ timestruc_t va_atime; /* time of last access */
+ timestruc_t va_mtime; /* time of last modification */
+ timestruc_t va_ctime; /* time of last status change */
+ dev_t va_rdev; /* device the file represents */
+ uint_t va_blksize; /* fundamental block size */
+ u_longlong_t va_nblocks; /* # of blocks allocated */
+ uint_t va_seq; /* sequence number */
+} vattr_t;
+
+#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
+
+/*
+ * Structure of all optional attributes.
+ */
+typedef struct xoptattr {
+ timestruc_t xoa_createtime; /* Create time of file */
+ uint8_t xoa_archive;
+ uint8_t xoa_system;
+ uint8_t xoa_readonly;
+ uint8_t xoa_hidden;
+ uint8_t xoa_nounlink;
+ uint8_t xoa_immutable;
+ uint8_t xoa_appendonly;
+ uint8_t xoa_nodump;
+ uint8_t xoa_opaque;
+ uint8_t xoa_av_quarantined;
+ uint8_t xoa_av_modified;
+ uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+ uint8_t xoa_reparse;
+ uint64_t xoa_generation;
+ uint8_t xoa_offline;
+ uint8_t xoa_sparse;
+} xoptattr_t;
+
+/*
+ * The xvattr structure is really a variable length structure that
+ * is made up of:
+ * - The classic vattr_t (xva_vattr)
+ * - a 32 bit quantity (xva_mapsize) that specifies the size of the
+ * attribute bitmaps in 32 bit words.
+ * - A pointer to the returned attribute bitmap (needed because the
+ * previous element, the requested attribute bitmap) is variable lenth.
+ * - The requested attribute bitmap, which is an array of 32 bit words.
+ * Callers use the XVA_SET_REQ() macro to set the bits corresponding to
+ * the attributes that are being requested.
+ * - The returned attribute bitmap, which is an array of 32 bit words.
+ * File systems that support optional attributes use the XVA_SET_RTN()
+ * macro to set the bits corresponding to the attributes that are being
+ * returned.
+ * - The xoptattr_t structure which contains the attribute values
+ *
+ * xva_mapsize determines how many words in the attribute bitmaps.
+ * Immediately following the attribute bitmaps is the xoptattr_t.
+ * xva_getxoptattr() is used to get the pointer to the xoptattr_t
+ * section.
+ */
+
+#define XVA_MAPSIZE 3 /* Size of attr bitmaps */
+#define XVA_MAGIC 0x78766174 /* Magic # for verification */
+
+/*
+ * The xvattr structure is an extensible structure which permits optional
+ * attributes to be requested/returned. File systems may or may not support
+ * optional attributes. They do so at their own discretion but if they do
+ * support optional attributes, they must register the VFSFT_XVATTR feature
+ * so that the optional attributes can be set/retrived.
+ *
+ * The fields of the xvattr structure are:
+ *
+ * xva_vattr - The first element of an xvattr is a legacy vattr structure
+ * which includes the common attributes. If AT_XVATTR is set in the va_mask
+ * then the entire structure is treated as an xvattr. If AT_XVATTR is not
+ * set, then only the xva_vattr structure can be used.
+ *
+ * xva_magic - 0x78766174 (hex for "xvat"). Magic number for verification.
+ *
+ * xva_mapsize - Size of requested and returned attribute bitmaps.
+ *
+ * xva_rtnattrmapp - Pointer to xva_rtnattrmap[]. We need this since the
+ * size of the array before it, xva_reqattrmap[], could change which means
+ * the location of xva_rtnattrmap[] could change. This will allow unbundled
+ * file systems to find the location of xva_rtnattrmap[] when the sizes change.
+ *
+ * xva_reqattrmap[] - Array of requested attributes. Attributes are
+ * represented by a specific bit in a specific element of the attribute
+ * map array. Callers set the bits corresponding to the attributes
+ * that the caller wants to get/set.
+ *
+ * xva_rtnattrmap[] - Array of attributes that the file system was able to
+ * process. Not all file systems support all optional attributes. This map
+ * informs the caller which attributes the underlying file system was able
+ * to set/get. (Same structure as the requested attributes array in terms
+ * of each attribute corresponding to specific bits and array elements.)
+ *
+ * xva_xoptattrs - Structure containing values of optional attributes.
+ * These values are only valid if the corresponding bits in xva_reqattrmap
+ * are set and the underlying file system supports those attributes.
+ */
+typedef struct xvattr {
+ vattr_t xva_vattr; /* Embedded vattr structure */
+ uint32_t xva_magic; /* Magic Number */
+ uint32_t xva_mapsize; /* Size of attr bitmap (32-bit words) */
+ uint32_t *xva_rtnattrmapp; /* Ptr to xva_rtnattrmap[] */
+ uint32_t xva_reqattrmap[XVA_MAPSIZE]; /* Requested attrs */
+ uint32_t xva_rtnattrmap[XVA_MAPSIZE]; /* Returned attrs */
+ xoptattr_t xva_xoptattrs; /* Optional attributes */
+} xvattr_t;
+
+#ifdef _SYSCALL32
+/*
+ * For bigtypes time_t changed to 64 bit on the 64-bit kernel.
+ * Define an old version for user/kernel interface
+ */
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct vattr32 {
+ uint32_t va_mask; /* bit-mask of attributes */
+ vtype_t va_type; /* vnode type (for create) */
+ mode32_t va_mode; /* file access mode */
+ uid32_t va_uid; /* owner user id */
+ gid32_t va_gid; /* owner group id */
+ dev32_t va_fsid; /* file system id (dev for now) */
+ u_longlong_t va_nodeid; /* node id */
+ nlink_t va_nlink; /* number of references to file */
+ u_offset_t va_size; /* file size in bytes */
+ timestruc32_t va_atime; /* time of last access */
+ timestruc32_t va_mtime; /* time of last modification */
+ timestruc32_t va_ctime; /* time of last status change */
+ dev32_t va_rdev; /* device the file represents */
+ uint32_t va_blksize; /* fundamental block size */
+ u_longlong_t va_nblocks; /* # of blocks allocated */
+ uint32_t va_seq; /* sequence number */
+} vattr32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+#else /* not _SYSCALL32 */
+#define vattr32 vattr
+typedef vattr_t vattr32_t;
+#endif /* _SYSCALL32 */
+
+/*
+ * Attributes of interest to the caller of setattr or getattr.
+ */
+#define AT_TYPE 0x00001
+#define AT_MODE 0x00002
+#define AT_UID 0x00004
+#define AT_GID 0x00008
+#define AT_FSID 0x00010
+#define AT_NODEID 0x00020
+#define AT_NLINK 0x00040
+#define AT_SIZE 0x00080
+#define AT_ATIME 0x00100
+#define AT_MTIME 0x00200
+#define AT_CTIME 0x00400
+#define AT_RDEV 0x00800
+#define AT_BLKSIZE 0x01000
+#define AT_NBLOCKS 0x02000
+/* 0x04000 */ /* unused */
+#define AT_SEQ 0x08000
+/*
+ * If AT_XVATTR is set then there are additional bits to process in
+ * the xvattr_t's attribute bitmap. If this is not set then the bitmap
+ * MUST be ignored. Note that this bit must be set/cleared explicitly.
+ * That is, setting AT_ALL will NOT set AT_XVATTR.
+ */
+#define AT_XVATTR 0x10000
+
+#define AT_ALL (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|\
+ AT_NLINK|AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|\
+ AT_RDEV|AT_BLKSIZE|AT_NBLOCKS|AT_SEQ)
+
+#define AT_STAT (AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|AT_NLINK|\
+ AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|AT_RDEV|AT_TYPE)
+
+#define AT_TIMES (AT_ATIME|AT_MTIME|AT_CTIME)
+
+#define AT_NOSET (AT_NLINK|AT_RDEV|AT_FSID|AT_NODEID|AT_TYPE|\
+ AT_BLKSIZE|AT_NBLOCKS|AT_SEQ)
+
+/*
+ * Attribute bits used in the extensible attribute's (xva's) attribute
+ * bitmaps. Note that the bitmaps are made up of a variable length number
+ * of 32-bit words. The convention is to use XAT{n}_{attrname} where "n"
+ * is the element in the bitmap (starting at 1). This convention is for
+ * the convenience of the maintainer to keep track of which element each
+ * attribute belongs to.
+ *
+ * NOTE THAT CONSUMERS MUST *NOT* USE THE XATn_* DEFINES DIRECTLY. CONSUMERS
+ * MUST USE THE XAT_* DEFINES.
+ */
+#define XAT0_INDEX 0LL /* Index into bitmap for XAT0 attrs */
+#define XAT0_CREATETIME 0x00000001 /* Create time of file */
+#define XAT0_ARCHIVE 0x00000002 /* Archive */
+#define XAT0_SYSTEM 0x00000004 /* System */
+#define XAT0_READONLY 0x00000008 /* Readonly */
+#define XAT0_HIDDEN 0x00000010 /* Hidden */
+#define XAT0_NOUNLINK 0x00000020 /* Nounlink */
+#define XAT0_IMMUTABLE 0x00000040 /* immutable */
+#define XAT0_APPENDONLY 0x00000080 /* appendonly */
+#define XAT0_NODUMP 0x00000100 /* nodump */
+#define XAT0_OPAQUE 0x00000200 /* opaque */
+#define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */
+#define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */
+#define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */
+#define XAT0_REPARSE 0x00002000 /* FS reparse point */
+#define XAT0_GEN 0x00004000 /* object generation number */
+#define XAT0_OFFLINE 0x00008000 /* offline */
+#define XAT0_SPARSE 0x00010000 /* sparse */
+
+#define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
+ XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
+ XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| XAT0_AV_MODIFIED| \
+ XAT0_AV_SCANSTAMP|XAT0_REPARSE|XATO_GEN|XAT0_OFFLINE|XAT0_SPARSE)
+
+/* Support for XAT_* optional attributes */
+#define XVA_MASK 0xffffffff /* Used to mask off 32 bits */
+#define XVA_SHFT 32 /* Used to shift index */
+
+/*
+ * Used to pry out the index and attribute bits from the XAT_* attributes
+ * defined below. Note that we're masking things down to 32 bits then
+ * casting to uint32_t.
+ */
+#define XVA_INDEX(attr) ((uint32_t)(((attr) >> XVA_SHFT) & XVA_MASK))
+#define XVA_ATTRBIT(attr) ((uint32_t)((attr) & XVA_MASK))
+
+/*
+ * The following defines present a "flat namespace" so that consumers don't
+ * need to keep track of which element belongs to which bitmap entry.
+ *
+ * NOTE THAT THESE MUST NEVER BE OR-ed TOGETHER
+ */
+#define XAT_CREATETIME ((XAT0_INDEX << XVA_SHFT) | XAT0_CREATETIME)
+#define XAT_ARCHIVE ((XAT0_INDEX << XVA_SHFT) | XAT0_ARCHIVE)
+#define XAT_SYSTEM ((XAT0_INDEX << XVA_SHFT) | XAT0_SYSTEM)
+#define XAT_READONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_READONLY)
+#define XAT_HIDDEN ((XAT0_INDEX << XVA_SHFT) | XAT0_HIDDEN)
+#define XAT_NOUNLINK ((XAT0_INDEX << XVA_SHFT) | XAT0_NOUNLINK)
+#define XAT_IMMUTABLE ((XAT0_INDEX << XVA_SHFT) | XAT0_IMMUTABLE)
+#define XAT_APPENDONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_APPENDONLY)
+#define XAT_NODUMP ((XAT0_INDEX << XVA_SHFT) | XAT0_NODUMP)
+#define XAT_OPAQUE ((XAT0_INDEX << XVA_SHFT) | XAT0_OPAQUE)
+#define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED)
+#define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED)
+#define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
+#define XAT_REPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_REPARSE)
+#define XAT_GEN ((XAT0_INDEX << XVA_SHFT) | XAT0_GEN)
+#define XAT_OFFLINE ((XAT0_INDEX << XVA_SHFT) | XAT0_OFFLINE)
+#define XAT_SPARSE ((XAT0_INDEX << XVA_SHFT) | XAT0_SPARSE)
+
+/*
+ * The returned attribute map array (xva_rtnattrmap[]) is located past the
+ * requested attribute map array (xva_reqattrmap[]). Its location changes
+ * when the array sizes change. We use a separate pointer in a known location
+ * (xva_rtnattrmapp) to hold the location of xva_rtnattrmap[]. This is
+ * set in xva_init()
+ */
+#define XVA_RTNATTRMAP(xvap) ((xvap)->xva_rtnattrmapp)
+
+/*
+ * XVA_SET_REQ() sets an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define XVA_SET_REQ(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+/*
+ * XVA_CLR_REQ() clears an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define XVA_CLR_REQ(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] &= ~XVA_ATTRBIT(attr)
+
+/*
+ * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap
+ * of returned attributes (xva_rtnattrmap[]).
+ */
+#define XVA_SET_RTN(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+
+/*
+ * XVA_ISSET_REQ() checks the requested attribute bitmap (xva_reqattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_REQ(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((xvap)->xva_reqattrmap[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * XVA_ISSET_RTN() checks the returned attribute bitmap (xva_rtnattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_RTN(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * Modes. Some values same as S_xxx entries from stat.h for convenience.
+ */
+#define VSUID 04000 /* set user id on execution */
+#define VSGID 02000 /* set group id on execution */
+#define VSVTX 01000 /* save swapped text even after use */
+
+/*
+ * Permissions.
+ */
+#define VREAD 00400
+#define VWRITE 00200
+#define VEXEC 00100
+
+#define MODEMASK 07777 /* mode bits plus permission bits */
+#define PERMMASK 00777 /* permission bits */
+
+/*
+ * VOP_ACCESS flags
+ */
+#define V_ACE_MASK 0x1 /* mask represents NFSv4 ACE permissions */
+#define V_APPEND 0x2 /* want to do append only check */
+
+/*
+ * Check whether mandatory file locking is enabled.
+ */
+
+#define MANDMODE(mode) (((mode) & (VSGID|(VEXEC>>3))) == VSGID)
+#define MANDLOCK(vp, mode) ((vp)->v_type == VREG && MANDMODE(mode))
+
+/*
+ * Flags for vnode operations.
+ */
+enum rm { RMFILE, RMDIRECTORY }; /* rm or rmdir (remove) */
+enum symfollow { NO_FOLLOW, FOLLOW }; /* follow symlinks (or not) */
+enum vcexcl { NONEXCL, EXCL }; /* (non)excl create */
+enum create { CRCREAT, CRMKNOD, CRMKDIR }; /* reason for create */
+
+typedef enum rm rm_t;
+typedef enum symfollow symfollow_t;
+typedef enum vcexcl vcexcl_t;
+typedef enum create create_t;
+
+/* Vnode Events - Used by VOP_VNEVENT */
+typedef enum vnevent {
+ VE_SUPPORT = 0, /* Query */
+ VE_RENAME_SRC = 1, /* Rename, with vnode as source */
+ VE_RENAME_DEST = 2, /* Rename, with vnode as target/destination */
+ VE_REMOVE = 3, /* Remove of vnode's name */
+ VE_RMDIR = 4, /* Remove of directory vnode's name */
+ VE_CREATE = 5, /* Create with vnode's name which exists */
+ VE_LINK = 6, /* Link with vnode's name as source */
+ VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */
+ VE_MOUNTEDOVER = 8, /* File or Filesystem got mounted over vnode */
+ VE_TRUNCATE = 9 /* Truncate */
+} vnevent_t;
+
+/*
+ * Values for checking vnode open and map counts
+ */
+enum v_mode { V_READ, V_WRITE, V_RDORWR, V_RDANDWR };
+
+typedef enum v_mode v_mode_t;
+
+#define V_TRUE 1
+#define V_FALSE 0
+
+/*
+ * Structure used on VOP_GETSECATTR and VOP_SETSECATTR operations
+ */
+
+typedef struct vsecattr {
+ uint_t vsa_mask; /* See below */
+ int vsa_aclcnt; /* ACL entry count */
+ void *vsa_aclentp; /* pointer to ACL entries */
+ int vsa_dfaclcnt; /* default ACL entry count */
+ void *vsa_dfaclentp; /* pointer to default ACL entries */
+ size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
+ uint_t vsa_aclflags; /* ACE ACL flags */
+} vsecattr_t;
+
+/* vsa_mask values */
+#define VSA_ACL 0x0001
+#define VSA_ACLCNT 0x0002
+#define VSA_DFACL 0x0004
+#define VSA_DFACLCNT 0x0008
+#define VSA_ACE 0x0010
+#define VSA_ACECNT 0x0020
+#define VSA_ACE_ALLTYPES 0x0040
+#define VSA_ACE_ACLFLAGS 0x0080 /* get/set ACE ACL flags */
+
+/*
+ * Structure used by various vnode operations to determine
+ * the context (pid, host, identity) of a caller.
+ *
+ * The cc_caller_id is used to identify one or more callers who invoke
+ * operations, possibly on behalf of others. For example, the NFS
+ * server could have it's own cc_caller_id which can be detected by
+ * vnode/vfs operations or (FEM) monitors on those operations. New
+ * caller IDs are generated by fs_new_caller_id().
+ */
+typedef struct caller_context {
+ pid_t cc_pid; /* Process ID of the caller */
+ int cc_sysid; /* System ID, used for remote calls */
+ u_longlong_t cc_caller_id; /* Identifier for (set of) caller(s) */
+ ulong_t cc_flags;
+} caller_context_t;
+
+/*
+ * Flags for caller context. The caller sets CC_DONTBLOCK if it does not
+ * want to block inside of a FEM monitor. The monitor will set CC_WOULDBLOCK
+ * and return EAGAIN if the operation would have blocked.
+ */
+#define CC_WOULDBLOCK 0x01
+#define CC_DONTBLOCK 0x02
+
+/*
+ * Structure tags for function prototypes, defined elsewhere.
+ */
+struct pathname;
+struct fid;
+struct flock64;
+struct flk_callback;
+struct shrlock;
+struct page;
+struct seg;
+struct as;
+struct pollhead;
+struct taskq;
+
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+/*
+ * VNODE_OPS defines all the vnode operations. It is used to define
+ * the vnodeops structure (below) and the fs_func_p union (vfs_opreg.h).
+ */
+#define VNODE_OPS \
+ int (*vop_open)(vnode_t **, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_close)(vnode_t *, int, int, offset_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_read)(vnode_t *, uio_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_write)(vnode_t *, uio_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_ioctl)(vnode_t *, int, intptr_t, int, cred_t *, \
+ int *, caller_context_t *); \
+ int (*vop_setfl)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_getattr)(vnode_t *, vattr_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_setattr)(vnode_t *, vattr_t *, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_access)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_lookup)(vnode_t *, char *, vnode_t **, \
+ struct pathname *, \
+ int, vnode_t *, cred_t *, \
+ caller_context_t *, int *, \
+ struct pathname *); \
+ int (*vop_create)(vnode_t *, char *, vattr_t *, vcexcl_t, \
+ int, vnode_t **, cred_t *, int, \
+ caller_context_t *, vsecattr_t *); \
+ int (*vop_remove)(vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_link)(vnode_t *, vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_rename)(vnode_t *, char *, vnode_t *, char *, \
+ cred_t *, caller_context_t *, int); \
+ int (*vop_mkdir)(vnode_t *, char *, vattr_t *, vnode_t **, \
+ cred_t *, caller_context_t *, int, \
+ vsecattr_t *); \
+ int (*vop_rmdir)(vnode_t *, char *, vnode_t *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_readdir)(vnode_t *, uio_t *, cred_t *, int *, \
+ caller_context_t *, int); \
+ int (*vop_symlink)(vnode_t *, char *, vattr_t *, char *, \
+ cred_t *, caller_context_t *, int); \
+ int (*vop_readlink)(vnode_t *, uio_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fsync)(vnode_t *, int, cred_t *, \
+ caller_context_t *); \
+ void (*vop_inactive)(vnode_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fid)(vnode_t *, struct fid *, \
+ caller_context_t *); \
+ int (*vop_rwlock)(vnode_t *, int, caller_context_t *); \
+ void (*vop_rwunlock)(vnode_t *, int, caller_context_t *); \
+ int (*vop_seek)(vnode_t *, offset_t, offset_t *, \
+ caller_context_t *); \
+ int (*vop_cmp)(vnode_t *, vnode_t *, caller_context_t *); \
+ int (*vop_frlock)(vnode_t *, int, struct flock64 *, \
+ int, offset_t, \
+ struct flk_callback *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_space)(vnode_t *, int, struct flock64 *, \
+ int, offset_t, \
+ cred_t *, caller_context_t *); \
+ int (*vop_realvp)(vnode_t *, vnode_t **, \
+ caller_context_t *); \
+ int (*vop_getpage)(vnode_t *, offset_t, size_t, uint_t *, \
+ struct page **, size_t, struct seg *, \
+ caddr_t, enum seg_rw, cred_t *, \
+ caller_context_t *); \
+ int (*vop_putpage)(vnode_t *, offset_t, size_t, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_map)(vnode_t *, offset_t, struct as *, \
+ caddr_t *, size_t, \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_addmap)(vnode_t *, offset_t, struct as *, \
+ caddr_t, size_t, \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_delmap)(vnode_t *, offset_t, struct as *, \
+ caddr_t, size_t, \
+ uint_t, uint_t, uint_t, cred_t *, \
+ caller_context_t *); \
+ int (*vop_poll)(vnode_t *, short, int, short *, \
+ struct pollhead **, \
+ caller_context_t *); \
+ int (*vop_dump)(vnode_t *, caddr_t, offset_t, offset_t, \
+ caller_context_t *); \
+ int (*vop_pathconf)(vnode_t *, int, ulong_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_pageio)(vnode_t *, struct page *, \
+ u_offset_t, size_t, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_dumpctl)(vnode_t *, int, offset_t *, \
+ caller_context_t *); \
+ void (*vop_dispose)(vnode_t *, struct page *, \
+ int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_setsecattr)(vnode_t *, vsecattr_t *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_getsecattr)(vnode_t *, vsecattr_t *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_shrlock)(vnode_t *, int, struct shrlock *, \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, \
+ char *, caller_context_t *); \
+ int (*vop_reqzcbuf)(vnode_t *, enum uio_rw, xuio_t *, \
+ cred_t *, caller_context_t *); \
+ int (*vop_retzcbuf)(vnode_t *, xuio_t *, cred_t *, \
+ caller_context_t *)
+ /* NB: No ";" */
+
+/*
+ * Operations on vnodes. Note: File systems must never operate directly
+ * on a 'vnodeops' structure -- it WILL change in future releases! They
+ * must use vn_make_ops() to create the structure.
+ */
+typedef struct vnodeops {
+ const char *vnop_name;
+ VNODE_OPS; /* Signatures of all vnode operations (vops) */
+} vnodeops_t;
+
+typedef int (*fs_generic_func_p) (); /* Generic vop/vfsop/femop/fsemop ptr */
+
+extern int fop_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int fop_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+extern int fop_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
+extern int fop_write(vnode_t *, uio_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+extern int fop_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fop_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_setattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fop_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
+ int, vnode_t *, cred_t *, caller_context_t *,
+ int *, struct pathname *);
+extern int fop_create(vnode_t *, char *, vattr_t *, vcexcl_t, int,
+ vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+extern int fop_remove(vnode_t *vp, char *, cred_t *, caller_context_t *,
+ int);
+extern int fop_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
+ caller_context_t *, int, vsecattr_t *);
+extern int fop_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+extern int fop_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
+extern int fop_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+extern void fop_inactive(vnode_t *, cred_t *, caller_context_t *);
+extern int fop_fid(vnode_t *, struct fid *, caller_context_t *);
+extern int fop_rwlock(vnode_t *, int, caller_context_t *);
+extern void fop_rwunlock(vnode_t *, int, caller_context_t *);
+extern int fop_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
+extern int fop_cmp(vnode_t *, vnode_t *, caller_context_t *);
+extern int fop_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
+ struct flk_callback *, cred_t *,
+ caller_context_t *);
+extern int fop_space(vnode_t *, int, struct flock64 *, int, offset_t,
+ cred_t *, caller_context_t *);
+extern int fop_realvp(vnode_t *, vnode_t **, caller_context_t *);
+extern int fop_getpage(vnode_t *, offset_t, size_t, uint_t *,
+ struct page **, size_t, struct seg *,
+ caddr_t, enum seg_rw, cred_t *,
+ caller_context_t *);
+extern int fop_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+extern int fop_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *cr,
+ caller_context_t *);
+extern int fop_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
+extern int fop_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *,
+ caller_context_t *);
+extern int fop_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+extern int fop_dump(vnode_t *, caddr_t, offset_t, offset_t,
+ caller_context_t *);
+extern int fop_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+extern int fop_pageio(vnode_t *, struct page *, u_offset_t, size_t, int,
+ cred_t *, caller_context_t *);
+extern int fop_dumpctl(vnode_t *, int, offset_t *, caller_context_t *);
+extern void fop_dispose(vnode_t *, struct page *, int, int, cred_t *,
+ caller_context_t *);
+extern int fop_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
+extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *,
+ caller_context_t *);
+extern int fop_reqzcbuf(vnode_t *, enum uio_rw, xuio_t *, cred_t *,
+ caller_context_t *);
+extern int fop_retzcbuf(vnode_t *, xuio_t *, cred_t *, caller_context_t *);
+
+#endif /* _KERNEL */
+
+#define VOP_OPEN(vpp, mode, cr, ct) \
+ fop_open(vpp, mode, cr, ct)
+#define VOP_CLOSE(vp, f, c, o, cr, ct) \
+ fop_close(vp, f, c, o, cr, ct)
+#define VOP_READ(vp, uiop, iof, cr, ct) \
+ fop_read(vp, uiop, iof, cr, ct)
+#define VOP_WRITE(vp, uiop, iof, cr, ct) \
+ fop_write(vp, uiop, iof, cr, ct)
+#define VOP_IOCTL(vp, cmd, a, f, cr, rvp, ct) \
+ fop_ioctl(vp, cmd, a, f, cr, rvp, ct)
+#define VOP_SETFL(vp, f, a, cr, ct) \
+ fop_setfl(vp, f, a, cr, ct)
+#define VOP_GETATTR(vp, vap, f, cr, ct) \
+ fop_getattr(vp, vap, f, cr, ct)
+#define VOP_SETATTR(vp, vap, f, cr, ct) \
+ fop_setattr(vp, vap, f, cr, ct)
+#define VOP_ACCESS(vp, mode, f, cr, ct) \
+ fop_access(vp, mode, f, cr, ct)
+#define VOP_LOOKUP(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp) \
+ fop_lookup(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp)
+#define VOP_CREATE(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap) \
+ fop_create(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap)
+#define VOP_REMOVE(dvp, p, cr, ct, f) \
+ fop_remove(dvp, p, cr, ct, f)
+#define VOP_LINK(tdvp, fvp, p, cr, ct, f) \
+ fop_link(tdvp, fvp, p, cr, ct, f)
+#define VOP_RENAME(fvp, fnm, tdvp, tnm, cr, ct, f) \
+ fop_rename(fvp, fnm, tdvp, tnm, cr, ct, f)
+#define VOP_MKDIR(dp, p, vap, vpp, cr, ct, f, vsap) \
+ fop_mkdir(dp, p, vap, vpp, cr, ct, f, vsap)
+#define VOP_RMDIR(dp, p, cdir, cr, ct, f) \
+ fop_rmdir(dp, p, cdir, cr, ct, f)
+#define VOP_READDIR(vp, uiop, cr, eofp, ct, f) \
+ fop_readdir(vp, uiop, cr, eofp, ct, f)
+#define VOP_SYMLINK(dvp, lnm, vap, tnm, cr, ct, f) \
+ fop_symlink(dvp, lnm, vap, tnm, cr, ct, f)
+#define VOP_READLINK(vp, uiop, cr, ct) \
+ fop_readlink(vp, uiop, cr, ct)
+#define VOP_FSYNC(vp, syncflag, cr, ct) \
+ fop_fsync(vp, syncflag, cr, ct)
+#define VOP_INACTIVE(vp, cr, ct) \
+ fop_inactive(vp, cr, ct)
+#define VOP_FID(vp, fidp, ct) \
+ fop_fid(vp, fidp, ct)
+#define VOP_RWLOCK(vp, w, ct) \
+ fop_rwlock(vp, w, ct)
+#define VOP_RWUNLOCK(vp, w, ct) \
+ fop_rwunlock(vp, w, ct)
+#define VOP_SEEK(vp, ooff, noffp, ct) \
+ fop_seek(vp, ooff, noffp, ct)
+#define VOP_CMP(vp1, vp2, ct) \
+ fop_cmp(vp1, vp2, ct)
+#define VOP_FRLOCK(vp, cmd, a, f, o, cb, cr, ct) \
+ fop_frlock(vp, cmd, a, f, o, cb, cr, ct)
+#define VOP_SPACE(vp, cmd, a, f, o, cr, ct) \
+ fop_space(vp, cmd, a, f, o, cr, ct)
+#define VOP_REALVP(vp1, vp2, ct) \
+ fop_realvp(vp1, vp2, ct)
+#define VOP_GETPAGE(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct) \
+ fop_getpage(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct)
+#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) \
+ fop_putpage(vp, of, sz, fl, cr, ct)
+#define VOP_MAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_map(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_ADDMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_addmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_DELMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_delmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_POLL(vp, events, anyyet, reventsp, phpp, ct) \
+ fop_poll(vp, events, anyyet, reventsp, phpp, ct)
+#define VOP_DUMP(vp, addr, bn, count, ct) \
+ fop_dump(vp, addr, bn, count, ct)
+#define VOP_PATHCONF(vp, cmd, valp, cr, ct) \
+ fop_pathconf(vp, cmd, valp, cr, ct)
+#define VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct) \
+ fop_pageio(vp, pp, io_off, io_len, flags, cr, ct)
+#define VOP_DUMPCTL(vp, action, blkp, ct) \
+ fop_dumpctl(vp, action, blkp, ct)
+#define VOP_DISPOSE(vp, pp, flag, dn, cr, ct) \
+ fop_dispose(vp, pp, flag, dn, cr, ct)
+#define VOP_GETSECATTR(vp, vsap, f, cr, ct) \
+ fop_getsecattr(vp, vsap, f, cr, ct)
+#define VOP_SETSECATTR(vp, vsap, f, cr, ct) \
+ fop_setsecattr(vp, vsap, f, cr, ct)
+#define VOP_SHRLOCK(vp, cmd, shr, f, cr, ct) \
+ fop_shrlock(vp, cmd, shr, f, cr, ct)
+#define VOP_VNEVENT(vp, vnevent, dvp, fnm, ct) \
+ fop_vnevent(vp, vnevent, dvp, fnm, ct)
+#define VOP_REQZCBUF(vp, rwflag, xuiop, cr, ct) \
+ fop_reqzcbuf(vp, rwflag, xuiop, cr, ct)
+#define VOP_RETZCBUF(vp, xuiop, cr, ct) \
+ fop_retzcbuf(vp, xuiop, cr, ct)
+
+#define VOPNAME_OPEN "open"
+#define VOPNAME_CLOSE "close"
+#define VOPNAME_READ "read"
+#define VOPNAME_WRITE "write"
+#define VOPNAME_IOCTL "ioctl"
+#define VOPNAME_SETFL "setfl"
+#define VOPNAME_GETATTR "getattr"
+#define VOPNAME_SETATTR "setattr"
+#define VOPNAME_ACCESS "access"
+#define VOPNAME_LOOKUP "lookup"
+#define VOPNAME_CREATE "create"
+#define VOPNAME_REMOVE "remove"
+#define VOPNAME_LINK "link"
+#define VOPNAME_RENAME "rename"
+#define VOPNAME_MKDIR "mkdir"
+#define VOPNAME_RMDIR "rmdir"
+#define VOPNAME_READDIR "readdir"
+#define VOPNAME_SYMLINK "symlink"
+#define VOPNAME_READLINK "readlink"
+#define VOPNAME_FSYNC "fsync"
+#define VOPNAME_INACTIVE "inactive"
+#define VOPNAME_FID "fid"
+#define VOPNAME_RWLOCK "rwlock"
+#define VOPNAME_RWUNLOCK "rwunlock"
+#define VOPNAME_SEEK "seek"
+#define VOPNAME_CMP "cmp"
+#define VOPNAME_FRLOCK "frlock"
+#define VOPNAME_SPACE "space"
+#define VOPNAME_REALVP "realvp"
+#define VOPNAME_GETPAGE "getpage"
+#define VOPNAME_PUTPAGE "putpage"
+#define VOPNAME_MAP "map"
+#define VOPNAME_ADDMAP "addmap"
+#define VOPNAME_DELMAP "delmap"
+#define VOPNAME_POLL "poll"
+#define VOPNAME_DUMP "dump"
+#define VOPNAME_PATHCONF "pathconf"
+#define VOPNAME_PAGEIO "pageio"
+#define VOPNAME_DUMPCTL "dumpctl"
+#define VOPNAME_DISPOSE "dispose"
+#define VOPNAME_GETSECATTR "getsecattr"
+#define VOPNAME_SETSECATTR "setsecattr"
+#define VOPNAME_SHRLOCK "shrlock"
+#define VOPNAME_VNEVENT "vnevent"
+#define VOPNAME_REQZCBUF "reqzcbuf"
+#define VOPNAME_RETZCBUF "retzcbuf"
+
+/*
+ * Flags for VOP_LOOKUP
+ *
+ * Defined in file.h, but also possible, FIGNORECASE and FSEARCH
+ *
+ */
+#define LOOKUP_DIR 0x01 /* want parent dir vp */
+#define LOOKUP_XATTR 0x02 /* lookup up extended attr dir */
+#define CREATE_XATTR_DIR 0x04 /* Create extended attr dir */
+#define LOOKUP_HAVE_SYSATTR_DIR 0x08 /* Already created virtual GFS dir */
+
+/*
+ * Flags for VOP_READDIR
+ */
+#define V_RDDIR_ENTFLAGS 0x01 /* request dirent flags */
+#define V_RDDIR_ACCFILTER 0x02 /* filter out inaccessible dirents */
+
+/*
+ * Flags for VOP_RWLOCK/VOP_RWUNLOCK
+ * VOP_RWLOCK will return the flag that was actually set, or -1 if none.
+ */
+#define V_WRITELOCK_TRUE (1) /* Request write-lock on the vnode */
+#define V_WRITELOCK_FALSE (0) /* Request read-lock on the vnode */
+
+/*
+ * Flags for VOP_DUMPCTL
+ */
+#define DUMP_ALLOC 0
+#define DUMP_FREE 1
+#define DUMP_SCAN 2
+
+/*
+ * Public vnode manipulation functions.
+ */
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
+
+vnode_t *vn_alloc(int);
+void vn_reinit(vnode_t *);
+void vn_recycle(vnode_t *);
+void vn_free(vnode_t *);
+
+int vn_is_readonly(vnode_t *);
+int vn_is_opened(vnode_t *, v_mode_t);
+int vn_is_mapped(vnode_t *, v_mode_t);
+int vn_has_other_opens(vnode_t *, v_mode_t);
+void vn_open_upgrade(vnode_t *, int);
+void vn_open_downgrade(vnode_t *, int);
+
+int vn_can_change_zones(vnode_t *vp);
+
+int vn_has_flocks(vnode_t *);
+int vn_has_mandatory_locks(vnode_t *, int);
+int vn_has_cached_data(vnode_t *);
+
+void vn_setops(vnode_t *, vnodeops_t *);
+vnodeops_t *vn_getops(vnode_t *);
+int vn_matchops(vnode_t *, vnodeops_t *);
+int vn_matchopval(vnode_t *, char *, fs_generic_func_p);
+int vn_ismntpt(vnode_t *);
+
+struct vfs *vn_mountedvfs(vnode_t *);
+
+int vn_in_dnlc(vnode_t *);
+
+void vn_create_cache(void);
+void vn_destroy_cache(void);
+
+void vn_freevnodeops(vnodeops_t *);
+
+int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy, mode_t umask);
+int vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy,
+ mode_t umask, struct vnode *startvp, int fd);
+int vn_create(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask);
+int vn_createat(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask, struct vnode *startvp);
+int vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, ssize_t len,
+ offset_t offset, enum uio_seg seg, int ioflag, rlim64_t ulimit,
+ cred_t *cr, ssize_t *residp);
+
+void vn_hold(struct vnode *vp);
+void vn_rele(struct vnode *vp);
+void vn_rele_async(struct vnode *vp, struct taskq *taskq);
+void vn_rele_dnlc(struct vnode *vp);
+void vn_rele_stream(struct vnode *vp);
+int vn_link(char *from, char *to, enum uio_seg seg);
+int vn_linkat(vnode_t *fstartvp, char *from, enum symfollow follow,
+ vnode_t *tstartvp, char *to, enum uio_seg seg);
+int vn_rename(char *from, char *to, enum uio_seg seg);
+int vn_renameat(vnode_t *fdvp, char *fname, vnode_t *tdvp, char *tname,
+ enum uio_seg seg);
+int vn_remove(char *fnamep, enum uio_seg seg, enum rm dirflag);
+int vn_removeat(vnode_t *startvp, char *fnamep, enum uio_seg seg,
+ enum rm dirflag);
+int vn_compare(vnode_t *vp1, vnode_t *vp2);
+int vn_vfswlock(struct vnode *vp);
+int vn_vfswlock_wait(struct vnode *vp);
+int vn_vfsrlock(struct vnode *vp);
+int vn_vfsrlock_wait(struct vnode *vp);
+void vn_vfsunlock(struct vnode *vp);
+int vn_vfswlock_held(struct vnode *vp);
+vnode_t *specvp(struct vnode *vp, dev_t dev, vtype_t type, struct cred *cr);
+vnode_t *makespecvp(dev_t dev, vtype_t type);
+
+#if defined(_KERNEL)
+vn_vfslocks_entry_t *vn_vfslocks_getlock(void *);
+void vn_vfslocks_rele(vn_vfslocks_entry_t *);
+#endif
+
+boolean_t vn_is_reparse(vnode_t *, cred_t *, caller_context_t *);
+
+void vn_copypath(struct vnode *src, struct vnode *dst);
+void vn_setpath_str(struct vnode *vp, const char *str, size_t len);
+void vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
+ const char *path, size_t plen);
+void vn_renamepath(vnode_t *dvp, vnode_t *vp, const char *nm, size_t len);
+
+/* Vnode event notification */
+void vnevent_rename_src(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rename_dest(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_remove(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rmdir(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_create(vnode_t *, caller_context_t *);
+void vnevent_link(vnode_t *, caller_context_t *);
+void vnevent_rename_dest_dir(vnode_t *, caller_context_t *ct);
+void vnevent_mountedover(vnode_t *, caller_context_t *);
+void vnevent_truncate(vnode_t *, caller_context_t *);
+int vnevent_support(vnode_t *, caller_context_t *);
+
+/* Vnode specific data */
+void vsd_create(uint_t *, void (*)(void *));
+void vsd_destroy(uint_t *);
+void *vsd_get(vnode_t *, uint_t);
+int vsd_set(vnode_t *, uint_t, void *);
+void vsd_free(vnode_t *);
+
+/*
+ * Extensible vnode attribute (xva) routines:
+ * xva_init() initializes an xvattr_t (zero struct, init mapsize, set AT_XATTR)
+ * xva_getxoptattr() returns a ponter to the xoptattr_t section of xvattr_t
+ */
+void xva_init(xvattr_t *);
+xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */
+
+void xattr_init(void); /* Initialize vnodeops for xattrs */
+
+/* GFS tunnel for xattrs */
+int xattr_dir_lookup(vnode_t *, vnode_t **, int, cred_t *);
+
+/* Reparse Point */
+void reparse_point_init(void);
+
+/* Context identification */
+u_longlong_t fs_new_caller_id();
+
+int vn_vmpss_usepageio(vnode_t *);
+
+/* Empty v_path placeholder */
+extern char *vn_vpath_empty;
+
+/*
+ * Needed for use of IS_VMODSORT() in kernel.
+ */
+extern uint_t pvn_vmodsort_supported;
+
+#define VN_HOLD(vp) { \
+ vn_hold(vp); \
+}
+
+#define VN_RELE(vp) { \
+ vn_rele(vp); \
+}
+
+#define VN_RELE_ASYNC(vp, taskq) { \
+ vn_rele_async(vp, taskq); \
+}
+
+#define VN_RELE_LOCKED(vp) { \
+ (vp)->v_count--; \
+}
+
+#define VN_SET_VFS_TYPE_DEV(vp, vfsp, type, dev) { \
+ (vp)->v_vfsp = (vfsp); \
+ (vp)->v_type = (type); \
+ (vp)->v_rdev = (dev); \
+}
+
+/*
+ * Compare two vnodes for equality. In general this macro should be used
+ * in preference to calling VOP_CMP directly.
+ */
+#if defined(_FAKE_KERNEL)
+#define VN_CMP(VP1, VP2) \
+ (((VP1) == (VP2)) ? 1 : VOP_CMP(VP1, VP2, NULL))
+#else
+#define VN_CMP(VP1, VP2) ((VP1) == (VP2) ? 1 : \
+ ((VP1) && (VP2) && (vn_getops(VP1) == vn_getops(VP2)) ? \
+ VOP_CMP(VP1, VP2, NULL) : 0))
+#endif
+
+/*
+ * Some well-known global vnodes used by the VM system to name pages.
+ */
+extern struct vnode kvps[];
+
+typedef enum {
+ KV_KVP, /* vnode for all segkmem pages */
+ KV_ZVP, /* vnode for all ZFS pages */
+#if defined(__sparc)
+ KV_MPVP, /* vnode for all page_t meta-pages */
+ KV_PROMVP, /* vnode for all PROM pages */
+#endif /* __sparc */
+ KV_MAX /* total number of vnodes in kvps[] */
+} kvps_index_t;
+
+#define VN_ISKAS(vp) ((vp) >= &kvps[0] && (vp) < &kvps[KV_MAX])
+
+#endif /* _KERNEL */
+
+/*
+ * Flags to VOP_SETATTR/VOP_GETATTR.
+ */
+#define ATTR_UTIME 0x01 /* non-default utime(2) request */
+#define ATTR_EXEC 0x02 /* invocation from exec(2) */
+#define ATTR_COMM 0x04 /* yield common vp attributes */
+#define ATTR_HINT 0x08 /* information returned will be `hint' */
+#define ATTR_REAL 0x10 /* yield attributes of the real vp */
+#define ATTR_NOACLCHECK 0x20 /* Don't check ACL when checking permissions */
+#define ATTR_TRIGGER 0x40 /* Mount first if vnode is a trigger mount */
+/*
+ * Generally useful macros.
+ */
+#define VBSIZE(vp) ((vp)->v_vfsp->vfs_bsize)
+
+#define VTOZONE(vp) ((vp)->v_vfsp->vfs_zone)
+
+#define NULLVP ((struct vnode *)0)
+#define NULLVPP ((struct vnode **)0)
+
+#ifdef _KERNEL
+
+/*
+ * Structure used while handling asynchronous VOP_PUTPAGE operations.
+ */
+struct async_reqs {
+ struct async_reqs *a_next; /* pointer to next arg struct */
+ struct vnode *a_vp; /* vnode pointer */
+ u_offset_t a_off; /* offset in file */
+ uint_t a_len; /* size of i/o request */
+ int a_flags; /* flags to indicate operation type */
+ struct cred *a_cred; /* cred pointer */
+ ushort_t a_prealloced; /* set if struct is pre-allocated */
+};
+
+/*
+ * VN_DISPOSE() -- given a page pointer, safely invoke VOP_DISPOSE().
+ * Note that there is no guarantee that the page passed in will be
+ * freed. If that is required, then a check after calling VN_DISPOSE would
+ * be necessary to ensure the page was freed.
+ */
+#define VN_DISPOSE(pp, flag, dn, cr) { \
+ if ((pp)->p_vnode != NULL && !VN_ISKAS((pp)->p_vnode)) \
+ VOP_DISPOSE((pp)->p_vnode, (pp), (flag), (dn), (cr), NULL); \
+ else if ((flag) == B_FREE) \
+ page_free((pp), (dn)); \
+ else \
+ page_destroy((pp), (dn)); \
+ }
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VNODE_H */
diff --git a/usr/src/lib/smbclnt/libfknsmb/i386/Makefile b/usr/src/lib/smbclnt/libfknsmb/i386/Makefile
new file mode 100644
index 0000000000..40b7e3bf5d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile b/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile
new file mode 100644
index 0000000000..40b7e3bf5d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile b/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile
new file mode 100644
index 0000000000..de1ec045d8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/sparcv9/Makefile
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/Makefile b/usr/src/lib/smbclnt/libfksmbfs/Makefile
new file mode 100644
index 0000000000..ee4ab9faf7
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.smbclnt
diff --git a/usr/src/lib/smbclnt/libfksmbfs/Makefile.com b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
new file mode 100644
index 0000000000..5eb9728c12
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
@@ -0,0 +1,137 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+LIBRARY = libfksmbfs.a
+VERS = .1
+
+OBJS_LOCAL = \
+ fksmbfs_rwlock.o \
+ fake_fssub.o \
+ fake_getdents.o \
+ fake_lookup.o \
+ fake_misc.o \
+ fake_modconf.o \
+ fake_nbmlock.o \
+ fake_open.o \
+ fake_rename.o \
+ fake_rw.o \
+ fake_stat.o \
+ fake_unlink.o \
+ fake_vfs.o \
+ fake_vnode.o \
+ fake_zone.o
+
+# See also: $SRC/uts/common/Makefile.files
+# NB: Intentionally ommitted, compared w/ the above:
+# smbfs_rwlock.o
+#
+OBJS_FS_SMBFS = \
+ smbfs_vfsops.o \
+ smbfs_vnops.o \
+ smbfs_client.o \
+ smbfs_node.o \
+ smbfs_smb.o \
+ smbfs_subr.o \
+ smbfs_subr2.o \
+ smbfs_acl.o \
+ smbfs_xattr.o
+
+OBJS_CMN_SMBFS = \
+ smbfs_ntacl.o
+
+OBJS_MISC = \
+ acl_common.o \
+ pathname.o \
+ refstr.o
+
+OBJECTS = \
+ $(OBJS_LOCAL) \
+ $(OBJS_FS_SMBFS) \
+ $(OBJS_CMN_SMBFS) \
+ $(OBJS_MISC)
+
+include ../../../Makefile.lib
+include ../../Makefile.lib
+
+# Force SOURCEDEBUG
+CSOURCEDEBUGFLAGS = -g
+CCSOURCEDEBUGFLAGS = -g
+STRIP_STABS = :
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+# Also, like Makefile.uts, reset CPPFLAGS
+CPPFLAGS.first += -I../../../libfakekernel/common
+CPPFLAGS.first += -I../../libfknsmb/common
+CPPFLAGS.first += -I../common
+CPPFLAGS= $(CPPFLAGS.first)
+
+INCS += -I$(SRC)/uts/common/fs/smbclnt
+INCS += -I$(SRC)/uts/common
+INCS += -I$(SRC)/common/smbclnt
+INCS += -I$(SRC)/common
+
+CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CERRWARN += -_gcc=-Wno-switch
+CERRWARN += -_gcc=-Wno-parentheses
+
+LDLIBS += $(MACH_LDLIBS)
+LDLIBS += -lfknsmb -lfakekernel -lidmap -lcmdutils -lavl -lc
+
+FS_SMBFS_DIR=$(SRC)/uts/common/fs/smbclnt/smbfs
+CMN_SMBFS_DIR=$(SRC)/common/smbclnt
+SRCS= $(OBJS_LOCAL:%.o=$(SRCDIR)/%.c) \
+ $(OBJS_FS_SMBFS:%.o=$(FS_SMBFS_DIR)/%.c) \
+ $(OBJS_CMN_SMBFS:%.o=$(CMN_SMBFS_DIR)/%.c)
+
+all:
+
+pics/%.o: $(FS_SMBFS_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# pathname.o
+pics/%.o: $(SRC)/uts/common/fs/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# refstr.o
+pics/%.o: $(SRC)/uts/common/os/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/acl_common.o: $(SRC)/common/acl/acl_common.c
+ $(COMPILE.c) -o $@ $(SRC)/common/acl/acl_common.c
+ $(POST_PROCESS_O)
+
+.KEEP_STATE:
+
+include ../../Makefile.targ
+include ../../../Makefile.targ
diff --git a/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile b/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile
new file mode 100644
index 0000000000..8b52fdf7af
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/amd64/Makefile
@@ -0,0 +1,23 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbfs/$(MACH64)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c
new file mode 100644
index 0000000000..336406f095
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_fssub.c
@@ -0,0 +1,432 @@
+/*
+ * 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) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Generic vnode operations.
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/flock.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/cred.h>
+#include <sys/poll.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/share.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/nbmlock.h>
+#include <sys/acl.h>
+
+#include <acl/acl_common.h>
+#include <fs/fs_subr.h>
+
+/*
+ * Tunable to limit the number of retry to recover from STALE error.
+ */
+int fs_estale_retry = 5;
+
+/*
+ * The associated operation is not supported by the file system.
+ */
+int
+fs_nosys()
+{
+ return (ENOSYS);
+}
+
+/*
+ * The associated operation is invalid (on this vnode).
+ */
+int
+fs_inval()
+{
+ return (EINVAL);
+}
+
+/*
+ * The associated operation is valid only for directories.
+ */
+int
+fs_notdir()
+{
+ return (ENOTDIR);
+}
+
+/*
+ * Free the file system specific resources. For the file systems that
+ * do not support the forced unmount, it will be a nop function.
+ */
+
+/*ARGSUSED*/
+void
+fs_freevfs(vfs_t *vfsp)
+{
+}
+
+/* ARGSUSED */
+int
+fs_nosys_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/* ARGSUSED */
+int
+fs_nosys_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/* ARGSUSED */
+int
+fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp, caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+
+/*
+ * The file system has nothing to sync to disk. However, the
+ * VFS_SYNC operation must not fail.
+ */
+/* ARGSUSED */
+int
+fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_FSYNC must not fail.
+ */
+/* ARGSUSED */
+int
+fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_PUTPAGE must not fail.
+ */
+/* ARGSUSED */
+int
+fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ctp)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_IOCTL must not fail.
+ */
+/* ARGSUSED */
+int
+fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
+ int *rvalp)
+{
+ return (0);
+}
+
+/*
+ * Read/write lock/unlock. Does nothing.
+ */
+/* ARGSUSED */
+int
+fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+void
+fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+}
+
+/*
+ * Compare two vnodes.
+ */
+/*ARGSUSED2*/
+int
+fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
+{
+ return (vp1 == vp2);
+}
+
+/*
+ * No-op seek operation.
+ */
+/* ARGSUSED */
+int
+fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
+{
+ return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
+}
+
+/*
+ * File and record locking.
+ */
+/* ARGSUSED */
+int
+fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
+ flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/*
+ * Allow any flags.
+ */
+/* ARGSUSED */
+int
+fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
+{
+ return (0);
+}
+
+/*
+ * Return the answer requested to poll() for non-device files.
+ * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
+ */
+struct pollhead fs_pollhd;
+
+/* ARGSUSED */
+int
+fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp, caller_context_t *ct)
+{
+ if (events & POLLET) {
+ return (EPERM);
+ }
+
+ *reventsp = 0;
+ if (events & POLLIN)
+ *reventsp |= POLLIN;
+ if (events & POLLRDNORM)
+ *reventsp |= POLLRDNORM;
+ if (events & POLLRDBAND)
+ *reventsp |= POLLRDBAND;
+ if (events & POLLOUT)
+ *reventsp |= POLLOUT;
+ if (events & POLLWRBAND)
+ *reventsp |= POLLWRBAND;
+ if (*reventsp == 0 && !anyyet) {
+ *phpp = &fs_pollhd;
+ }
+ return (0);
+}
+
+/*
+ * POSIX pathconf() support.
+ */
+/* ARGSUSED */
+int
+fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
+{
+ /* not called */
+ return (EINVAL);
+}
+
+/*
+ * Dispose of a page.
+ */
+/* ARGSUSED */
+void
+fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
+ caller_context_t *ct)
+{
+}
+
+/* ARGSUSED */
+void
+fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
+ caller_context_t *ct)
+{
+ cmn_err(CE_PANIC, "fs_nodispose invoked");
+}
+
+/*
+ * fabricate acls for file systems that do not support acls.
+ */
+/* ARGSUSED */
+int
+fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
+{
+ struct vattr vattr;
+ int error;
+
+ vsecattr->vsa_aclcnt = 0;
+ vsecattr->vsa_aclentsz = 0;
+ vsecattr->vsa_aclentp = NULL;
+ vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
+ vsecattr->vsa_dfaclentp = NULL;
+
+ vattr.va_mask = AT_MODE | AT_UID | AT_GID;
+ if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
+ return (error);
+
+ if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
+ return (ENOSYS);
+ }
+
+ if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
+ VERIFY(0 == acl_trivial_create(vattr.va_mode,
+ (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
+ &vsecattr->vsa_aclcnt));
+ vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ }
+
+ return (error);
+}
+
+/*
+ * Common code for implementing DOS share reservations
+ */
+/* ARGSUSED */
+int
+fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
+{
+ return (ENOSYS);
+}
+
+/*ARGSUSED1*/
+int
+fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ ASSERT(vp != NULL);
+ return (ENOTSUP);
+}
+
+/*ARGSUSED1*/
+int
+fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ ASSERT(vp != NULL);
+ return (0);
+}
+
+// fs_acl_nontrivial
+
+/*
+ * Check whether we need a retry to recover from STALE error.
+ */
+int
+fs_need_estale_retry(int retry_count)
+{
+ if (retry_count < fs_estale_retry)
+ return (1);
+ else
+ return (0);
+}
+
+// fs_vscan...
+// reparse...
+
+/*
+ * A few things from os/flock.c
+ */
+
+/* ARGSUSED */
+void
+cleanlocks(vnode_t *vp, pid_t pid, int sysid)
+{
+}
+
+/* ARGSUSED */
+void
+cleanshares(struct vnode *vp, pid_t pid)
+{
+}
+
+/*
+ * convoff - converts the given data (start, whence) to the
+ * given whence.
+ */
+int
+convoff(struct vnode *vp, struct flock64 *lckdat, int whence, offset_t offset)
+{
+ int error;
+ struct vattr vattr;
+
+ if ((lckdat->l_whence == 2) || (whence == 2)) {
+ vattr.va_mask = AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
+ return (error);
+ }
+
+ switch (lckdat->l_whence) {
+ case 1:
+ lckdat->l_start += offset;
+ break;
+ case 2:
+ lckdat->l_start += vattr.va_size;
+ /* FALLTHRU */
+ case 0:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (lckdat->l_start < 0)
+ return (EINVAL);
+
+ switch (whence) {
+ case 1:
+ lckdat->l_start -= offset;
+ break;
+ case 2:
+ lckdat->l_start -= vattr.va_size;
+ /* FALLTHRU */
+ case 0:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ lckdat->l_whence = (short)whence;
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c
new file mode 100644
index 0000000000..afa4eb1c0f
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_getdents.c
@@ -0,0 +1,96 @@
+/*
+ * 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) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/dirent.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/mode.h>
+#include <sys/uio.h>
+#include <sys/filio.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+
+/*
+ * Returns count of dir entries, or -errno
+ */
+int
+fake_getdents(vnode_t *vp, offset_t *offp, void *buf, size_t count)
+{
+ struct uio auio;
+ struct iovec aiov;
+ register int error;
+ int sink;
+
+ if (count < sizeof (struct dirent64))
+ return (-EINVAL);
+
+ /*
+ * Don't let the user overcommit kernel resources.
+ */
+ if (count > MAXGETDENTS_SIZE)
+ count = MAXGETDENTS_SIZE;
+
+ if (vp->v_type != VDIR) {
+ return (-ENOTDIR);
+ }
+
+ aiov.iov_base = buf;
+ aiov.iov_len = count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_loffset = *offp;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_resid = count;
+ auio.uio_fmode = 0;
+ auio.uio_extflg = UIO_COPY_CACHED;
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(vp, &auio, CRED(), &sink, NULL, 0);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ if (error) {
+ return (-error);
+ }
+ count = count - auio.uio_resid;
+ *offp = auio.uio_loffset;
+
+ return (count);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c
new file mode 100644
index 0000000000..8072a91b3b
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_lookup.c
@@ -0,0 +1,173 @@
+/*
+ * 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/pathname.h>
+#include <sys/proc.h>
+#include <sys/vtrace.h>
+#include <sys/sysmacros.h>
+#include <sys/debug.h>
+#include <sys/dirent.h>
+#include <sys/zone.h>
+#include <sys/fs/snode.h>
+
+#include <libfksmbfs.h>
+
+extern vnode_t *rootdir;
+
+/*
+ * Simplified variation on lookuppnvp()
+ */
+int
+fake_lookup(vnode_t *dvp, char *path, vnode_t **vpp)
+{
+ char component[MAXNAMELEN]; /* buffer for component */
+ pathname_t pn;
+ cred_t *cr;
+ vnode_t *cvp; /* current component vp */
+ vnode_t *nvp; /* next component vp */
+ char *p;
+ int flags = 0;
+ int error, len;
+
+ bzero(&pn, sizeof (pn));
+ pn.pn_buf = path;
+ pn.pn_path = path;
+ pn.pn_pathlen = strlen(path);
+ pn.pn_bufsize = pn.pn_pathlen + 1;
+ p = path;
+
+ cr = CRED();
+ cvp = (dvp != NULL) ? dvp : rootdir;
+ VN_HOLD(cvp);
+ nvp = NULL;
+
+ while (*p != '\0') {
+ if (*p == '/') {
+ p++;
+ continue;
+ }
+
+ len = strcspn(p, "/");
+ ASSERT(len > 0);
+ if (len >= MAXNAMELEN)
+ return (EINVAL);
+ (void) strncpy(component, p, len);
+ component[len] = '\0';
+ pn.pn_path = p;
+ pn.pn_pathlen = strlen(p);
+
+ error = VOP_LOOKUP(cvp, component, &nvp, &pn, flags,
+ rootdir, cr, NULL, NULL, NULL);
+ VN_RELE(cvp);
+ if (error != 0)
+ return (error);
+
+ /* Lookup gave us a hold on nvp */
+ cvp = nvp;
+ nvp = NULL;
+ p += len;
+ }
+
+ *vpp = cvp;
+ return (0);
+}
+
+/*
+ * Lookup the directory and find the start of the
+ * last component of the given path.
+ */
+int
+fake_lookup_dir(char *path, vnode_t **vpp, char **lastcomp)
+{
+ vnode_t *dvp;
+ char *last;
+ char *tpn = NULL;
+ int tpn_sz;
+ int lc_off;
+ int error;
+
+ *vpp = NULL;
+ *lastcomp = NULL;
+
+ tpn_sz = strlen(path) + 1;
+ tpn = kmem_alloc(tpn_sz, KM_SLEEP);
+
+ /*
+ * Get a copy of the path, and zap the last /
+ */
+ bcopy(path, tpn, tpn_sz);
+ last = strrchr(tpn, '/');
+ if (last == NULL) {
+ lc_off = 0;
+ dvp = rootdir;
+ VN_HOLD(dvp);
+ error = 0;
+ } else {
+ *last++ = '\0';
+ if (*last == '\0') {
+ error = EINVAL;
+ goto out;
+ }
+ error = fake_lookup(rootdir, tpn, &dvp);
+ if (error != 0) {
+ /* dir not found */
+ goto out;
+ }
+ lc_off = last - tpn;
+ ASSERT(lc_off >= 0 && lc_off < tpn_sz);
+ }
+ *vpp = dvp;
+ *lastcomp = path + lc_off;
+
+out:
+ if (tpn != NULL)
+ kmem_free(tpn, tpn_sz);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.c
new file mode 100644
index 0000000000..e5ab8973b4
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_misc.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) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/cred.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+
+volatile int ncsize = 500; /* dnlc.h */
+
+static major_t devcnt = 0x280;
+static kmutex_t udevlock;
+
+/* os/subr.c */
+major_t
+getudev()
+{
+ static major_t next = 0;
+ major_t ret;
+
+ mutex_enter(&udevlock);
+ if (next == 0)
+ next = devcnt;
+ if (next <= L_MAXMAJ32 && next >= devcnt)
+ ret = next++;
+ else {
+ cmn_err(CE_WARN, "out of major numbers");
+ ret = ((major_t)-1);
+ }
+ mutex_exit(&udevlock);
+ return (ret);
+}
+
+/*
+ * Compress 'long' device number encoding to 32-bit device number
+ * encoding. If it won't fit, we return failure, but set the
+ * device number to 32-bit NODEV for the sake of our callers.
+ */
+int
+cmpldev(dev32_t *dst, dev_t dev)
+{
+#if defined(_LP64)
+ if (dev == NODEV) {
+ *dst = (dev32_t)(-1);
+ } else {
+ major_t major = dev >> L_BITSMINOR;
+ minor_t minor = dev & L_MAXMIN;
+
+ if (major > L_MAXMAJ32 || minor > L_MAXMIN32) {
+ *dst = (dev32_t)(-1);
+ return (0);
+ }
+
+ *dst = (dev32_t)((major << L_BITSMINOR32) | minor);
+ }
+#else
+ *dst = (dev32_t)dev;
+#endif
+ return (1);
+}
+
+/* os/cred.c */
+int
+groupmember(gid_t gid, const cred_t *cr)
+{
+ if (gid == 0 || gid == 1)
+ return (1);
+ return (0);
+}
+
+/* os/sig.c */
+
+/* ARGSUSED */
+void
+sigintr(k_sigset_t *smask, int intable)
+{
+}
+
+/* ARGSUSED */
+void
+sigunintr(k_sigset_t *smask)
+{
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c
new file mode 100644
index 0000000000..d5482f9cc5
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_modconf.c
@@ -0,0 +1,195 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+
+#if 0 // XXX
+
+#include <sys/user.h>
+#include <sys/vm.h>
+#include <sys/conf.h>
+#include <sys/class.h>
+#include <sys/systm.h>
+#include <sys/modctl.h>
+#include <sys/exec.h>
+#include <sys/exechdr.h>
+#include <sys/devops.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/hwconf.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/autoconf.h>
+#include <sys/disp.h>
+#include <sys/kmem.h>
+#include <sys/instance.h>
+#include <sys/modhash.h>
+#include <sys/dacf.h>
+#include <ipp/ipp.h>
+#include <sys/strsubr.h>
+#include <sys/kcpc.h>
+#include <sys/brand.h>
+#include <sys/cpc_pcbe.h>
+#include <sys/kstat.h>
+#include <sys/socketvar.h>
+#include <sys/kiconv.h>
+
+#endif // XXX
+
+#include <libfksmbfs.h>
+
+/*
+ * Install a filesystem.
+ */
+/*ARGSUSED1*/
+int
+fake_installfs(vfsdef_t *def)
+{
+ struct vfssw *vswp;
+ char *fsname = def->name;
+ int fstype; /* index into vfssw[] and vsanchor_fstype[] */
+ int allocated;
+ int err;
+
+ if (def->def_version != VFSDEF_VERSION) {
+ cmn_err(CE_WARN, "file system '%s' version mismatch", fsname);
+ return (ENXIO);
+ }
+
+ allocated = 0;
+
+ WLOCK_VFSSW();
+ if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) {
+ if ((vswp = allocate_vfssw(fsname)) == NULL) {
+ WUNLOCK_VFSSW();
+ /*
+ * See 1095689. If this message appears, then
+ * we either need to make the vfssw table bigger
+ * statically, or make it grow dynamically.
+ */
+ cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname);
+ return (ENXIO);
+ }
+ allocated = 1;
+ }
+ ASSERT(vswp != NULL);
+
+ fstype = vswp - vfssw; /* Pointer arithmetic to get the fstype */
+
+ /* Turn on everything by default *except* VSW_STATS */
+ vswp->vsw_flag = def->flags & ~(VSW_STATS);
+
+ if (def->flags & VSW_HASPROTO) {
+ vfs_mergeopttbl(&vfs_mntopts, def->optproto,
+ &vswp->vsw_optproto);
+ } else {
+ vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto);
+ }
+
+ if (def->flags & VSW_CANRWRO) {
+ /*
+ * This obviously implies VSW_CANREMOUNT.
+ */
+ vswp->vsw_flag |= VSW_CANREMOUNT;
+ }
+
+ /* vopstats ... */
+
+ if (def->init == NULL)
+ err = EFAULT;
+ else
+ err = (*(def->init))(fstype, fsname);
+
+ if (err != 0) {
+ if (allocated) {
+ kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1);
+ vswp->vsw_name = "";
+ }
+ vswp->vsw_flag = 0;
+ vswp->vsw_init = NULL;
+ }
+
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+
+ /* ... vopstats */
+
+ return (err);
+}
+
+int fake_removefs_allowed = 1;
+
+/*
+ * Remove a filesystem
+ */
+int
+fake_removefs(vfsdef_t *def)
+{
+ struct vfssw *vswp;
+
+ if (fake_removefs_allowed == 0)
+ return (EBUSY);
+
+ WLOCK_VFSSW();
+ if ((vswp = vfs_getvfsswbyname(def->name)) == NULL) {
+ WUNLOCK_VFSSW();
+ cmn_err(CE_WARN, "fake_removefs: %s not in vfssw",
+ def->name);
+ return (EINVAL);
+ }
+ if (vswp->vsw_count != 1) {
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (EBUSY);
+ }
+
+ /*
+ * A mounted filesystem could still have vsw_count = 0
+ * so we must check whether anyone is actually using our ops
+ */
+ if (vfs_opsinuse(&vswp->vsw_vfsops)) {
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (EBUSY);
+ }
+
+ vfs_freeopttbl(&vswp->vsw_optproto);
+ vswp->vsw_optproto.mo_count = 0;
+
+ vswp->vsw_flag = 0;
+ vswp->vsw_init = NULL;
+ vfs_unrefvfssw(vswp);
+ WUNLOCK_VFSSW();
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c
new file mode 100644
index 0000000000..c1b5ef63e8
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_nbmlock.c
@@ -0,0 +1,124 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Utility routines and top-level conflict detection code for NBMAND
+ * locks.
+ */
+
+#include <sys/nbmlock.h>
+#include <sys/rwlock.h>
+#include <sys/vnode.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/vfs.h>
+
+/*
+ * Enter the critical region for synchronizing I/O requests with lock/share
+ * requests. "mode" specifies whether the caller intends to update
+ * lock/share state (as opposed to just query it).
+ */
+
+void
+nbl_start_crit(vnode_t *vp, krw_t mode)
+{
+ rw_enter(&vp->v_nbllock, mode);
+}
+
+/*
+ * Leave the critical region.
+ */
+
+void
+nbl_end_crit(vnode_t *vp)
+{
+ rw_exit(&vp->v_nbllock);
+}
+
+/*
+ * Return non-zero if some thread is in the critical region.
+ * Note that this is appropriate for use in ASSERT()s only.
+ */
+
+int
+nbl_in_crit(vnode_t *vp)
+{
+ return (RW_LOCK_HELD(&vp->v_nbllock));
+}
+
+/*
+ * Returns non-zero if we need to look further for an NBMAND lock or
+ * share conflict.
+ */
+int
+nbl_need_check(vnode_t *vp)
+{
+ /*
+ * Currently we only check if NBMAND locks/shares are allowed on
+ * the filesystem. An option for the future would be to have a
+ * flag on the vnode, though the locking for that can get tricky.
+ */
+ return ((vp->v_vfsp) && (vp->v_vfsp->vfs_flag & VFS_NBMAND));
+}
+
+/* No locks, so no conflicts. */
+int
+nbl_conflict(vnode_t *vp,
+ nbl_op_t op, /* attempted operation */
+ u_offset_t offset, /* ignore if not I/O */
+ ssize_t length, /* ignore if not I/O */
+ int svmand, /* System V mandatory locking */
+ caller_context_t *ct) /* caller context */
+{
+ ASSERT(nbl_in_crit(vp));
+
+ return (0);
+}
+
+/*
+ * Determine if the given file has mode bits for System V mandatory locks.
+ * If there was an error, the errno value is returned. Otherwise, zero is
+ * returned and *svp is set appropriately (non-zero for mandatory locks,
+ * zero for no mandatory locks).
+ */
+
+int
+nbl_svmand(vnode_t *vp, cred_t *cr, int *svp)
+{
+ struct vattr va;
+ int error;
+
+ va.va_mask = AT_MODE;
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
+ if (error != 0)
+ return (error);
+
+ *svp = MANDLOCK(vp, va.va_mode);
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c
new file mode 100644
index 0000000000..169197ae03
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c
@@ -0,0 +1,340 @@
+/*
+ * 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * Portions of code from both of:
+ * syscall/open.c
+ * fs/vnode.c
+ * heavily modified for this use.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <fs/fs_subr.h>
+#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
+#include <sys/time.h>
+
+#include <libfksmbfs.h>
+
+/* close and release */
+int
+vn_close_rele(vnode_t *vp, int flag)
+{
+ int error;
+
+ error = VOP_CLOSE(vp, flag, 0, 0, CRED(), NULL);
+ vn_rele(vp);
+
+ return (error);
+}
+
+/*
+ * Open/create a vnode.
+ * This may be callable by the kernel, the only known use
+ * of user context being that the current user credentials
+ * are used for permissions. crwhy is defined iff filemode & FCREAT.
+ */
+int
+vn_open(
+ char *pnamep,
+ enum uio_seg seg,
+ int filemode,
+ int createmode,
+ struct vnode **vpp,
+ enum create crwhy,
+ mode_t umask)
+{
+ struct vnode *vp;
+ int mode;
+ int accessflags;
+ int error;
+ int open_done = 0;
+ struct vattr vattr;
+ int estale_retry = 0;
+
+ mode = 0;
+ accessflags = 0;
+ if (filemode & FREAD)
+ mode |= VREAD;
+ if (filemode & (FWRITE|FTRUNC))
+ mode |= VWRITE;
+ if (filemode & (FSEARCH|FEXEC|FXATTRDIROPEN))
+ mode |= VEXEC;
+
+ if (filemode & FAPPEND)
+ accessflags |= V_APPEND;
+
+top:
+ if (filemode & FCREAT) {
+ enum vcexcl excl;
+
+ /*
+ * Wish to create a file.
+ */
+ vattr.va_type = VREG;
+ vattr.va_mode = createmode;
+ vattr.va_mask = AT_TYPE|AT_MODE;
+ if (filemode & FTRUNC) {
+ vattr.va_size = 0;
+ vattr.va_mask |= AT_SIZE;
+ }
+ if (filemode & FEXCL)
+ excl = EXCL;
+ else
+ excl = NONEXCL;
+
+ if ((error =
+ vn_create(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
+ (filemode & ~(FTRUNC|FEXCL)), umask)) != 0)
+ return (error);
+ } else {
+ /*
+ * Wish to open a file. Just look it up.
+ * Was lookupnameat()
+ */
+ if ((error = fake_lookup(NULL, pnamep, &vp)) != 0) {
+ if ((error == ESTALE) &&
+ fs_need_estale_retry(estale_retry++))
+ goto top;
+ return (error);
+ }
+
+ /*
+ * Want the XATTRDIR under it?
+ */
+ if (filemode & FXATTRDIROPEN) {
+ vnode_t *xvp = NULL;
+ error = VOP_LOOKUP(vp, NULL, &xvp, NULL,
+ LOOKUP_XATTR, rootdir, CRED(), NULL,
+ NULL, NULL);
+ VN_RELE(vp);
+ vp = xvp;
+ /* continue with vp */
+ }
+
+ /*
+ * Can't write directories, active texts, or
+ * read-only filesystems. Can't truncate files
+ * on which mandatory locking is in effect.
+ */
+ if (filemode & (FWRITE|FTRUNC)) {
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ goto out;
+ }
+ }
+ /*
+ * Check permissions.
+ */
+ if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
+ goto out;
+ /*
+ * Require FSEARCH to return a directory.
+ * Require FEXEC to return a regular file.
+ */
+ if ((filemode & FSEARCH) && vp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
+ if ((filemode & FEXEC) && vp->v_type != VREG) {
+ error = ENOEXEC;
+ goto out;
+ }
+ }
+
+ /*
+ * Do remaining checks for FNOFOLLOW and FNOLINKS.
+ */
+ if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
+ error = ELOOP;
+ goto out;
+ }
+ if (filemode & FNOLINKS) {
+ vattr.va_mask = AT_NLINK;
+ if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
+ goto out;
+ }
+ if (vattr.va_nlink != 1) {
+ error = EMLINK;
+ goto out;
+ }
+ }
+
+ /*
+ * Opening a socket corresponding to the AF_UNIX pathname
+ * in the filesystem name space is not supported...
+ */
+ if (vp->v_type == VSOCK) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
+ /*
+ * Do opening protocol.
+ */
+ error = VOP_OPEN(&vp, filemode, CRED(), NULL);
+ if (error)
+ goto out;
+ open_done = 1;
+
+ /*
+ * Truncate if required.
+ */
+ if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
+ vattr.va_size = 0;
+ vattr.va_mask = AT_SIZE;
+ if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
+ goto out;
+ }
+out:
+ ASSERT(vp->v_count > 0);
+
+ if (error) {
+ if (open_done) {
+ (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
+ NULL);
+ open_done = 0;
+ }
+ VN_RELE(vp);
+ } else
+ *vpp = vp;
+ return (error);
+}
+
+
+/*
+ * Create a vnode (makenode).
+ */
+int
+vn_create(
+ char *pnamep,
+ enum uio_seg seg,
+ struct vattr *vap,
+ enum vcexcl excl,
+ int mode,
+ struct vnode **vpp,
+ enum create why,
+ int flag,
+ mode_t umask)
+{
+ struct vnode *dvp = NULL; /* ptr to parent dir vnode */
+ char *lastcomp = NULL;
+ int error;
+
+ ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
+
+ flag &= ~(FNOFOLLOW|FNOLINKS);
+
+ *vpp = NULL;
+
+ /*
+ * Lookup directory and last component
+ */
+ error = fake_lookup_dir(pnamep, &dvp, &lastcomp);
+ if (error != 0) {
+ /* dir not found */
+ return (error);
+ }
+
+ /*
+ * If default ACLs are defined for the directory don't apply the
+ * umask if umask is passed.
+ */
+
+ if (umask) {
+ /*
+ * Apply the umask if no default ACLs...
+ */
+ vap->va_mode &= ~umask;
+ }
+
+ if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ /*
+ * Call mkdir() if specified, otherwise create().
+ */
+ if (why == CRMKDIR) {
+ /*
+ * N.B., if vn_createat() ever requests
+ * case-insensitive behavior then it will need
+ * to be passed to VOP_MKDIR(). VOP_CREATE()
+ * will already get it via "flag"
+ */
+ error = VOP_MKDIR(dvp, lastcomp, vap, vpp, CRED(),
+ NULL, 0, NULL);
+ } else {
+ error = VOP_CREATE(dvp, lastcomp, vap,
+ excl, mode, vpp, CRED(), flag, NULL, NULL);
+ }
+
+out:
+ if (dvp != NULL)
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c
new file mode 100644
index 0000000000..5ff428593d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rename.c
@@ -0,0 +1,123 @@
+/*
+ * 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * Portions of code from both of:
+ * syscall/rename.c
+ * fs/vnode.c
+ * heavily modified for this use.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <fs/fs_subr.h>
+#include <sys/taskq.h>
+#include <fs/fs_reparse.h>
+#include <sys/time.h>
+
+#include <libfksmbfs.h>
+
+int
+fake_rename(char *frompath, char *topath)
+{
+ vnode_t *fdvp = NULL;
+ vnode_t *tdvp = NULL;
+ char *fname = NULL;
+ char *tname = NULL;
+ int error;
+
+ /*
+ * Lookup to and from directories.
+ */
+ if ((error = fake_lookup_dir(frompath, &fdvp, &fname)) != 0)
+ goto out;
+ if ((error = fake_lookup_dir(topath, &tdvp, &tname)) != 0)
+ goto out;
+
+ /*
+ * Make sure both the from vnode directory and the to directory
+ * are in the same vfs and the to directory is writable.
+ */
+ if (fdvp != tdvp && fdvp->v_vfsp != tdvp->v_vfsp) {
+ error = EXDEV;
+ goto out;
+ }
+ if (tdvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ /*
+ * Do the rename.
+ */
+ error = VOP_RENAME(fdvp, fname, tdvp, tname, CRED(), NULL, 0);
+
+out:
+ if (fdvp)
+ VN_RELE(fdvp);
+ if (tdvp)
+ VN_RELE(tdvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c
new file mode 100644
index 0000000000..33a63a16dc
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_rw.c
@@ -0,0 +1,203 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+
+#include <libfksmbfs.h>
+
+#define set_errno(e) (-(e))
+
+ssize_t
+fake_pread(vnode_t *vp, void *cbuf, size_t count, off_t offset)
+{
+ struct uio auio;
+ struct iovec aiov;
+ int fflag, ioflag, rwflag;
+ ssize_t bcount;
+ int error = 0;
+ u_offset_t fileoff = (u_offset_t)(ulong_t)offset;
+ const u_offset_t maxoff = MAXOFF32_T;
+
+ if ((bcount = (ssize_t)count) < 0)
+ return (set_errno(EINVAL));
+ fflag = FREAD;
+
+ rwflag = 0;
+
+ if (vp->v_type == VREG) {
+
+ if (bcount == 0)
+ goto out;
+
+ /*
+ * Return EINVAL if an invalid offset comes to pread.
+ * Negative offset from user will cause this error.
+ */
+
+ if (fileoff > maxoff) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Limit offset such that we don't read or write
+ * a file beyond the maximum offset representable in
+ * an off_t structure.
+ */
+ if (fileoff + bcount > maxoff)
+ bcount = (ssize_t)((offset_t)maxoff - fileoff);
+ } else if (vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto out;
+ }
+
+ aiov.iov_base = cbuf;
+ aiov.iov_len = bcount;
+ (void) VOP_RWLOCK(vp, rwflag, NULL);
+ auio.uio_loffset = fileoff;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = bcount;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_llimit = MAXOFFSET_T;
+ auio.uio_fmode = fflag;
+ auio.uio_extflg = UIO_COPY_CACHED;
+
+ ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC);
+
+ /* If read sync is not asked for, filter sync flags */
+ if ((ioflag & FRSYNC) == 0)
+ ioflag &= ~(FSYNC|FDSYNC);
+ error = VOP_READ(vp, &auio, ioflag, CRED(), NULL);
+ bcount -= auio.uio_resid;
+ VOP_RWUNLOCK(vp, rwflag, NULL);
+
+ if (error == EINTR && bcount != 0)
+ error = 0;
+out:
+ if (error)
+ return (set_errno(error));
+ return (bcount);
+}
+
+ssize_t
+fake_pwrite(vnode_t *vp, void *cbuf, size_t count, off_t offset)
+{
+ struct uio auio;
+ struct iovec aiov;
+ int fflag, ioflag, rwflag;
+ ssize_t bcount;
+ int error = 0;
+ u_offset_t fileoff = (u_offset_t)(ulong_t)offset;
+ const u_offset_t maxoff = MAXOFF32_T;
+
+ if ((bcount = (ssize_t)count) < 0)
+ return (set_errno(EINVAL));
+ fflag = FREAD | FWRITE;
+
+ rwflag = 1;
+
+ if (vp->v_type == VREG) {
+
+ if (bcount == 0)
+ goto out;
+
+ /*
+ * return EINVAL for offsets that cannot be
+ * represented in an off_t.
+ */
+ if (fileoff > maxoff) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * Don't allow pwrite to cause file sizes to exceed
+ * maxoff.
+ */
+ if (fileoff == maxoff) {
+ error = EFBIG;
+ goto out;
+ }
+ if (fileoff + count > maxoff)
+ bcount = (ssize_t)((u_offset_t)maxoff - fileoff);
+ } else if (vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto out;
+ }
+
+ aiov.iov_base = cbuf;
+ aiov.iov_len = bcount;
+ (void) VOP_RWLOCK(vp, rwflag, NULL);
+ auio.uio_loffset = fileoff;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = bcount;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_llimit = MAXOFFSET_T;
+ auio.uio_fmode = fflag;
+ auio.uio_extflg = UIO_COPY_CACHED;
+
+ /*
+ * The SUSv4 POSIX specification states:
+ * The pwrite() function shall be equivalent to write(), except
+ * that it writes into a given position and does not change
+ * the file offset (regardless of whether O_APPEND is set).
+ * To make this be true, we omit the FAPPEND flag from ioflag.
+ */
+ ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
+
+ error = VOP_WRITE(vp, &auio, ioflag, CRED(), NULL);
+ bcount -= auio.uio_resid;
+ VOP_RWUNLOCK(vp, rwflag, NULL);
+
+ if (error == EINTR && bcount != 0)
+ error = 0;
+out:
+ if (error)
+ return (set_errno(error));
+ return (bcount);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c
new file mode 100644
index 0000000000..5b074e2be9
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_stat.c
@@ -0,0 +1,96 @@
+/*
+ * 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) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+/*
+ * Get file attribute information through a file name or a file descriptor.
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/pathname.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/mode.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <fs/fs_subr.h>
+
+#include <libfksmbfs.h>
+
+int
+fake_stat(vnode_t *vp, struct stat64 *ubp, int flag)
+{
+ cred_t *cr = CRED();
+ struct vfssw *vswp;
+ struct stat64 lsb;
+ vattr_t vattr;
+ int error;
+
+ vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
+ return (error);
+
+ bzero(&lsb, sizeof (lsb));
+ lsb.st_dev = vattr.va_fsid;
+ lsb.st_ino = vattr.va_nodeid;
+ lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
+ lsb.st_nlink = vattr.va_nlink;
+ lsb.st_uid = vattr.va_uid;
+ lsb.st_gid = vattr.va_gid;
+ lsb.st_rdev = vattr.va_rdev;
+ lsb.st_size = vattr.va_size;
+ lsb.st_atim = vattr.va_atime;
+ lsb.st_mtim = vattr.va_mtime;
+ lsb.st_ctim = vattr.va_ctime;
+ lsb.st_blksize = vattr.va_blksize;
+ lsb.st_blocks = vattr.va_nblocks;
+ if (vp->v_vfsp != NULL) {
+ vswp = &vfssw[vp->v_vfsp->vfs_fstype];
+ if (vswp->vsw_name && *vswp->vsw_name)
+ (void) strcpy(lsb.st_fstype, vswp->vsw_name);
+ }
+ if (copyout(&lsb, ubp, sizeof (lsb)))
+ return (EFAULT);
+ return (0);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c
new file mode 100644
index 0000000000..4c35620d29
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_unlink.c
@@ -0,0 +1,91 @@
+/*
+ * 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) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+/*
+ * Modified version of syscall/unlink.c
+ */
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+
+#include <libfksmbfs.h>
+
+/*
+ * Unlink a file from a directory
+ * Like syscall/unlinkat.c
+ */
+int
+fake_unlink(char *path, int flags)
+{
+ vnode_t *dvp = NULL;
+ char *lastcomp = NULL;
+ int error;
+
+ if (path == NULL)
+ return (EFAULT);
+
+ error = fake_lookup_dir(path, &dvp, &lastcomp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Some logic from vn_removeat() here
+ */
+ if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
+ error = EROFS;
+ goto out;
+ }
+
+ if (flags == AT_REMOVEDIR) {
+ error = VOP_RMDIR(dvp, lastcomp, NULL, CRED(), NULL, 0);
+ } else {
+ error = VOP_REMOVE(dvp, lastcomp, CRED(), NULL, 0);
+ }
+
+out:
+ if (dvp != NULL)
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c
new file mode 100644
index 0000000000..cc63b01ee1
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vfs.c
@@ -0,0 +1,2155 @@
+/*
+ * 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 RackTop Systems.
+ * Copyright 2018 Nexenta Systems, Inc.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * This file contains those functions from fs/vfs.c that can be
+ * used with relatively little change. Functions that differ
+ * significantly from that are in other files.
+ */
+
+#include <sys/types.h>
+#include <sys/t_lock.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/user.h>
+#include <sys/fstyp.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/fem.h>
+#include <sys/mntent.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/statfs.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/dnlc.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/atomic.h>
+#include <sys/cmn_err.h>
+#include <sys/buf.h>
+#include <sys/debug.h>
+#include <sys/vnode.h>
+#include <sys/ddi.h>
+#include <sys/pathname.h>
+#include <sys/poll.h>
+#include <sys/sunddi.h>
+#include <sys/sysmacros.h>
+#include <sys/zone.h>
+#include <sys/policy.h>
+#include <sys/attr.h>
+#include <fs/fs_subr.h>
+
+#include <libfksmbfs.h>
+
+static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
+static void vfs_setmntopt_nolock(mntopts_t *, const char *,
+ const char *, int, int);
+static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
+// static void vfs_freemnttab(struct vfs *);
+static void vfs_freeopt(mntopt_t *);
+static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
+static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
+static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
+// static void vfs_createopttbl_extend(mntopts_t *, const char *,
+// const mntopts_t *);
+// static char **vfs_copycancelopt_extend(char **const, int);
+static void vfs_freecancelopt(char **);
+
+/*
+ * VFS global data.
+ */
+vnode_t *rootdir; /* pointer to root inode vnode. */
+struct vfs *rootvfs = NULL; /* pointer to root vfs; head of VFS list. */
+static krwlock_t vfslist;
+struct vfs *zone_vfslist; /* list of FS's mounted in zone */
+
+/* from os/vfs_conf.c */
+const int nfstype = 5;
+struct vfssw vfssw[10] = {
+ { "BADVFS" }, /* 0:invalid */
+ { "" }, /* reserved for loadable fs */
+ { "" },
+ { "" },
+ { "" },
+};
+
+/*
+ * Table for generic options recognized in the VFS layer and acted
+ * on at this level before parsing file system specific options.
+ * The nosuid option is stronger than any of the devices and setuid
+ * options, so those are canceled when nosuid is seen.
+ *
+ * All options which are added here need to be added to the
+ * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
+ */
+/*
+ * VFS Mount options table
+ */
+static char *ro_cancel[] = { MNTOPT_RW, NULL };
+static char *rw_cancel[] = { MNTOPT_RO, NULL };
+static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
+static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
+ MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
+static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
+static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
+static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
+static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
+static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
+static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
+static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
+static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
+
+static const mntopt_t mntopts[] = {
+/*
+ * option name cancel options default arg flags
+ */
+ { MNTOPT_REMOUNT, NULL, NULL,
+ MO_NODISPLAY, (void *)0 },
+ { MNTOPT_RO, ro_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_RW, rw_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_SUID, suid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOSUID, nosuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_DEVICES, devices_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NODEVICES, nodevices_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_SETUID, setuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOSETUID, nosetuid_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NBMAND, nbmand_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NONBMAND, nonbmand_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_EXEC, exec_cancel, NULL, 0,
+ (void *)0 },
+ { MNTOPT_NOEXEC, noexec_cancel, NULL, 0,
+ (void *)0 },
+};
+
+const mntopts_t vfs_mntopts = {
+ sizeof (mntopts) / sizeof (mntopt_t),
+ (mntopt_t *)&mntopts[0]
+};
+
+/*
+ * File system operation dispatch functions.
+ */
+
+int
+fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
+}
+
+int
+fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
+}
+
+int
+fsop_root(vfs_t *vfsp, vnode_t **vpp)
+{
+ return ((*(vfsp)->vfs_op->vfs_root)(vfsp, vpp));
+}
+
+int
+fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
+{
+ return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
+}
+
+int
+fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
+{
+ return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
+}
+
+int
+fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
+{
+ return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
+}
+
+int
+fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
+{
+ return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
+}
+
+void
+fsop_freefs(vfs_t *vfsp)
+{
+ (*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
+}
+
+int
+fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
+{
+ return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
+}
+
+int
+fsop_sync_by_kind(int fstype, short flag, cred_t *cr)
+{
+ ASSERT((fstype >= 0) && (fstype < nfstype));
+
+ if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
+ return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
+ else
+ return (ENOTSUP);
+}
+
+/*
+ * File system initialization. vfs_setfsops() must be called from a file
+ * system's init routine.
+ */
+
+static int
+fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
+ int *unused_ops)
+{
+ static const fs_operation_trans_def_t vfs_ops_table[] = {
+ VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
+ (fs_generic_func_p) fs_sync,
+ (fs_generic_func_p) fs_sync, /* No errors allowed */
+
+ VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
+ fs_nosys, fs_nosys,
+
+ VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
+ (fs_generic_func_p)fs_freevfs,
+ (fs_generic_func_p)fs_freevfs, /* Shouldn't fail */
+
+ VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
+ (fs_generic_func_p)fs_nosys,
+ (fs_generic_func_p)fs_nosys,
+
+ NULL, 0, NULL, NULL
+ };
+
+ return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
+}
+
+/* zfs_boot_init() */
+
+int
+vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
+{
+ int error;
+ int unused_ops;
+
+ /*
+ * Verify that fstype refers to a valid fs. Note that
+ * 0 is valid since it's used to set "stray" ops.
+ */
+ if ((fstype < 0) || (fstype >= nfstype))
+ return (EINVAL);
+
+ if (!ALLOCATED_VFSSW(&vfssw[fstype]))
+ return (EINVAL);
+
+ /* Set up the operations vector. */
+
+ error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
+
+ if (error != 0)
+ return (error);
+
+ vfssw[fstype].vsw_flag |= VSW_INSTALLED;
+
+ if (actual != NULL)
+ *actual = &vfssw[fstype].vsw_vfsops;
+
+#if DEBUG
+ if (unused_ops != 0)
+ cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
+ "but not used", vfssw[fstype].vsw_name, unused_ops);
+#endif
+
+ return (0);
+}
+
+int
+vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
+{
+ int error;
+ int unused_ops;
+
+ *actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
+
+ error = fs_copyfsops(template, *actual, &unused_ops);
+ if (error != 0) {
+ kmem_free(*actual, sizeof (vfsops_t));
+ *actual = NULL;
+ return (error);
+ }
+
+ return (0);
+}
+
+/*
+ * Free a vfsops structure created as a result of vfs_makefsops().
+ * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
+ * vfs_freevfsops_by_type().
+ */
+void
+vfs_freevfsops(vfsops_t *vfsops)
+{
+ kmem_free(vfsops, sizeof (vfsops_t));
+}
+
+/*
+ * Since the vfsops structure is part of the vfssw table and wasn't
+ * really allocated, we're not really freeing anything. We keep
+ * the name for consistency with vfs_freevfsops(). We do, however,
+ * need to take care of a little bookkeeping.
+ * NOTE: For a vfsops structure created by vfs_setfsops(), use
+ * vfs_freevfsops_by_type().
+ */
+int
+vfs_freevfsops_by_type(int fstype)
+{
+
+ /* Verify that fstype refers to a loaded fs (and not fsid 0). */
+ if ((fstype <= 0) || (fstype >= nfstype))
+ return (EINVAL);
+
+ WLOCK_VFSSW();
+ if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
+ WUNLOCK_VFSSW();
+ return (EINVAL);
+ }
+
+ vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
+ WUNLOCK_VFSSW();
+
+ return (0);
+}
+
+/* Support routines used to reference vfs_op */
+
+/* Set the operations vector for a vfs */
+void
+vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
+{
+
+ ASSERT(vfsp != NULL);
+ ASSERT(vfsops != NULL);
+
+ vfsp->vfs_op = vfsops;
+}
+
+/* Retrieve the operations vector for a vfs */
+vfsops_t *
+vfs_getops(vfs_t *vfsp)
+{
+
+ ASSERT(vfsp != NULL);
+
+ return (vfsp->vfs_op);
+}
+
+/*
+ * Returns non-zero (1) if the vfsops matches that of the vfs.
+ * Returns zero (0) if not.
+ */
+int
+vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
+{
+ return (vfs_getops(vfsp) == vfsops);
+}
+
+/*
+ * Returns non-zero (1) if the file system has installed a non-default,
+ * non-error vfs_sync routine. Returns zero (0) otherwise.
+ */
+int
+vfs_can_sync(vfs_t *vfsp)
+{
+ /* vfs_sync() routine is not the default/error function */
+ return (vfs_getops(vfsp)->vfs_sync != fs_sync);
+}
+
+/*
+ * Initialize a vfs structure.
+ */
+void
+vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
+{
+ /* Always do full init, like vfs_alloc() */
+ bzero(vfsp, sizeof (vfs_t));
+ vfsp->vfs_count = 0;
+ vfsp->vfs_next = vfsp;
+ vfsp->vfs_prev = vfsp;
+ vfsp->vfs_zone_next = vfsp;
+ vfsp->vfs_zone_prev = vfsp;
+ vfsp->vfs_lofi_id = 0;
+ sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
+ vfsimpl_setup(vfsp);
+ vfsp->vfs_data = (data);
+ vfs_setops((vfsp), (op));
+}
+
+/*
+ * Allocate and initialize the vfs implementation private data
+ * structure, vfs_impl_t.
+ */
+void
+vfsimpl_setup(vfs_t *vfsp)
+{
+ int i;
+
+ if (vfsp->vfs_implp != NULL) {
+ return;
+ }
+
+ vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
+ /* Note that these are #define'd in vfs.h */
+ vfsp->vfs_vskap = NULL;
+ vfsp->vfs_fstypevsp = NULL;
+
+ /* Set size of counted array, then zero the array */
+ vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
+ for (i = 1; i < VFS_FEATURE_MAXSZ; i++) {
+ vfsp->vfs_featureset[i] = 0;
+ }
+}
+
+/*
+ * Release the vfs_impl_t structure, if it exists. Some unbundled
+ * filesystems may not use the newer version of vfs and thus
+ * would not contain this implementation private data structure.
+ */
+void
+vfsimpl_teardown(vfs_t *vfsp)
+{
+ vfs_impl_t *vip = vfsp->vfs_implp;
+
+ if (vip == NULL)
+ return;
+
+ kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
+ vfsp->vfs_implp = NULL;
+}
+
+/*
+ * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
+ * fstatvfs, and sysfs moved to common/syscall.
+ */
+
+// vfs_sync, sync
+
+/*
+ * External routines.
+ */
+
+krwlock_t vfssw_lock; /* lock accesses to vfssw */
+
+/*
+ * Lock for accessing the vfs linked list. Initialized in vfs_mountroot(),
+ * but otherwise should be accessed only via vfs_list_lock() and
+ * vfs_list_unlock(). Also used to protect the timestamp for mods to the list.
+ */
+static krwlock_t vfslist;
+
+// vfs_mountdevices(void)
+// vfs_mountdev1(void)
+// vfs_mountfs()
+// vfs_mountroot()
+// lofi_add, lofi_remove
+
+
+/*
+ * Mount the FS for the test jig. Based on domount()
+ */
+int
+fake_domount(char *fsname, struct mounta *uap, struct vfs **vfspp)
+{
+ vnode_t *vp;
+ struct cred *credp;
+ struct vfssw *vswp;
+ vfsops_t *vfsops;
+ struct vfs *vfsp = NULL;
+ mntopts_t mnt_mntopts;
+ int error = 0;
+ int copyout_error = 0;
+ char *opts = uap->optptr;
+ char *inargs = opts;
+ int optlen = uap->optlen;
+
+ credp = CRED();
+
+ /*
+ * Test jig specific: mount on rootdir
+ */
+ if (rootvfs != NULL)
+ return (EBUSY);
+ vp = rootdir;
+
+ /*
+ * The v_flag value for the mount point vp is permanently set
+ * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
+ * for mount point locking.
+ */
+ mutex_enter(&vp->v_lock);
+ vp->v_flag |= VVFSLOCK;
+ mutex_exit(&vp->v_lock);
+
+ mnt_mntopts.mo_count = 0;
+
+ /*
+ * Find the ops vector to use to invoke the file system-specific mount
+ * method. If the fsname argument is non-NULL, use it directly.
+ */
+ if ((vswp = vfs_getvfssw(fsname)) == NULL) {
+ return (EINVAL);
+ }
+ if (!VFS_INSTALLED(vswp))
+ return (EINVAL);
+
+ // secpolicy_fs_allowed_mount(fsname)
+
+ vfsops = &vswp->vsw_vfsops;
+
+ vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
+
+ /*
+ * Fetch mount options and parse them for generic vfs options
+ */
+ if (uap->flags & MS_OPTIONSTR) {
+ /*
+ * Limit the buffer size
+ */
+ if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
+ error = EINVAL;
+ goto errout;
+ }
+ if ((uap->flags & MS_SYSSPACE) == 0) {
+ inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
+ inargs[0] = '\0';
+ if (optlen) {
+ error = copyinstr(opts, inargs, (size_t)optlen,
+ NULL);
+ if (error) {
+ goto errout;
+ }
+ }
+ }
+ vfs_parsemntopts(&mnt_mntopts, inargs, 0);
+ }
+ /*
+ * Flag bits override the options string.
+ */
+ if (uap->flags & MS_REMOUNT)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
+ if (uap->flags & MS_RDONLY)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
+ if (uap->flags & MS_NOSUID)
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+
+ /*
+ * Check if this is a remount; must be set in the option string and
+ * the file system must support a remount option.
+ */
+ if (vfs_optionisset_nolock(&mnt_mntopts,
+ MNTOPT_REMOUNT, NULL)) {
+ /* disallow here */
+ error = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * uap->flags and vfs_optionisset() should agree.
+ */
+ if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
+ uap->flags |= MS_RDONLY;
+ }
+ if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
+ uap->flags |= MS_NOSUID;
+ }
+ // nbmand ...
+
+ /*
+ * If we are splicing the fs into the namespace,
+ * perform mount point checks...
+ * (always splice=0 here)
+ */
+
+ if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
+ uap->dataptr = NULL;
+ uap->datalen = 0;
+ }
+
+ /*
+ * If this is a remount, ... (never here)
+ */
+ vfsp = vfs_alloc(KM_SLEEP);
+ VFS_INIT(vfsp, vfsops, NULL);
+
+ VFS_HOLD(vfsp);
+
+ // lofi_add(fsname, vfsp, &mnt_mntopts, uap)
+
+ /*
+ * PRIV_SYS_MOUNT doesn't mean you can become root.
+ */
+ uap->flags |= MS_NOSUID;
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+
+ /*
+ * The vfs_reflock...
+ */
+
+ /*
+ * Lock the vfs...
+ */
+ if ((error = vfs_lock(vfsp)) != 0) {
+ vfs_free(vfsp);
+ vfsp = NULL;
+ goto errout;
+ }
+
+ /*
+ * Add device to mount in progress table...
+ */
+ /*
+ * Invalidate cached entry for the mount point.
+ */
+
+ /*
+ * If have an option string but the filesystem doesn't supply a
+ * prototype options table, create a table...
+ */
+
+ /*
+ * Serialize with zone state transitions...
+ */
+
+ // mount_in_progress(zone);
+
+ /*
+ * Instantiate (or reinstantiate) the file system...
+ */
+ vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
+
+ vfs_setresource(vfsp, uap->spec, 0);
+ vfs_setmntpoint(vfsp, uap->dir, 0);
+
+ /*
+ * going to mount on this vnode, so notify.
+ */
+ // vnevent_mountedover(vp, NULL);
+ error = VFS_MOUNT(vfsp, vp, uap, credp);
+
+ if (uap->flags & MS_RDONLY)
+ vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+ if (uap->flags & MS_NOSUID)
+ vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
+ if (uap->flags & MS_GLOBAL)
+ vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
+
+ if (error) {
+ // lofi_remove(vfsp);
+
+ // (remount == 0)
+ vfs_unlock(vfsp);
+ // vfs_freemnttab(vfsp);
+ vfs_free(vfsp);
+ vfsp = NULL;
+ } else {
+ /*
+ * Set the mount time to now
+ */
+ // vfsp->vfs_mtime = ddi_get_time();
+ // if (remount) ...
+ // else if (splice) vfs_add(vp, vfsp, flags)
+ // else VFS_HOLD(vfsp);
+
+ /*
+ * Test jig specific:
+ * Do sort of like vfs_add for vp=rootdir
+ * Already have hold on vp.
+ */
+ vfsp->vfs_vnodecovered = vp;
+ vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
+ VFS_HOLD(vfsp);
+ rootvfs = vfsp;
+
+ /*
+ * Set flags for global options encountered
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
+ vfsp->vfs_flag |= VFS_RDONLY;
+ else
+ vfsp->vfs_flag &= ~VFS_RDONLY;
+ if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
+ vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
+ } else {
+ if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
+ vfsp->vfs_flag |= VFS_NODEVICES;
+ else
+ vfsp->vfs_flag &= ~VFS_NODEVICES;
+ if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
+ vfsp->vfs_flag |= VFS_NOSETUID;
+ else
+ vfsp->vfs_flag &= ~VFS_NOSETUID;
+ }
+ if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
+ vfsp->vfs_flag |= VFS_NBMAND;
+ else
+ vfsp->vfs_flag &= ~VFS_NBMAND;
+
+ if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
+ vfsp->vfs_flag |= VFS_XATTR;
+ else
+ vfsp->vfs_flag &= ~VFS_XATTR;
+
+ if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
+ vfsp->vfs_flag |= VFS_NOEXEC;
+ else
+ vfsp->vfs_flag &= ~VFS_NOEXEC;
+
+ /*
+ * Now construct the output option string of options
+ * we recognized.
+ */
+ if (uap->flags & MS_OPTIONSTR) {
+ vfs_list_read_lock();
+ copyout_error = vfs_buildoptionstr(
+ &vfsp->vfs_mntopts, inargs, optlen);
+ vfs_list_unlock();
+ if (copyout_error == 0 &&
+ (uap->flags & MS_SYSSPACE) == 0) {
+ copyout_error = copyout(inargs, opts, optlen);
+ }
+ }
+
+ /*
+ * If this isn't a remount, set up the vopstats...
+ */
+ if (vswp->vsw_flag & VSW_XID)
+ vfsp->vfs_flag |= VFS_XID;
+
+ vfs_unlock(vfsp);
+
+ /*
+ * Test jig specicific:
+ * Replace rootdir with the mounted root.
+ */
+ error = VFS_ROOT(vfsp, &rootdir);
+ if (error != 0) {
+ panic("fake_domount, get root %d\n", error);
+ }
+ }
+ // mount_completed(zone);
+ // zone_rele(zone);
+
+ // if (splice)
+ // vn_vfsunlock(vp);
+
+ if ((error == 0) && (copyout_error == 0)) {
+ /* get_vskstat_anchor() */
+ /* Return vfsp to caller. */
+ *vfspp = vfsp;
+ }
+errout:
+ vfs_freeopttbl(&mnt_mntopts);
+ /* resource, mountpt not allocated */
+ /* no addmip, delmip */
+ ASSERT(vswp != NULL);
+ vfs_unrefvfssw(vswp);
+ if (inargs != opts)
+ kmem_free(inargs, MAX_MNTOPT_STR);
+ if (copyout_error) {
+ if (vfsp != NULL) {
+ // lofi_remove(vfsp);
+ VFS_RELE(vfsp);
+ }
+ error = copyout_error;
+ }
+ return (error);
+}
+
+
+static void
+vfs_setpath(
+ struct vfs *vfsp, /* vfs being updated */
+ refstr_t **refp, /* Ref-count string to contain the new path */
+ const char *newpath, /* Path to add to refp (above) */
+ uint32_t flag) /* flag */
+{
+ // size_t len;
+ refstr_t *ref;
+ // char *sp;
+ int have_list_lock = 0;
+
+ ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
+
+ /*
+ * New path must be less than MAXPATHLEN because mntfs
+ * will only display up to MAXPATHLEN bytes. This is currently
+ * safe, because domount() uses pn_get(), and other callers
+ * similarly cap the size to fewer than MAXPATHLEN bytes.
+ */
+
+ ASSERT(strlen(newpath) < MAXPATHLEN);
+
+ /* mntfs requires consistency while vfs list lock is held */
+
+ if (VFS_ON_LIST(vfsp)) {
+ have_list_lock = 1;
+ vfs_list_lock();
+ }
+
+ if (*refp != NULL)
+ refstr_rele(*refp);
+
+ /*
+ * If we are in a non-global zone... (do something else)
+ */
+ ref = refstr_alloc(newpath);
+ *refp = ref;
+
+ if (have_list_lock) {
+ vfs_mnttab_modtimeupd();
+ vfs_list_unlock();
+ }
+}
+
+/*
+ * Record a mounted resource name in a vfs structure.
+ * If vfsp is already mounted, caller must hold the vfs lock.
+ */
+void
+vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag)
+{
+ if (resource == NULL || resource[0] == '\0')
+ resource = VFS_NORESOURCE;
+ vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag);
+}
+
+/*
+ * Record a mount point name in a vfs structure.
+ * If vfsp is already mounted, caller must hold the vfs lock.
+ */
+void
+vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag)
+{
+ if (mntpt == NULL || mntpt[0] == '\0')
+ mntpt = VFS_NOMNTPT;
+ vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag);
+}
+
+/* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
+
+refstr_t *
+vfs_getresource(const struct vfs *vfsp)
+{
+ refstr_t *resource;
+
+ vfs_list_read_lock();
+ resource = vfsp->vfs_resource;
+ refstr_hold(resource);
+ vfs_list_unlock();
+
+ return (resource);
+}
+
+/* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
+
+refstr_t *
+vfs_getmntpoint(const struct vfs *vfsp)
+{
+ refstr_t *mntpt;
+
+ vfs_list_read_lock();
+ mntpt = vfsp->vfs_mntpt;
+ refstr_hold(mntpt);
+ vfs_list_unlock();
+
+ return (mntpt);
+}
+
+// vfs_createopttbl_extend
+// vfs_createopttbl
+
+/*
+ * Swap two mount options tables
+ */
+static void
+vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
+{
+ uint_t tmpcnt;
+ mntopt_t *tmplist;
+
+ tmpcnt = optbl2->mo_count;
+ tmplist = optbl2->mo_list;
+ optbl2->mo_count = optbl1->mo_count;
+ optbl2->mo_list = optbl1->mo_list;
+ optbl1->mo_count = tmpcnt;
+ optbl1->mo_list = tmplist;
+}
+
+static void
+vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
+{
+ vfs_list_lock();
+ vfs_swapopttbl_nolock(optbl1, optbl2);
+ vfs_mnttab_modtimeupd();
+ vfs_list_unlock();
+}
+
+static char **
+vfs_copycancelopt_extend(char **const moc, int extend)
+{
+ int i = 0;
+ int j;
+ char **result;
+
+ if (moc != NULL) {
+ for (; moc[i] != NULL; i++)
+ /* count number of options to cancel */;
+ }
+
+ if (i + extend == 0)
+ return (NULL);
+
+ result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
+
+ for (j = 0; j < i; j++) {
+ result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
+ (void) strcpy(result[j], moc[j]);
+ }
+ for (; j <= i + extend; j++)
+ result[j] = NULL;
+
+ return (result);
+}
+
+static void
+vfs_copyopt(const mntopt_t *s, mntopt_t *d)
+{
+ char *sp, *dp;
+
+ d->mo_flags = s->mo_flags;
+ d->mo_data = s->mo_data;
+ sp = s->mo_name;
+ if (sp != NULL) {
+ dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
+ (void) strcpy(dp, sp);
+ d->mo_name = dp;
+ } else {
+ d->mo_name = NULL; /* should never happen */
+ }
+
+ d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
+
+ sp = s->mo_arg;
+ if (sp != NULL) {
+ dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
+ (void) strcpy(dp, sp);
+ d->mo_arg = dp;
+ } else {
+ d->mo_arg = NULL;
+ }
+}
+
+// vfs_copyopttbl_extend
+// vfs_copyopttbl
+
+/*
+ * Copy a mount options table, possibly allocating some spare
+ * slots at the end. It is permissible to copy_extend the NULL table.
+ */
+static void
+vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
+{
+ uint_t i, count;
+ mntopt_t *motbl;
+
+ /*
+ * Clear out any existing stuff in the options table being initialized
+ */
+ vfs_freeopttbl(dmo);
+ count = (smo == NULL) ? 0 : smo->mo_count;
+ if ((count + extra) == 0) /* nothing to do */
+ return;
+ dmo->mo_count = count + extra;
+ motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
+ dmo->mo_list = motbl;
+ for (i = 0; i < count; i++) {
+ vfs_copyopt(&smo->mo_list[i], &motbl[i]);
+ }
+ for (i = count; i < count + extra; i++) {
+ motbl[i].mo_flags = MO_EMPTY;
+ }
+}
+
+/*
+ * Copy a mount options table.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect smo and dmo.
+ */
+void
+vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
+{
+ vfs_copyopttbl_extend(smo, dmo, 0);
+}
+
+static char **
+vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2)
+{
+ int c1 = 0;
+ int c2 = 0;
+ char **result;
+ char **sp1, **sp2, **dp;
+
+ /*
+ * First we count both lists of cancel options.
+ * If either is NULL or has no elements, we return a copy of
+ * the other.
+ */
+ if (mop1->mo_cancel != NULL) {
+ for (; mop1->mo_cancel[c1] != NULL; c1++)
+ /* count cancel options in mop1 */;
+ }
+
+ if (c1 == 0)
+ return (vfs_copycancelopt_extend(mop2->mo_cancel, 0));
+
+ if (mop2->mo_cancel != NULL) {
+ for (; mop2->mo_cancel[c2] != NULL; c2++)
+ /* count cancel options in mop2 */;
+ }
+
+ result = vfs_copycancelopt_extend(mop1->mo_cancel, c2);
+
+ if (c2 == 0)
+ return (result);
+
+ /*
+ * When we get here, we've got two sets of cancel options;
+ * we need to merge the two sets. We know that the result
+ * array has "c1+c2+1" entries and in the end we might shrink
+ * it.
+ * Result now has a copy of the c1 entries from mop1; we'll
+ * now lookup all the entries of mop2 in mop1 and copy it if
+ * it is unique.
+ * This operation is O(n^2) but it's only called once per
+ * filesystem per duplicate option. This is a situation
+ * which doesn't arise with the filesystems in ON and
+ * n is generally 1.
+ */
+
+ dp = &result[c1];
+ for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) {
+ for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) {
+ if (strcmp(*sp1, *sp2) == 0)
+ break;
+ }
+ if (*sp1 == NULL) {
+ /*
+ * Option *sp2 not found in mop1, so copy it.
+ * The calls to vfs_copycancelopt_extend()
+ * guarantee that there's enough room.
+ */
+ *dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP);
+ (void) strcpy(*dp++, *sp2);
+ }
+ }
+ if (dp != &result[c1+c2]) {
+ size_t bytes = (dp - result + 1) * sizeof (char *);
+ char **nres = kmem_alloc(bytes, KM_SLEEP);
+
+ bcopy(result, nres, bytes);
+ kmem_free(result, (c1 + c2 + 1) * sizeof (char *));
+ result = nres;
+ }
+ return (result);
+}
+
+/*
+ * Merge two mount option tables (outer and inner) into one. This is very
+ * similar to "merging" global variables and automatic variables in C.
+ *
+ * This isn't (and doesn't have to be) fast.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect omo, imo & dmo.
+ */
+void
+vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo)
+{
+ uint_t i, count;
+ mntopt_t *mop, *motbl;
+ uint_t freeidx;
+
+ /*
+ * First determine how much space we need to allocate.
+ */
+ count = omo->mo_count;
+ for (i = 0; i < imo->mo_count; i++) {
+ if (imo->mo_list[i].mo_flags & MO_EMPTY)
+ continue;
+ if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL)
+ count++;
+ }
+ ASSERT(count >= omo->mo_count &&
+ count <= omo->mo_count + imo->mo_count);
+ motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP);
+ for (i = 0; i < omo->mo_count; i++)
+ vfs_copyopt(&omo->mo_list[i], &motbl[i]);
+ freeidx = omo->mo_count;
+ for (i = 0; i < imo->mo_count; i++) {
+ if (imo->mo_list[i].mo_flags & MO_EMPTY)
+ continue;
+ if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) {
+ char **newcanp;
+ uint_t index = mop - omo->mo_list;
+
+ newcanp = vfs_mergecancelopts(mop, &motbl[index]);
+
+ vfs_freeopt(&motbl[index]);
+ vfs_copyopt(&imo->mo_list[i], &motbl[index]);
+
+ vfs_freecancelopt(motbl[index].mo_cancel);
+ motbl[index].mo_cancel = newcanp;
+ } else {
+ /*
+ * If it's a new option, just copy it over to the first
+ * free location.
+ */
+ vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]);
+ }
+ }
+ dmo->mo_count = count;
+ dmo->mo_list = motbl;
+}
+
+/*
+ * Functions to set and clear mount options in a mount options table.
+ */
+
+/*
+ * Clear a mount option, if it exists.
+ *
+ * The update_mnttab arg indicates whether mops is part of a vfs that is on
+ * the vfs list.
+ */
+static void
+vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name))
+ continue;
+ mop->mo_flags &= ~MO_SET;
+ if (mop->mo_arg != NULL) {
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+ }
+ mop->mo_arg = NULL;
+ if (update_mnttab)
+ vfs_mnttab_modtimeupd();
+ break;
+ }
+}
+
+void
+vfs_clearmntopt(struct vfs *vfsp, const char *opt)
+{
+ int gotlock = 0;
+
+ if (VFS_ON_LIST(vfsp)) {
+ gotlock = 1;
+ vfs_list_lock();
+ }
+ vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock);
+ if (gotlock)
+ vfs_list_unlock();
+}
+
+
+/*
+ * Set a mount option on...
+ */
+static void
+vfs_setmntopt_nolock(mntopts_t *mops, const char *opt,
+ const char *arg, int flags, int update_mnttab)
+{
+ mntopt_t *mop;
+ uint_t i, count;
+ char *sp;
+
+ ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
+
+ if (flags & VFS_CREATEOPT) {
+ if (vfs_hasopt(mops, opt) != NULL) {
+ flags &= ~VFS_CREATEOPT;
+ }
+ }
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY) {
+ if ((flags & VFS_CREATEOPT) == 0)
+ continue;
+ sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP);
+ (void) strcpy(sp, opt);
+ mop->mo_name = sp;
+ if (arg != NULL)
+ mop->mo_flags = MO_HASVALUE;
+ else
+ mop->mo_flags = 0;
+ } else if (strcmp(opt, mop->mo_name)) {
+ continue;
+ }
+ if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT))
+ break;
+ if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) {
+ sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP);
+ (void) strcpy(sp, arg);
+ } else {
+ sp = NULL;
+ }
+ if (mop->mo_arg != NULL)
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+ mop->mo_arg = sp;
+ if (flags & VFS_DISPLAY)
+ mop->mo_flags &= ~MO_NODISPLAY;
+ if (flags & VFS_NODISPLAY)
+ mop->mo_flags |= MO_NODISPLAY;
+ mop->mo_flags |= MO_SET;
+ if (mop->mo_cancel != NULL) {
+ char **cp;
+
+ for (cp = mop->mo_cancel; *cp != NULL; cp++)
+ vfs_clearmntopt_nolock(mops, *cp, 0);
+ }
+ if (update_mnttab)
+ vfs_mnttab_modtimeupd();
+ break;
+ }
+}
+
+void
+vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags)
+{
+ int gotlock = 0;
+
+ if (VFS_ON_LIST(vfsp)) {
+ gotlock = 1;
+ vfs_list_lock();
+ }
+ vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock);
+ if (gotlock)
+ vfs_list_unlock();
+}
+
+// vfs_addtag
+// vfs_settag
+// vfs_clrtag
+
+/*
+ * Function to parse an option string and fill in a mount options table.
+ * Unknown options are silently ignored. The input option string is modified
+ * by replacing separators with nulls. If the create flag is set, options
+ * not found in the table are just added on the fly. The table must have
+ * an option slot marked MO_EMPTY to add an option on the fly.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mops..
+ */
+void
+vfs_parsemntopts(mntopts_t *mops, char *osp, int create)
+{
+ char *s = osp, *p, *nextop, *valp, *cp, *ep = NULL;
+ int setflg = VFS_NOFORCEOPT;
+
+ if (osp == NULL)
+ return;
+ while (*s != '\0') {
+ p = strchr(s, ','); /* find next option */
+ if (p == NULL) {
+ cp = NULL;
+ p = s + strlen(s);
+ } else {
+ cp = p; /* save location of comma */
+ *p++ = '\0'; /* mark end and point to next option */
+ }
+ nextop = p;
+ p = strchr(s, '='); /* look for value */
+ if (p == NULL) {
+ valp = NULL; /* no value supplied */
+ ep = NULL;
+ } else {
+ ep = p; /* save location of equals */
+ *p++ = '\0'; /* end option and point to value */
+ valp = p;
+ }
+ /*
+ * set option into options table
+ */
+ if (create)
+ setflg |= VFS_CREATEOPT;
+ vfs_setmntopt_nolock(mops, s, valp, setflg, 0);
+ if (cp != NULL)
+ *cp = ','; /* restore the comma */
+ if (valp != NULL)
+ *ep = '='; /* restore the equals */
+ s = nextop;
+ }
+}
+
+/*
+ * Function to inquire if an option exists in a mount options table.
+ * Returns a pointer to the option if it exists, else NULL.
+ */
+struct mntopt *
+vfs_hasopt(const mntopts_t *mops, const char *opt)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name) == 0)
+ return (mop);
+ }
+ return (NULL);
+}
+
+/*
+ * Function to inquire if an option is set in a mount options table.
+ * Returns non-zero if set and fills in the arg pointer with a pointer to
+ * the argument string or NULL if there is no argument string.
+ */
+static int
+vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp)
+{
+ struct mntopt *mop;
+ uint_t i, count;
+
+ count = mops->mo_count;
+ for (i = 0; i < count; i++) {
+ mop = &mops->mo_list[i];
+
+ if (mop->mo_flags & MO_EMPTY)
+ continue;
+ if (strcmp(opt, mop->mo_name))
+ continue;
+ if ((mop->mo_flags & MO_SET) == 0)
+ return (0);
+ if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0)
+ *argp = mop->mo_arg;
+ return (1);
+ }
+ return (0);
+}
+
+
+int
+vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp)
+{
+ int ret;
+
+ vfs_list_read_lock();
+ ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp);
+ vfs_list_unlock();
+ return (ret);
+}
+
+
+/*
+ * Construct a comma separated string of the options set in the given
+ * mount table, return the string in the given buffer. Return non-zero if
+ * the buffer would overflow.
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mp.
+ */
+int
+vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len)
+{
+ char *cp;
+ uint_t i;
+
+ buf[0] = '\0';
+ cp = buf;
+ for (i = 0; i < mp->mo_count; i++) {
+ struct mntopt *mop;
+
+ mop = &mp->mo_list[i];
+ if (mop->mo_flags & MO_SET) {
+ int optlen, comma = 0;
+
+ if (buf[0] != '\0')
+ comma = 1;
+ optlen = strlen(mop->mo_name);
+ if (strlen(buf) + comma + optlen + 1 > len)
+ goto err;
+ if (comma)
+ *cp++ = ',';
+ (void) strcpy(cp, mop->mo_name);
+ cp += optlen;
+ /*
+ * Append option value if there is one
+ */
+ if (mop->mo_arg != NULL) {
+ int arglen;
+
+ arglen = strlen(mop->mo_arg);
+ if (strlen(buf) + arglen + 2 > len)
+ goto err;
+ *cp++ = '=';
+ (void) strcpy(cp, mop->mo_arg);
+ cp += arglen;
+ }
+ }
+ }
+ return (0);
+err:
+ return (EOVERFLOW);
+}
+
+static void
+vfs_freecancelopt(char **moc)
+{
+ if (moc != NULL) {
+ int ccnt = 0;
+ char **cp;
+
+ for (cp = moc; *cp != NULL; cp++) {
+ kmem_free(*cp, strlen(*cp) + 1);
+ ccnt++;
+ }
+ kmem_free(moc, (ccnt + 1) * sizeof (char *));
+ }
+}
+
+static void
+vfs_freeopt(mntopt_t *mop)
+{
+ if (mop->mo_name != NULL)
+ kmem_free(mop->mo_name, strlen(mop->mo_name) + 1);
+
+ vfs_freecancelopt(mop->mo_cancel);
+
+ if (mop->mo_arg != NULL)
+ kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
+}
+
+/*
+ * Free a mount options table
+ *
+ * This function is *not* for general use by filesystems.
+ *
+ * Note: caller is responsible for locking the vfs list, if needed,
+ * to protect mp.
+ */
+void
+vfs_freeopttbl(mntopts_t *mp)
+{
+ uint_t i, count;
+
+ count = mp->mo_count;
+ for (i = 0; i < count; i++) {
+ vfs_freeopt(&mp->mo_list[i]);
+ }
+ if (count) {
+ kmem_free(mp->mo_list, sizeof (mntopt_t) * count);
+ mp->mo_count = 0;
+ mp->mo_list = NULL;
+ }
+}
+
+// vfs_mntdummyread
+// vfs_mntdummywrite
+// vfs_mntdummygetattr
+// vfs_mnttabvp_setup
+// vfs_mnttab_rwop
+// vfs_mnttab_writeop
+// vfs_mnttab_readop
+// vfs_freemnttab
+// vfs_mnttab_modtime
+// vfs_mnttab_poll
+// vfs_mono_time
+
+/*
+ * Update the mnttab modification time...
+ */
+void
+vfs_mnttab_modtimeupd()
+{
+}
+
+/*
+ * Unlike the real dounmount, we don't have
+ * vn_vfswlock_held(coveredvp)
+ */
+int
+fake_dounmount(struct vfs *vfsp, int flag)
+{
+ cred_t *cr = CRED();
+ vnode_t *coveredvp;
+ int error;
+
+ /*
+ * Get covered vnode. This will be NULL if the vfs is not linked
+ * into the file system name space (i.e., domount() with MNT_NOSPICE).
+ */
+ coveredvp = vfsp->vfs_vnodecovered;
+
+ /* For forcible umount, skip VFS_SYNC() since it may hang */
+ if ((flag & MS_FORCE) == 0)
+ (void) VFS_SYNC(vfsp, 0, cr);
+
+ /*
+ * Test-jig specific:
+ * Need to release rootdir before unmount or VFS_UNMOUNT
+ * may fail due to that node being active.
+ */
+ if (rootdir != NULL) {
+ ASSERT(rootdir != coveredvp);
+ VN_RELE(rootdir);
+ rootdir = NULL;
+ }
+
+ /*
+ * Lock the vfs to maintain fs status quo during unmount. This
+ * has to be done after the sync because ufs_update tries to acquire
+ * the vfs_reflock.
+ */
+ vfs_lock_wait(vfsp);
+
+ if ((error = VFS_UNMOUNT(vfsp, flag, cr)) != 0) {
+ int err2;
+ vfs_unlock(vfsp);
+ /* Get rootdir back */
+ err2 = VFS_ROOT(vfsp, &rootdir);
+ if (err2 != 0) {
+ panic("fake_dounmount, get root %d\n", err2);
+ }
+ } else {
+ /*
+ * Real dounmount does vfs_remove.
+ *
+ * Test-jig specific:
+ * Restore the covered rootdir,
+ * release the rootvfs hold and clear.
+ */
+ if (coveredvp != NULL) {
+ // vfs_list_remove(vfsp);
+ vfsp->vfs_vnodecovered = NULL;
+ rootdir = coveredvp;
+ }
+ if (rootvfs == vfsp) {
+ VFS_RELE(vfsp);
+ rootvfs = NULL;
+ }
+
+ /*
+ * Release the (final) reference to vfs
+ */
+ vfs_unlock(vfsp);
+ VFS_RELE(vfsp);
+ }
+ return (error);
+}
+
+// vfs_unmountall(void)
+// vfs_addmip
+// vfs_delmip
+// vfs_add
+// vfs_remove
+
+static krwlock_t vpvfsentry_ve_lock;
+
+/*
+ * Lock a filesystem to prevent access to it while mounting,
+ * unmounting and syncing. Return EBUSY immediately if lock
+ * can't be acquired.
+ */
+int
+vfs_lock(vfs_t *vfsp)
+{
+
+ if (rw_tryenter(&vpvfsentry_ve_lock, RW_WRITER))
+ return (0);
+
+ return (EBUSY);
+}
+
+int
+vfs_rlock(vfs_t *vfsp)
+{
+
+ if (rw_tryenter(&vpvfsentry_ve_lock, RW_READER))
+ return (0);
+
+ return (EBUSY);
+}
+
+void
+vfs_lock_wait(vfs_t *vfsp)
+{
+
+ rw_enter(&vpvfsentry_ve_lock, RW_WRITER);
+}
+
+void
+vfs_rlock_wait(vfs_t *vfsp)
+{
+ rw_enter(&vpvfsentry_ve_lock, RW_READER);
+}
+
+/*
+ * Unlock a locked filesystem.
+ */
+void
+vfs_unlock(vfs_t *vfsp)
+{
+
+ rw_exit(&vpvfsentry_ve_lock);
+}
+
+/*
+ * Utility routine that allows a filesystem to construct its
+ * fsid in "the usual way" - by munging some underlying dev_t and
+ * the filesystem type number into the 64-bit fsid. ...
+ */
+void
+vfs_make_fsid(fsid_t *fsi, dev_t dev, int val)
+{
+ if (!cmpldev((dev32_t *)&fsi->val[0], dev))
+ panic("device number too big for fsid!");
+ fsi->val[1] = val;
+}
+
+int
+vfs_lock_held(vfs_t *vfsp)
+{
+ int held;
+
+ held = rw_write_held(&vpvfsentry_ve_lock);
+
+ return (held);
+}
+
+// vfs_lock_owner
+
+/*
+ * vfs list locking.
+ */
+
+void
+vfs_list_lock()
+{
+ rw_enter(&vfslist, RW_WRITER);
+}
+
+void
+vfs_list_read_lock()
+{
+ rw_enter(&vfslist, RW_READER);
+}
+
+void
+vfs_list_unlock()
+{
+ rw_exit(&vfslist);
+}
+
+/*
+ * Low level worker routines for adding entries to and removing entries from
+ * the vfs list.
+ */
+
+// vfs_hash_add
+// vfs_hash_remove
+// vfs_list_add
+// vfs_list_remove
+// getvfs
+// vfs_devmounting
+
+/*
+ * Search the vfs list for a specified device. Returns 1, if entry is found
+ * or 0 if no suitable entry is found.
+ */
+
+int
+vfs_devismounted(dev_t dev)
+{
+ return (0);
+}
+
+// vfs_dev2vfsp
+// vfs_mntpoint2vfsp
+
+/*
+ * Search the vfs list for a specified vfsops.
+ * if vfs entry is found then return 1, else 0.
+ */
+int
+vfs_opsinuse(vfsops_t *ops)
+{
+ return (0);
+}
+
+/*
+ * Allocate an entry in vfssw for a file system type
+ */
+struct vfssw *
+allocate_vfssw(const char *type)
+{
+ struct vfssw *vswp;
+
+ if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) {
+ /*
+ * The vfssw table uses the empty string to identify an
+ * available entry; we cannot add any type which has
+ * a leading NUL. The string length is limited to
+ * the size of the st_fstype array in struct stat.
+ */
+ return (NULL);
+ }
+
+ ASSERT(VFSSW_WRITE_LOCKED());
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++)
+ if (!ALLOCATED_VFSSW(vswp)) {
+ vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP);
+ (void) strcpy(vswp->vsw_name, type);
+ ASSERT(vswp->vsw_count == 0);
+ vswp->vsw_count = 1;
+ mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL);
+ return (vswp);
+ }
+ return (NULL);
+}
+
+// vfs_to_modname
+// vfs_getvfssw
+
+/*
+ * Find a vfssw entry given a file system type name.
+ */
+struct vfssw *
+vfs_getvfssw(const char *type)
+{
+ struct vfssw *vswp;
+
+ if (type == NULL || *type == '\0')
+ return (NULL);
+
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
+ if (strcmp(type, vswp->vsw_name) == 0) {
+ return (vswp);
+ }
+ }
+
+ return (NULL);
+
+}
+
+/*
+ * Find a vfssw entry given a file system type name.
+ */
+struct vfssw *
+vfs_getvfsswbyname(const char *type)
+{
+ struct vfssw *vswp;
+
+ ASSERT(VFSSW_LOCKED());
+ if (type == NULL || *type == '\0')
+ return (NULL);
+
+ for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
+ if (strcmp(type, vswp->vsw_name) == 0) {
+ vfs_refvfssw(vswp);
+ return (vswp);
+ }
+ }
+
+ return (NULL);
+}
+
+// vfs_getvfsswbyvfsops
+
+/*
+ * Reference a vfssw entry.
+ */
+void
+vfs_refvfssw(struct vfssw *vswp)
+{
+
+ mutex_enter(&vswp->vsw_lock);
+ vswp->vsw_count++;
+ mutex_exit(&vswp->vsw_lock);
+}
+
+/*
+ * Unreference a vfssw entry.
+ */
+void
+vfs_unrefvfssw(struct vfssw *vswp)
+{
+
+ mutex_enter(&vswp->vsw_lock);
+ vswp->vsw_count--;
+ mutex_exit(&vswp->vsw_lock);
+}
+
+// vfs_syncall
+
+/*
+ * Map VFS flags to statvfs flags. These shouldn't really be separate
+ * flags at all.
+ */
+uint_t
+vf_to_stf(uint_t vf)
+{
+ uint_t stf = 0;
+
+ if (vf & VFS_RDONLY)
+ stf |= ST_RDONLY;
+ if (vf & VFS_NOSETUID)
+ stf |= ST_NOSUID;
+ if (vf & VFS_NOTRUNC)
+ stf |= ST_NOTRUNC;
+
+ return (stf);
+}
+
+// vfsstray_sync
+// vfsstray
+// vfs_EIO
+// vfs_EIO_sync
+// EIO_vfs
+// EIO_vfsops
+
+#pragma init(vfsinit)
+
+/*
+ * Called from startup() to initialize all loaded vfs's
+ */
+void
+vfsinit(void)
+{
+ vn_create_cache();
+
+ /* Temporary, until we mount root */
+ rootdir = vn_alloc(KM_SLEEP);
+ rootdir->v_type = VDIR;
+}
+
+vfs_t *
+vfs_alloc(int kmflag)
+{
+ vfs_t *vfsp;
+
+ vfsp = kmem_alloc(sizeof (struct vfs), kmflag);
+
+ /*
+ * Do the simplest initialization here.
+ * Everything else gets done in vfs_init()
+ */
+ bzero(vfsp, sizeof (vfs_t));
+ return (vfsp);
+}
+
+void
+vfs_free(vfs_t *vfsp)
+{
+ /*
+ * One would be tempted to assert that "vfsp->vfs_count == 0".
+ * Don't. See fs/vfs.c
+ */
+
+ /* If FEM was in use, make sure everything gets cleaned up */
+
+ if (vfsp->vfs_implp)
+ vfsimpl_teardown(vfsp);
+ sema_destroy(&vfsp->vfs_reflock);
+ kmem_free(vfsp, sizeof (struct vfs));
+}
+
+/*
+ * Increments the vfs reference count by one atomically.
+ */
+void
+vfs_hold(vfs_t *vfsp)
+{
+ atomic_inc_32(&vfsp->vfs_count);
+ ASSERT(vfsp->vfs_count != 0);
+}
+
+/*
+ * Decrements the vfs reference count by one atomically. When
+ * vfs reference count becomes zero, it calls the file system
+ * specific vfs_freevfs() to free up the resources.
+ */
+void
+vfs_rele(vfs_t *vfsp)
+{
+ ASSERT(vfsp->vfs_count != 0);
+ if (atomic_dec_32_nv(&vfsp->vfs_count) == 0) {
+ VFS_FREEVFS(vfsp);
+ // lofi_remove(vfsp);
+ // zone_rele_ref...
+ // vfs_freemnttab(vfsp);
+ vfs_free(vfsp);
+ }
+}
+
+/*
+ * Generic operations vector support.
+ */
+
+int
+fs_build_vector(void *vector, int *unused_ops,
+ const fs_operation_trans_def_t *translation,
+ const fs_operation_def_t *operations)
+{
+ int i, num_trans, num_ops, used;
+
+ /*
+ * Count the number of translations and the number of supplied
+ * operations.
+ */
+
+ {
+ const fs_operation_trans_def_t *p;
+
+ for (num_trans = 0, p = translation;
+ p->name != NULL;
+ num_trans++, p++)
+ ;
+ }
+
+ {
+ const fs_operation_def_t *p;
+
+ for (num_ops = 0, p = operations;
+ p->name != NULL;
+ num_ops++, p++)
+ ;
+ }
+
+ /* Walk through each operation known to our caller. There will be */
+ /* one entry in the supplied "translation table" for each. */
+
+ used = 0;
+
+ for (i = 0; i < num_trans; i++) {
+ int j, found;
+ char *curname;
+ fs_generic_func_p result;
+ fs_generic_func_p *location;
+
+ curname = translation[i].name;
+
+ /* Look for a matching operation in the list supplied by the */
+ /* file system. */
+
+ found = 0;
+
+ for (j = 0; j < num_ops; j++) {
+ if (strcmp(operations[j].name, curname) == 0) {
+ used++;
+ found = 1;
+ break;
+ }
+ }
+
+ /*
+ * If the file system is using a "placeholder" for default
+ * or error functions, grab the appropriate function out of
+ * the translation table. If the file system didn't supply
+ * this operation at all, use the default function.
+ */
+
+ if (found) {
+ result = operations[j].func.fs_generic;
+ if (result == fs_default) {
+ result = translation[i].defaultFunc;
+ } else if (result == fs_error) {
+ result = translation[i].errorFunc;
+ } else if (result == NULL) {
+ /* Null values are PROHIBITED */
+ return (EINVAL);
+ }
+ } else {
+ result = translation[i].defaultFunc;
+ }
+
+ /* Now store the function into the operations vector. */
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ location = (fs_generic_func_p *)
+ (((char *)vector) + translation[i].offset);
+
+ *location = result;
+ }
+
+ *unused_ops = num_ops - used;
+
+ return (0);
+}
+
+/* Placeholder functions, should never be called. */
+
+int
+fs_error(void)
+{
+ cmn_err(CE_PANIC, "fs_error called");
+ return (0);
+}
+
+int
+fs_default(void)
+{
+ cmn_err(CE_PANIC, "fs_default called");
+ return (0);
+}
+
+// rootconf
+// getfsname
+// getrootfs
+
+/*
+ * VFS feature routines
+ */
+
+#define VFTINDEX(feature) (((feature) >> 32) & 0xFFFFFFFF)
+#define VFTBITS(feature) ((feature) & 0xFFFFFFFFLL)
+
+/* Register a feature in the vfs */
+void
+vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return;
+
+ vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
+}
+
+void
+vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return;
+ vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature);
+}
+
+/*
+ * Query a vfs for a feature.
+ * Returns 1 if feature is present, 0 if not
+ */
+int
+vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ int ret = 0;
+
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return (ret);
+
+ if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature))
+ ret = 1;
+
+ return (ret);
+}
+
+// vfs_propagate_features
+// vfs_get_lofi
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c
new file mode 100644
index 0000000000..07eb5bc18d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_vnode.c
@@ -0,0 +1,2026 @@
+/*
+ * 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) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017, Joyent, Inc.
+ * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * This file contains those functions from fs/vnode.c that can be
+ * used with relatively little change. Functions that differ
+ * significantly from that are in other files.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/t_lock.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/pathname.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/rwstlock.h>
+#include <sys/fem.h>
+#include <sys/stat.h>
+#include <sys/mode.h>
+#include <sys/conf.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/atomic.h>
+#include <sys/debug.h>
+#include <sys/acl.h>
+#include <sys/nbmlock.h>
+#include <sys/fcntl.h>
+#include <sys/time.h>
+#include <fs/fs_subr.h>
+#include <fs/fs_reparse.h>
+
+#include <libfksmbfs.h>
+
+/* Determine if this vnode is a file that is read-only */
+#define ISROFILE(vp) \
+ ((vp)->v_type != VCHR && (vp)->v_type != VBLK && \
+ (vp)->v_type != VFIFO && vn_is_readonly(vp))
+
+#define VOPSTATS_UPDATE(vp, counter) ((void)vp)
+#define VOPSTATS_UPDATE_IO(vp, counter, bytecounter, bytesval) \
+ ((void)vp, (void)bytesval)
+#define VOPXID_MAP_CR(vp, cr) ((void)vp)
+
+/*
+ * Excerpts from fs/vnode.c
+ */
+
+/* Global used for empty/invalid v_path */
+char *vn_vpath_empty = "";
+
+static int fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr);
+
+/*
+ * Convert stat(2) formats to vnode types and vice versa. (Knows about
+ * numerical order of S_IFMT and vnode types.)
+ */
+enum vtype iftovt_tab[] = {
+ VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
+ VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON
+};
+
+ushort_t vttoif_tab[] = {
+ 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO,
+ S_IFDOOR, 0, S_IFSOCK, S_IFPORT, 0
+};
+
+/*
+ * The system vnode cache.
+ */
+
+kmem_cache_t *vn_cache;
+
+
+/*
+ * Vnode operations vector.
+ */
+
+static const fs_operation_trans_def_t vn_ops_table[] = {
+ VOPNAME_OPEN, offsetof(struct vnodeops, vop_open),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CLOSE, offsetof(struct vnodeops, vop_close),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READ, offsetof(struct vnodeops, vop_read),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_WRITE, offsetof(struct vnodeops, vop_write),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_IOCTL, offsetof(struct vnodeops, vop_ioctl),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SETFL, offsetof(struct vnodeops, vop_setfl),
+ fs_setfl, fs_nosys,
+
+ VOPNAME_GETATTR, offsetof(struct vnodeops, vop_getattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SETATTR, offsetof(struct vnodeops, vop_setattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_ACCESS, offsetof(struct vnodeops, vop_access),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_LOOKUP, offsetof(struct vnodeops, vop_lookup),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CREATE, offsetof(struct vnodeops, vop_create),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_REMOVE, offsetof(struct vnodeops, vop_remove),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_LINK, offsetof(struct vnodeops, vop_link),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RENAME, offsetof(struct vnodeops, vop_rename),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_MKDIR, offsetof(struct vnodeops, vop_mkdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RMDIR, offsetof(struct vnodeops, vop_rmdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READDIR, offsetof(struct vnodeops, vop_readdir),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_SYMLINK, offsetof(struct vnodeops, vop_symlink),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_READLINK, offsetof(struct vnodeops, vop_readlink),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_FSYNC, offsetof(struct vnodeops, vop_fsync),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_INACTIVE, offsetof(struct vnodeops, vop_inactive),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_FID, offsetof(struct vnodeops, vop_fid),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RWLOCK, offsetof(struct vnodeops, vop_rwlock),
+ fs_rwlock, fs_rwlock,
+
+ VOPNAME_RWUNLOCK, offsetof(struct vnodeops, vop_rwunlock),
+ (fs_generic_func_p) fs_rwunlock,
+ (fs_generic_func_p) fs_rwunlock, /* no errors allowed */
+
+ VOPNAME_SEEK, offsetof(struct vnodeops, vop_seek),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_CMP, offsetof(struct vnodeops, vop_cmp),
+ fs_cmp, fs_cmp, /* no errors allowed */
+
+ VOPNAME_FRLOCK, offsetof(struct vnodeops, vop_frlock),
+ fs_frlock, fs_nosys,
+
+ VOPNAME_SPACE, offsetof(struct vnodeops, vop_space),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_REALVP, offsetof(struct vnodeops, vop_realvp),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_GETPAGE, offsetof(struct vnodeops, vop_getpage),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_PUTPAGE, offsetof(struct vnodeops, vop_putpage),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_MAP, offsetof(struct vnodeops, vop_map),
+ (fs_generic_func_p) fs_nosys_map,
+ (fs_generic_func_p) fs_nosys_map,
+
+ VOPNAME_ADDMAP, offsetof(struct vnodeops, vop_addmap),
+ (fs_generic_func_p) fs_nosys_addmap,
+ (fs_generic_func_p) fs_nosys_addmap,
+
+ VOPNAME_DELMAP, offsetof(struct vnodeops, vop_delmap),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_POLL, offsetof(struct vnodeops, vop_poll),
+ (fs_generic_func_p) fs_poll, (fs_generic_func_p) fs_nosys_poll,
+
+ VOPNAME_DUMP, offsetof(struct vnodeops, vop_dump),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_PATHCONF, offsetof(struct vnodeops, vop_pathconf),
+ fs_pathconf, fs_nosys,
+
+ VOPNAME_PAGEIO, offsetof(struct vnodeops, vop_pageio),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_DUMPCTL, offsetof(struct vnodeops, vop_dumpctl),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_DISPOSE, offsetof(struct vnodeops, vop_dispose),
+ (fs_generic_func_p) fs_dispose,
+ (fs_generic_func_p) fs_nodispose,
+
+ VOPNAME_SETSECATTR, offsetof(struct vnodeops, vop_setsecattr),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_GETSECATTR, offsetof(struct vnodeops, vop_getsecattr),
+ fs_fab_acl, fs_nosys,
+
+ VOPNAME_SHRLOCK, offsetof(struct vnodeops, vop_shrlock),
+ fs_shrlock, fs_nosys,
+
+ VOPNAME_VNEVENT, offsetof(struct vnodeops, vop_vnevent),
+ (fs_generic_func_p) fs_vnevent_nosupport,
+ (fs_generic_func_p) fs_vnevent_nosupport,
+
+ VOPNAME_REQZCBUF, offsetof(struct vnodeops, vop_reqzcbuf),
+ fs_nosys, fs_nosys,
+
+ VOPNAME_RETZCBUF, offsetof(struct vnodeops, vop_retzcbuf),
+ fs_nosys, fs_nosys,
+
+ NULL, 0, NULL, NULL
+};
+
+/* Extensible attribute (xva) routines. */
+
+/*
+ * Zero out the structure, set the size of the requested/returned bitmaps,
+ * set AT_XVATTR in the embedded vattr_t's va_mask, and set up the pointer
+ * to the returned attributes array.
+ */
+void
+xva_init(xvattr_t *xvap)
+{
+ bzero(xvap, sizeof (xvattr_t));
+ xvap->xva_mapsize = XVA_MAPSIZE;
+ xvap->xva_magic = XVA_MAGIC;
+ xvap->xva_vattr.va_mask = AT_XVATTR;
+ xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0];
+}
+
+/*
+ * If AT_XVATTR is set, returns a pointer to the embedded xoptattr_t
+ * structure. Otherwise, returns NULL.
+ */
+xoptattr_t *
+xva_getxoptattr(xvattr_t *xvap)
+{
+ xoptattr_t *xoap = NULL;
+ if (xvap->xva_vattr.va_mask & AT_XVATTR)
+ xoap = &xvap->xva_xoptattrs;
+ return (xoap);
+}
+
+// vska_compar
+// create_vopstats_template
+// new_vskstat
+// vopstats_startup
+// initialize_vopstats
+// get_fstype_vopstats
+// get_vskstat_anchor
+// teardown_vopstats
+
+/*
+ * Read or write a vnode. Called from kernel code.
+ */
+int
+vn_rdwr(
+ enum uio_rw rw,
+ struct vnode *vp,
+ caddr_t base,
+ ssize_t len,
+ offset_t offset,
+ enum uio_seg seg,
+ int ioflag,
+ rlim64_t ulimit, /* meaningful only if rw is UIO_WRITE */
+ cred_t *cr,
+ ssize_t *residp)
+{
+ struct uio uio;
+ struct iovec iov;
+ int error;
+ int in_crit = 0;
+
+ if (rw == UIO_WRITE && ISROFILE(vp))
+ return (EROFS);
+
+ if (len < 0)
+ return (EIO);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ iov.iov_base = base;
+ iov.iov_len = len;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_loffset = offset;
+ uio.uio_segflg = (short)seg;
+ uio.uio_resid = len;
+ uio.uio_llimit = ulimit;
+
+ /*
+ * We have to enter the critical region before calling VOP_RWLOCK
+ * to avoid a deadlock with ufs.
+ */
+ if (nbl_need_check(vp)) {
+ int svmand;
+
+ nbl_start_crit(vp, RW_READER);
+ in_crit = 1;
+ error = nbl_svmand(vp, cr, &svmand);
+ if (error != 0)
+ goto done;
+ if (nbl_conflict(vp, rw == UIO_WRITE ? NBL_WRITE : NBL_READ,
+ uio.uio_offset, uio.uio_resid, svmand, NULL)) {
+ error = EACCES;
+ goto done;
+ }
+ }
+
+ (void) VOP_RWLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
+ if (rw == UIO_WRITE) {
+ uio.uio_fmode = FWRITE;
+ uio.uio_extflg = UIO_COPY_DEFAULT;
+ error = VOP_WRITE(vp, &uio, ioflag, cr, NULL);
+ } else {
+ uio.uio_fmode = FREAD;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ error = VOP_READ(vp, &uio, ioflag, cr, NULL);
+ }
+ VOP_RWUNLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
+ if (residp)
+ *residp = uio.uio_resid;
+ else if (uio.uio_resid)
+ error = EIO;
+
+done:
+ if (in_crit)
+ nbl_end_crit(vp);
+ return (error);
+}
+
+/*
+ * Incremend the hold on a vnode
+ * (Real kernel uses a macro)
+ */
+void
+vn_hold(struct vnode *vp)
+{
+ mutex_enter(&vp->v_lock);
+ (vp)->v_count++;
+ mutex_exit(&vp->v_lock);
+}
+
+/*
+ * Release a vnode. Call VOP_INACTIVE on last reference or
+ * decrement reference count...
+ */
+void
+vn_rele(vnode_t *vp)
+{
+ VERIFY(vp->v_count > 0);
+ mutex_enter(&vp->v_lock);
+ if (vp->v_count == 1) {
+ mutex_exit(&vp->v_lock);
+ VOP_INACTIVE(vp, CRED(), NULL);
+ return;
+ }
+ VN_RELE_LOCKED(vp);
+ mutex_exit(&vp->v_lock);
+}
+
+// vn_rele_dnlc
+// vn_rele_stream
+// vn_rele_inactive
+// vn_rele_async
+// vn_open, vn_openat
+// vn_open_upgrade
+// vn_open_downgrade
+// vn_create, vn_createat
+// vn_link, vn_linkat
+// vn_rename, vn_renameat
+// vn_remove, vn_removeat
+
+
+/*
+ * Utility function to compare equality of vnodes.
+ * Compare the underlying real vnodes, if there are underlying vnodes.
+ * This is a more thorough comparison than the VN_CMP() macro provides.
+ */
+int
+vn_compare(vnode_t *vp1, vnode_t *vp2)
+{
+ vnode_t *realvp;
+
+ if (vp1 != NULL && VOP_REALVP(vp1, &realvp, NULL) == 0)
+ vp1 = realvp;
+ if (vp2 != NULL && VOP_REALVP(vp2, &realvp, NULL) == 0)
+ vp2 = realvp;
+ return (VN_CMP(vp1, vp2));
+}
+
+// vn_vfslocks_buckets
+// vn_vfslocks_getlock
+// vn_vfslocks_rele
+
+static krwlock_t vfsentry_ve_lock;
+
+/*
+ * vn_vfswlock_wait is used to implement a lock which is logically a
+ * writers lock protecting the v_vfsmountedhere field.
+ * vn_vfswlock_wait has been modified to be similar to vn_vfswlock,
+ * except that it blocks to acquire the lock VVFSLOCK.
+ *
+ * traverse() and routines re-implementing part of traverse (e.g. autofs)
+ * need to hold this lock. mount(), vn_rename(), vn_remove() and so on
+ * need the non-blocking version of the writers lock i.e. vn_vfswlock
+ */
+int
+vn_vfswlock_wait(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ rw_enter(&vfsentry_ve_lock, RW_WRITER);
+
+ return (0);
+}
+
+int
+vn_vfsrlock_wait(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ rw_enter(&vfsentry_ve_lock, RW_READER);
+
+ return (0);
+}
+
+/*
+ * vn_vfswlock is used to implement a lock which is logically a writers lock
+ * protecting the v_vfsmountedhere field.
+ */
+int
+vn_vfswlock(vnode_t *vp)
+{
+
+ if (vp == NULL)
+ return (EBUSY);
+
+ if (rw_tryenter(&vfsentry_ve_lock, RW_WRITER))
+ return (0);
+
+ return (EBUSY);
+}
+
+int
+vn_vfsrlock(vnode_t *vp)
+{
+
+ if (vp == NULL)
+ return (EBUSY);
+
+ if (rw_tryenter(&vfsentry_ve_lock, RW_READER))
+ return (0);
+
+ return (EBUSY);
+}
+
+void
+vn_vfsunlock(vnode_t *vp)
+{
+
+ rw_exit(&vfsentry_ve_lock);
+}
+
+int
+vn_vfswlock_held(vnode_t *vp)
+{
+ int held;
+
+ ASSERT(vp != NULL);
+
+ held = rw_write_held(&vfsentry_ve_lock);
+
+ return (held);
+}
+
+
+int
+vn_make_ops(
+ const char *name, /* Name of file system */
+ const fs_operation_def_t *templ, /* Operation specification */
+ vnodeops_t **actual) /* Return the vnodeops */
+{
+ int unused_ops;
+ int error;
+
+ *actual = (vnodeops_t *)kmem_alloc(sizeof (vnodeops_t), KM_SLEEP);
+
+ (*actual)->vnop_name = name;
+
+ error = fs_build_vector(*actual, &unused_ops, vn_ops_table, templ);
+ if (error) {
+ kmem_free(*actual, sizeof (vnodeops_t));
+ }
+
+#if DEBUG
+ if (unused_ops != 0)
+ cmn_err(CE_WARN, "vn_make_ops: %s: %d operations supplied "
+ "but not used", name, unused_ops);
+#endif
+
+ return (error);
+}
+
+/*
+ * Free the vnodeops created as a result of vn_make_ops()
+ */
+void
+vn_freevnodeops(vnodeops_t *vnops)
+{
+ kmem_free(vnops, sizeof (vnodeops_t));
+}
+
+/*
+ * Vnode cache.
+ */
+
+/* ARGSUSED */
+static int
+vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ struct vnode *vp = buf;
+
+ bzero(vp, sizeof (*vp));
+ mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
+ rw_init(&vp->v_nbllock, NULL, RW_DEFAULT, NULL);
+ vp->v_path = vn_vpath_empty;
+ vp->v_fd = -1;
+ vp->v_st_dev = NODEV;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+vn_cache_destructor(void *buf, void *cdrarg)
+{
+ struct vnode *vp;
+
+ vp = buf;
+
+ rw_destroy(&vp->v_nbllock);
+ mutex_destroy(&vp->v_lock);
+}
+
+void
+vn_create_cache(void)
+{
+ vn_cache = kmem_cache_create("vn_cache", sizeof (struct vnode),
+ VNODE_ALIGN, vn_cache_constructor, vn_cache_destructor, NULL, NULL,
+ NULL, 0);
+}
+
+void
+vn_destroy_cache(void)
+{
+ kmem_cache_destroy(vn_cache);
+}
+
+/*
+ * Used by file systems when fs-specific nodes (e.g., ufs inodes) are
+ * cached by the file system and vnodes remain associated.
+ */
+void
+vn_recycle(vnode_t *vp)
+{
+ VERIFY(vp->v_path != NULL);
+
+ /*
+ * XXX - This really belongs in vn_reinit(), but we have some issues
+ * with the counts. Best to have it here for clean initialization.
+ */
+ vp->v_rdcnt = 0;
+ vp->v_wrcnt = 0;
+
+ /*
+ * If FEM was in use...
+ */
+
+ if (vp->v_path != vn_vpath_empty) {
+ kmem_free(vp->v_path, strlen(vp->v_path) + 1);
+ vp->v_path = vn_vpath_empty;
+ }
+ // vsd_free(vp);
+}
+
+/*
+ * Used to reset the vnode fields including those that are directly accessible
+ * as well as those which require an accessor function.
+ */
+void
+vn_reinit(vnode_t *vp)
+{
+ vp->v_count = 1;
+ // vp->v_count_dnlc = 0;
+ vp->v_vfsp = NULL;
+ vp->v_stream = NULL;
+ vp->v_vfsmountedhere = NULL;
+ vp->v_flag = 0;
+ vp->v_type = VNON;
+ vp->v_rdev = NODEV;
+
+ vp->v_xattrdir = NULL;
+
+ /*
+ * In a few specific instances, vn_reinit() is used to initialize
+ * locally defined vnode_t instances. Lacking the construction offered
+ * by vn_alloc(), these vnodes require v_path initialization.
+ */
+ if (vp->v_path == NULL) {
+ vp->v_path = vn_vpath_empty;
+ }
+
+ /* Handles v_femhead, v_path, and the r/w/map counts */
+ vn_recycle(vp);
+}
+
+vnode_t *
+vn_alloc(int kmflag)
+{
+ vnode_t *vp;
+
+ vp = kmem_cache_alloc(vn_cache, kmflag);
+
+ if (vp != NULL) {
+ // vp->v_femhead = NULL; /* Must be done before vn_reinit() */
+ // vp->v_fopdata = NULL;
+ vn_reinit(vp);
+ }
+
+ return (vp);
+}
+
+void
+vn_free(vnode_t *vp)
+{
+ extern vnode_t *rootdir;
+ ASSERT(vp != rootdir);
+
+ /*
+ * Some file systems call vn_free() with v_count of zero,
+ * some with v_count of 1. In any case, the value should
+ * never be anything else.
+ */
+ ASSERT((vp->v_count == 0) || (vp->v_count == 1));
+ VERIFY(vp->v_path != NULL);
+ if (vp->v_path != vn_vpath_empty) {
+ kmem_free(vp->v_path, strlen(vp->v_path) + 1);
+ vp->v_path = vn_vpath_empty;
+ }
+
+ /* If FEM was in use... */
+
+ // vsd_free(vp);
+ kmem_cache_free(vn_cache, vp);
+}
+
+/*
+ * vnode status changes, should define better states than 1, 0.
+ */
+void
+vn_reclaim(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_RECLAIMED);
+}
+
+void
+vn_idle(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_IDLED);
+}
+void
+vn_exists(vnode_t *vp)
+{
+ vfs_t *vfsp = vp->v_vfsp;
+
+ if (vfsp == NULL ||
+ vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) {
+ return;
+ }
+ (void) VFS_VNSTATE(vfsp, vp, VNTRANS_EXISTS);
+}
+
+void
+vn_invalid(vnode_t *vp)
+{
+}
+
+/* Vnode event notification */
+// vnevent_support()
+// vnevent_...
+
+/*
+ * Vnode accessors.
+ */
+
+int
+vn_is_readonly(vnode_t *vp)
+{
+ return (vp->v_vfsp->vfs_flag & VFS_RDONLY);
+}
+
+int
+vn_has_flocks(vnode_t *vp)
+{
+ return (0);
+}
+
+int
+vn_has_mandatory_locks(vnode_t *vp, int mode)
+{
+ return (0);
+}
+
+int
+vn_has_cached_data(vnode_t *vp)
+{
+ return (0);
+}
+
+// vn_can_change_zones
+
+/*
+ * Return nonzero if the vnode is a mount point, zero if not.
+ */
+int
+vn_ismntpt(vnode_t *vp)
+{
+ return (vp->v_vfsmountedhere != NULL);
+}
+
+/* Retrieve the vfs (if any) mounted on this vnode */
+vfs_t *
+vn_mountedvfs(vnode_t *vp)
+{
+ return (vp->v_vfsmountedhere);
+}
+
+/*
+ * Return nonzero if the vnode is referenced by the dnlc, zero if not.
+ * (no DNLC here)
+ */
+int
+vn_in_dnlc(vnode_t *vp)
+{
+ return (0);
+}
+
+
+/*
+ * vn_has_other_opens() checks whether a particular file is opened by more than
+ * just the caller and whether the open is for read and/or write.
+ * This routine is for calling after the caller has already called VOP_OPEN()
+ * and the caller wishes to know if they are the only one with it open for
+ * the mode(s) specified.
+ *
+ * Vnode counts are only kept on regular files (v_type=VREG).
+ */
+int
+vn_has_other_opens(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+
+ ASSERT(vp != NULL);
+
+ switch (mode) {
+ case V_WRITE:
+ if (vp->v_wrcnt > 1)
+ return (V_TRUE);
+ break;
+ case V_RDORWR:
+ if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_RDANDWR:
+ if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_READ:
+ if (vp->v_rdcnt > 1)
+ return (V_TRUE);
+ break;
+ }
+
+ return (V_FALSE);
+}
+
+/*
+ * vn_is_opened() checks whether a particular file is opened and
+ * whether the open is for read and/or write.
+ *
+ * Vnode counts are only kept on regular files (v_type=VREG).
+ */
+int
+vn_is_opened(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+
+ ASSERT(vp != NULL);
+
+ switch (mode) {
+ case V_WRITE:
+ if (vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_RDANDWR:
+ if (vp->v_rdcnt && vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_RDORWR:
+ if (vp->v_rdcnt || vp->v_wrcnt)
+ return (V_TRUE);
+ break;
+ case V_READ:
+ if (vp->v_rdcnt)
+ return (V_TRUE);
+ break;
+ }
+
+ return (V_FALSE);
+}
+
+/*
+ * vn_is_mapped() checks whether a particular file is mapped and whether
+ * the file is mapped read and/or write. (no mmap here)
+ */
+int
+vn_is_mapped(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+ return (V_FALSE);
+}
+
+/*
+ * Set the operations vector for a vnode.
+ */
+void
+vn_setops(vnode_t *vp, vnodeops_t *vnodeops)
+{
+
+ ASSERT(vp != NULL);
+ ASSERT(vnodeops != NULL);
+
+ vp->v_op = vnodeops;
+}
+
+/*
+ * Retrieve the operations vector for a vnode
+ */
+vnodeops_t *
+vn_getops(vnode_t *vp)
+{
+
+ ASSERT(vp != NULL);
+
+ return (vp->v_op);
+}
+
+/*
+ * Returns non-zero (1) if the vnodeops matches that of the vnode.
+ * Returns zero (0) if not.
+ */
+int
+vn_matchops(vnode_t *vp, vnodeops_t *vnodeops)
+{
+ return (vn_getops(vp) == vnodeops);
+}
+
+// vn_matchopval
+// fs_new_caller_id
+
+// vn_clearpath
+// vn_setpath_common
+
+/* ARGSUSED */
+void
+vn_updatepath(vnode_t *pvp, vnode_t *vp, const char *name)
+{
+}
+
+// vn_setpath...
+// vn_renamepath
+// vn_copypath
+
+// vn_vmpss_usepageio
+
+/* VOP_XXX() macros call the corresponding fop_xxx() function */
+
+int
+fop_open(
+ vnode_t **vpp,
+ int mode,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int ret;
+ vnode_t *vp = *vpp;
+
+ VN_HOLD(vp);
+ /*
+ * Adding to the vnode counts before calling open
+ * avoids the need for a mutex...
+ */
+ if ((*vpp)->v_type == VREG) {
+ if (mode & FREAD)
+ atomic_inc_32(&(*vpp)->v_rdcnt);
+ if (mode & FWRITE)
+ atomic_inc_32(&(*vpp)->v_wrcnt);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
+
+ if (ret) {
+ /*
+ * Use the saved vp just in case the vnode ptr got trashed
+ * by the error.
+ */
+ VOPSTATS_UPDATE(vp, open);
+ if ((vp->v_type == VREG) && (mode & FREAD))
+ atomic_dec_32(&vp->v_rdcnt);
+ if ((vp->v_type == VREG) && (mode & FWRITE))
+ atomic_dec_32(&vp->v_wrcnt);
+ } else {
+ /*
+ * Some filesystems will return a different vnode,
+ * but the same path was still used to open it.
+ * So if we do change the vnode and need to
+ * copy over the path, do so here, rather than special
+ * casing each filesystem. Adjust the vnode counts to
+ * reflect the vnode switch.
+ */
+ VOPSTATS_UPDATE(*vpp, open);
+ if (*vpp != vp && *vpp != NULL) {
+ // vn_copypath(vp, *vpp);
+ if (((*vpp)->v_type == VREG) && (mode & FREAD))
+ atomic_inc_32(&(*vpp)->v_rdcnt);
+ if ((vp->v_type == VREG) && (mode & FREAD))
+ atomic_dec_32(&vp->v_rdcnt);
+ if (((*vpp)->v_type == VREG) && (mode & FWRITE))
+ atomic_inc_32(&(*vpp)->v_wrcnt);
+ if ((vp->v_type == VREG) && (mode & FWRITE))
+ atomic_dec_32(&vp->v_wrcnt);
+ }
+ }
+ VN_RELE(vp);
+ return (ret);
+}
+
+int
+fop_close(
+ vnode_t *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr, ct);
+ VOPSTATS_UPDATE(vp, close);
+ /*
+ * Check passed in count to handle possible dups. Vnode counts are only
+ * kept on regular files
+ */
+ if ((vp->v_type == VREG) && (count == 1)) {
+ if (flag & FREAD) {
+ ASSERT(vp->v_rdcnt > 0);
+ atomic_dec_32(&vp->v_rdcnt);
+ }
+ if (flag & FWRITE) {
+ ASSERT(vp->v_wrcnt > 0);
+ atomic_dec_32(&vp->v_wrcnt);
+ }
+ }
+ return (err);
+}
+
+int
+fop_read(
+ vnode_t *vp,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_read)(vp, uiop, ioflag, cr, ct);
+ VOPSTATS_UPDATE_IO(vp, read,
+ read_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_write(
+ vnode_t *vp,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_write)(vp, uiop, ioflag, cr, ct);
+ VOPSTATS_UPDATE_IO(vp, write,
+ write_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp, ct);
+ VOPSTATS_UPDATE(vp, ioctl);
+ return (err);
+}
+
+int
+fop_setfl(
+ vnode_t *vp,
+ int oflags,
+ int nflags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr, ct);
+ VOPSTATS_UPDATE(vp, setfl);
+ return (err);
+}
+
+int
+fop_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_getattr)(vp, vap, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, getattr);
+ return (err);
+}
+
+int
+fop_setattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, setattr);
+ return (err);
+}
+
+int
+fop_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ if ((flags & V_ACE_MASK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, access);
+ return (err);
+}
+
+int
+fop_lookup(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t **vpp,
+ pathname_t *pnp,
+ int flags,
+ vnode_t *rdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int *deflags, /* Returned per-dirent flags */
+ pathname_t *ppnp) /* Returned case-preserved name in directory */
+{
+ int ret;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly. It is required
+ * that if the vfs supports case-insensitive lookup, it also
+ * supports extended dirent flags.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ /*
+ * The real vnode.c would call xattr_dir_lookup here,
+ * which inserts the special "System Attribute" files:
+ * (SUNWattr_rw, SUNWattr_ro) into the xattr list.
+ * Here the main focus is on testing xattr support,
+ * so the system attribute stuff is ommitted.
+ */
+#if 0
+ if ((flags & LOOKUP_XATTR) && (flags & LOOKUP_HAVE_SYSATTR_DIR) == 0) {
+ // Don't need xattr support in libfksmbfs.
+ // ret = xattr_dir_lookup(dvp, vpp, flags, cr);
+ ret = EINVAL;
+ } else
+#endif
+ {
+ ret = (*(dvp)->v_op->vop_lookup)
+ (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
+ }
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, lookup);
+ vn_updatepath(dvp, *vpp, nm);
+ }
+
+ return (ret);
+}
+
+int
+fop_create(
+ vnode_t *dvp,
+ char *name,
+ vattr_t *vap,
+ vcexcl_t excl,
+ int mode,
+ vnode_t **vpp,
+ cred_t *cr,
+ int flags,
+ caller_context_t *ct,
+ vsecattr_t *vsecp) /* ACL to set during create */
+{
+ int ret;
+
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ ret = (*(dvp)->v_op->vop_create)
+ (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, create);
+ vn_updatepath(dvp, *vpp, name);
+ }
+
+ return (ret);
+}
+
+int
+fop_remove(
+ vnode_t *dvp,
+ char *nm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ err = (*(dvp)->v_op->vop_remove)(dvp, nm, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, remove);
+ return (err);
+}
+
+int
+fop_link(
+ vnode_t *tdvp,
+ vnode_t *svp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If the target file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(tdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(tdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(tdvp, cr);
+
+ err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags);
+ VOPSTATS_UPDATE(tdvp, link);
+ return (err);
+}
+
+int
+fop_rename(
+ vnode_t *sdvp,
+ char *snm,
+ vnode_t *tdvp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If the file system involved does not support
+ * case-insensitive access and said access is requested, fail
+ * quickly.
+ */
+ if (flags & FIGNORECASE &&
+ ((vfs_has_feature(sdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(sdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(tdvp, cr);
+
+ err = (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr, ct, flags);
+ VOPSTATS_UPDATE(sdvp, rename);
+ return (err);
+}
+
+int
+fop_mkdir(
+ vnode_t *dvp,
+ char *dirname,
+ vattr_t *vap,
+ vnode_t **vpp,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp) /* ACL to set during create */
+{
+ int ret;
+
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ ret = (*(dvp)->v_op->vop_mkdir)
+ (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
+ if (ret == 0 && *vpp) {
+ VOPSTATS_UPDATE(*vpp, mkdir);
+ vn_updatepath(dvp, *vpp, dirname);
+ }
+
+ return (ret);
+}
+
+int
+fop_rmdir(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t *cdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ err = (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, rmdir);
+ return (err);
+}
+
+int
+fop_readdir(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cr,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+ ssize_t resid_start = uiop->uio_resid;
+
+ /*
+ * If this file system doesn't support retrieving directory
+ * entry flags and said access is requested, fail quickly.
+ */
+ if (flags & V_RDDIR_ENTFLAGS &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS) == 0)
+ return (EINVAL);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_readdir)(vp, uiop, cr, eofp, ct, flags);
+ VOPSTATS_UPDATE_IO(vp, readdir,
+ readdir_bytes, (resid_start - uiop->uio_resid));
+ return (err);
+}
+
+int
+fop_symlink(
+ vnode_t *dvp,
+ char *linkname,
+ vattr_t *vap,
+ char *target,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ int err;
+ xvattr_t xvattr;
+
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
+ VOPXID_MAP_CR(dvp, cr);
+
+ /* check for reparse point */
+ if ((vfs_has_feature(dvp->v_vfsp, VFSFT_REPARSE)) &&
+ (strncmp(target, FS_REPARSE_TAG_STR,
+ strlen(FS_REPARSE_TAG_STR)) == 0)) {
+ if (!fs_reparse_mark(target, vap, &xvattr))
+ vap = (vattr_t *)&xvattr;
+ }
+
+ err = (*(dvp)->v_op->vop_symlink)
+ (dvp, linkname, vap, target, cr, ct, flags);
+ VOPSTATS_UPDATE(dvp, symlink);
+ return (err);
+}
+
+int
+fop_readlink(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr, ct);
+ VOPSTATS_UPDATE(vp, readlink);
+ return (err);
+}
+
+int
+fop_fsync(
+ vnode_t *vp,
+ int syncflag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr, ct);
+ VOPSTATS_UPDATE(vp, fsync);
+ return (err);
+}
+
+void
+fop_inactive(
+ vnode_t *vp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ /* Need to update stats before vop call since we may lose the vnode */
+ VOPSTATS_UPDATE(vp, inactive);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ (*(vp)->v_op->vop_inactive)(vp, cr, ct);
+}
+
+int
+fop_fid(
+ vnode_t *vp,
+ fid_t *fidp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_fid)(vp, fidp, ct);
+ VOPSTATS_UPDATE(vp, fid);
+ return (err);
+}
+
+int
+fop_rwlock(
+ vnode_t *vp,
+ int write_lock,
+ caller_context_t *ct)
+{
+ int ret;
+
+ ret = ((*(vp)->v_op->vop_rwlock)(vp, write_lock, ct));
+ VOPSTATS_UPDATE(vp, rwlock);
+ return (ret);
+}
+
+void
+fop_rwunlock(
+ vnode_t *vp,
+ int write_lock,
+ caller_context_t *ct)
+{
+ (*(vp)->v_op->vop_rwunlock)(vp, write_lock, ct);
+ VOPSTATS_UPDATE(vp, rwunlock);
+}
+
+int
+fop_seek(
+ vnode_t *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp, ct);
+ VOPSTATS_UPDATE(vp, seek);
+ return (err);
+}
+
+int
+fop_cmp(
+ vnode_t *vp1,
+ vnode_t *vp2,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp1)->v_op->vop_cmp)(vp1, vp2, ct);
+ VOPSTATS_UPDATE(vp1, cmp);
+ return (err);
+}
+
+int
+fop_frlock(
+ vnode_t *vp,
+ int cmd,
+ flock64_t *bfp,
+ int flag,
+ offset_t offset,
+ struct flk_callback *flk_cbp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_frlock)
+ (vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
+ VOPSTATS_UPDATE(vp, frlock);
+ return (err);
+}
+
+int
+fop_space(
+ vnode_t *vp,
+ int cmd,
+ flock64_t *bfp,
+ int flag,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_space)(vp, cmd, bfp, flag, offset, cr, ct);
+ VOPSTATS_UPDATE(vp, space);
+ return (err);
+}
+
+int
+fop_realvp(
+ vnode_t *vp,
+ vnode_t **vpp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_realvp)(vp, vpp, ct);
+ VOPSTATS_UPDATE(vp, realvp);
+ return (err);
+}
+
+int
+fop_getpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ uint_t *protp,
+ page_t **plarr,
+ size_t plsz,
+ struct seg *seg,
+ caddr_t addr,
+ enum seg_rw rw,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_getpage)
+ (vp, off, len, protp, plarr, plsz, seg, addr, rw, cr, ct);
+ VOPSTATS_UPDATE(vp, getpage);
+ return (err);
+}
+
+int
+fop_putpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, putpage);
+ return (err);
+}
+
+int
+fop_map(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t *addrp,
+ size_t len,
+ uchar_t prot,
+ uchar_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_map)
+ (vp, off, as, addrp, len, prot, maxprot, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, map);
+ return (err);
+}
+
+int
+fop_addmap(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uchar_t prot,
+ uchar_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ error = (*(vp)->v_op->vop_addmap)
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
+
+ VOPSTATS_UPDATE(vp, addmap);
+ return (error);
+}
+
+int
+fop_delmap(
+ vnode_t *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uint_t prot,
+ uint_t maxprot,
+ uint_t flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ error = (*(vp)->v_op->vop_delmap)
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
+
+ VOPSTATS_UPDATE(vp, delmap);
+ return (error);
+}
+
+
+int
+fop_poll(
+ vnode_t *vp,
+ short events,
+ int anyyet,
+ short *reventsp,
+ struct pollhead **phpp,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp, ct);
+ VOPSTATS_UPDATE(vp, poll);
+ return (err);
+}
+
+int
+fop_dump(
+ vnode_t *vp,
+ caddr_t addr,
+ offset_t lbdn,
+ offset_t dblks,
+ caller_context_t *ct)
+{
+ int err;
+
+ /* ensure lbdn and dblks can be passed safely to bdev_dump */
+ if ((lbdn != (daddr_t)lbdn) || (dblks != (int)dblks))
+ return (EIO);
+
+ err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks, ct);
+ VOPSTATS_UPDATE(vp, dump);
+ return (err);
+}
+
+int
+fop_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr, ct);
+ VOPSTATS_UPDATE(vp, pathconf);
+ return (err);
+}
+
+int
+fop_pageio(
+ vnode_t *vp,
+ struct page *pp,
+ u_offset_t io_off,
+ size_t io_len,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr, ct);
+ VOPSTATS_UPDATE(vp, pageio);
+ return (err);
+}
+
+int
+fop_dumpctl(
+ vnode_t *vp,
+ int action,
+ offset_t *blkp,
+ caller_context_t *ct)
+{
+ int err;
+ err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp, ct);
+ VOPSTATS_UPDATE(vp, dumpctl);
+ return (err);
+}
+
+void
+fop_dispose(
+ vnode_t *vp,
+ page_t *pp,
+ int flag,
+ int dn,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ /* Must do stats first since it's possible to lose the vnode */
+ VOPSTATS_UPDATE(vp, dispose);
+
+ VOPXID_MAP_CR(vp, cr);
+
+ (*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr, ct);
+}
+
+int
+fop_setsecattr(
+ vnode_t *vp,
+ vsecattr_t *vsap,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, setsecattr);
+ return (err);
+}
+
+int
+fop_getsecattr(
+ vnode_t *vp,
+ vsecattr_t *vsap,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, getsecattr);
+ return (err);
+}
+
+int
+fop_shrlock(
+ vnode_t *vp,
+ int cmd,
+ struct shrlock *shr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int err;
+
+ VOPXID_MAP_CR(vp, cr);
+
+ err = (*(vp)->v_op->vop_shrlock)(vp, cmd, shr, flag, cr, ct);
+ VOPSTATS_UPDATE(vp, shrlock);
+ return (err);
+}
+
+int
+fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
+{
+ int err;
+
+ err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm, ct);
+ VOPSTATS_UPDATE(vp, vnevent);
+ return (err);
+}
+
+// fop_reqzcbuf
+// fop_retzcbuf
+
+// vsd_defaultdestructor
+// vsd_create, vsd_destroy
+// vsd_get, vsd_set
+// vsd_free, vsd_realloc
+
+static int
+fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr)
+{
+ return (-1);
+}
+
+/*
+ * Function to check whether a symlink is a reparse point.
+ * Return B_TRUE if it is a reparse point, else return B_FALSE
+ */
+boolean_t
+vn_is_reparse(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ xvattr_t xvattr;
+ xoptattr_t *xoap;
+
+ if ((vp->v_type != VLNK) ||
+ !(vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR)))
+ return (B_FALSE);
+
+ xva_init(&xvattr);
+ xoap = xva_getxoptattr(&xvattr);
+ ASSERT(xoap);
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+
+ if (VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct))
+ return (B_FALSE);
+
+ if ((!(xvattr.xva_vattr.va_mask & AT_XVATTR)) ||
+ (!(XVA_ISSET_RTN(&xvattr, XAT_REPARSE))))
+ return (B_FALSE);
+
+ return (xoap->xoa_reparse ? B_TRUE : B_FALSE);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c b/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c
new file mode 100644
index 0000000000..5593a8d542
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fake_zone.c
@@ -0,0 +1,76 @@
+/*
+ * 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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc. All rights reserved.
+ * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Simulating just one zone here (the global zone)
+ */
+
+#include <sys/types.h>
+#include <sys/zone.h>
+#include <sys/debug.h>
+
+static void *zone_specific_val;
+static void *(*zkey_create)(zoneid_t);
+// static void (*zkey_shutdown)(zoneid_t, void *);
+// static void (*zkey_destroy)(zoneid_t, void *);
+
+/* ARGSUSED */
+void
+zone_key_create(zone_key_t *keyp, void *(*create)(zoneid_t),
+ void (*shutdown)(zoneid_t, void *), void (*destroy)(zoneid_t, void *))
+{
+
+ zkey_create = create;
+ // zkey_shutdown = shutdown;
+ // zkey_destroy = destroy;
+ *keyp = 1;
+}
+
+/* ARGSUSED */
+int
+zone_key_delete(zone_key_t key)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+zone_setspecific(zone_key_t key, zone_t *zone, const void *data)
+{
+ return (-1);
+}
+
+/* ARGSUSED */
+void *
+zone_getspecific(zone_key_t key, zone_t *zone)
+{
+ ASSERT(key == 1);
+ if (zone_specific_val == NULL)
+ zone_specific_val = (*zkey_create)(zone->zone_id);
+ return (zone_specific_val);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c b/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c
new file mode 100644
index 0000000000..ee92e3ed67
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/fksmbfs_rwlock.c
@@ -0,0 +1,235 @@
+/*
+ * 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 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
+ * All rights reserved.
+ */
+
+/*
+ * A homegrown reader/writer lock implementation. It addresses
+ * two requirements not addressed by the system primitives. They
+ * are that the `enter" operation is optionally interruptible and
+ * that that they can be re`enter'ed by writers without deadlock.
+ *
+ * All of this was borrowed from NFS.
+ * See: uts/common/fs/nfs/nfs_subr.c
+ *
+ * XXX: Could we make this serve our needs instead?
+ * See: uts/common/os/rwstlock.c
+ * (and then use it for NFS too)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Only can return non-zero if intr != 0.
+ */
+int
+smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr)
+{
+
+ mutex_enter(&l->lock);
+
+ /*
+ * If this is a nested enter, then allow it. There
+ * must be as many exits as enters through.
+ */
+ if (l->owner == curthread) {
+ /* lock is held for writing by current thread */
+ ASSERT(rw == RW_READER || rw == RW_WRITER);
+ l->count--;
+ } else if (rw == RW_READER) {
+ /*
+ * While there is a writer active or writers waiting,
+ * then wait for them to finish up and move on. Then,
+ * increment the count to indicate that a reader is
+ * active.
+ */
+ while (l->count < 0 || l->waiters > 0) {
+ if (intr) {
+ // lwp_nostop stuff...
+ (void) cv_wait_sig(&l->cv, &l->lock);
+ } else
+ cv_wait(&l->cv, &l->lock);
+ }
+ ASSERT(l->count < INT_MAX);
+#ifdef SMBDEBUG
+ if ((l->count % 10000) == 9999)
+ cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on"
+ "rwlock @ %p\n", l->count, (void *)&l);
+#endif
+ l->count++;
+ } else {
+ ASSERT(rw == RW_WRITER);
+ /*
+ * While there are readers active or a writer
+ * active, then wait for all of the readers
+ * to finish or for the writer to finish.
+ * Then, set the owner field to curthread and
+ * decrement count to indicate that a writer
+ * is active.
+ */
+ while (l->count > 0 || l->owner != NULL) {
+ l->waiters++;
+ if (intr) {
+ // lwp_nostop stuff...
+ if (!cv_wait_sig(&l->cv, &l->lock)) {
+ l->waiters--;
+ cv_broadcast(&l->cv);
+ mutex_exit(&l->lock);
+ return (EINTR);
+ }
+ } else
+ cv_wait(&l->cv, &l->lock);
+ l->waiters--;
+ }
+ l->owner = curthread;
+ l->count--;
+ }
+
+ mutex_exit(&l->lock);
+
+ return (0);
+}
+
+/*
+ * If the lock is available, obtain it and return non-zero. If there is
+ * already a conflicting lock, return 0 immediately.
+ */
+
+int
+smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw)
+{
+ mutex_enter(&l->lock);
+
+ /*
+ * If this is a nested enter, then allow it. There
+ * must be as many exits as enters through.
+ */
+ if (l->owner == curthread) {
+ /* lock is held for writing by current thread */
+ ASSERT(rw == RW_READER || rw == RW_WRITER);
+ l->count--;
+ } else if (rw == RW_READER) {
+ /*
+ * If there is a writer active or writers waiting, deny the
+ * lock. Otherwise, bump the count of readers.
+ */
+ if (l->count < 0 || l->waiters > 0) {
+ mutex_exit(&l->lock);
+ return (0);
+ }
+ l->count++;
+ } else {
+ ASSERT(rw == RW_WRITER);
+ /*
+ * If there are readers active or a writer active, deny the
+ * lock. Otherwise, set the owner field to curthread and
+ * decrement count to indicate that a writer is active.
+ */
+ if (l->count > 0 || l->owner != NULL) {
+ mutex_exit(&l->lock);
+ return (0);
+ }
+ l->owner = curthread;
+ l->count--;
+ }
+
+ mutex_exit(&l->lock);
+
+ return (1);
+}
+
+void
+smbfs_rw_exit(smbfs_rwlock_t *l)
+{
+
+ mutex_enter(&l->lock);
+ /*
+ * If this is releasing a writer lock, then increment count to
+ * indicate that there is one less writer active. If this was
+ * the last of possibly nested writer locks, then clear the owner
+ * field as well to indicate that there is no writer active
+ * and wakeup any possible waiting writers or readers.
+ *
+ * If releasing a reader lock, then just decrement count to
+ * indicate that there is one less reader active. If this was
+ * the last active reader and there are writer(s) waiting,
+ * then wake up the first.
+ */
+ if (l->owner != NULL) {
+ ASSERT(l->owner == curthread);
+ l->count++;
+ if (l->count == 0) {
+ l->owner = NULL;
+ cv_broadcast(&l->cv);
+ }
+ } else {
+ ASSERT(l->count > 0);
+ l->count--;
+ if (l->count == 0 && l->waiters > 0)
+ cv_broadcast(&l->cv);
+ }
+ mutex_exit(&l->lock);
+}
+
+int
+smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw)
+{
+
+ if (rw == RW_READER)
+ return (l->count > 0);
+ ASSERT(rw == RW_WRITER);
+ return (l->count < 0);
+}
+
+/* ARGSUSED */
+void
+smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg)
+{
+
+ l->count = 0;
+ l->waiters = 0;
+ l->owner = NULL;
+ mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&l->cv, NULL, CV_DEFAULT, NULL);
+}
+
+void
+smbfs_rw_destroy(smbfs_rwlock_t *l)
+{
+
+ mutex_destroy(&l->lock);
+ cv_destroy(&l->cv);
+}
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h b/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h
new file mode 100644
index 0000000000..e168b008af
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/libfksmbfs.h
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _LIBFKSMBFS_H_
+#define _LIBFKSMBFS_H_
+
+/*
+ * Declarations for exports in fake_vfs.c
+ */
+
+#include <sys/types.h>
+#include <sys/cred.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+
+#ifndef MAXOFF32_T
+#define MAXOFF32_T 0x7fffffff
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Need these visible outside _FAKE_KERNEL for the test CLI.
+ * In the kmod/lib build these duplicate declarations in vfs.h or
+ * vnode.h but that's OK as long as the declarations are identical.
+ */
+struct mounta;
+struct stat64;
+int fake_installfs(vfsdef_t *);
+int fake_removefs(vfsdef_t *);
+int fake_domount(char *, struct mounta *, struct vfs **);
+int fake_dounmount(struct vfs *, int);
+int fake_lookup(vnode_t *, char *, vnode_t **);
+int fake_lookup_dir(char *, vnode_t **, char **);
+int fake_stat(vnode_t *, struct stat64 *, int);
+int fake_getdents(vnode_t *, offset_t *, void *, size_t);
+ssize_t fake_pread(vnode_t *, void *, size_t, off_t);
+ssize_t fake_pwrite(vnode_t *, void *, size_t, off_t);
+int fake_unlink(char *, int);
+int fake_rename(char *, char *);
+
+int vn_close_rele(vnode_t *vp, int flag);
+int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode,
+ struct vnode **vpp, enum create crwhy, mode_t umask);
+int vn_create(char *pnamep, enum uio_seg seg, struct vattr *vap,
+ enum vcexcl excl, int mode, struct vnode **vpp,
+ enum create why, int flag, mode_t umask);
+
+void vn_rele(struct vnode *vp);
+
+/* In the real smbfs, these are _init(), _fini() */
+int fksmbfs_init(void);
+int fksmbfs_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFKSMBFS_H_ */
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs b/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs
new file mode 100644
index 0000000000..6e7f55f31d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/llib-lfksmbfs
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfksmbfs.h>
diff --git a/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers b/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers
new file mode 100644
index 0000000000..6e8b11a4ef
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/common/mapfile-vers
@@ -0,0 +1,68 @@
+#
+# 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ fake_domount;
+ fake_dounmount;
+ fake_lookup;
+ fake_lookup_dir;
+ fake_getdents;
+ fake_pread;
+ fake_pwrite;
+ fake_rename;
+ fake_stat;
+ fake_unlink;
+
+ fksmbfs_fini;
+ fksmbfs_init;
+
+ fsop_root;
+ fsop_statfs;
+ fsop_sync;
+
+ vn_close_rele;
+ vn_create;
+ vn_open;
+ vn_rele;
+ local:
+ *;
+};
diff --git a/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile b/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile
new file mode 100644
index 0000000000..6e1eb18522
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/i386/Makefile
@@ -0,0 +1,20 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbfs
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile b/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile
new file mode 100644
index 0000000000..6e1eb18522
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/sparc/Makefile
@@ -0,0 +1,20 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+DYNFLAGS += -R/usr/lib/smbfs
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile b/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile
new file mode 100644
index 0000000000..151660294b
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/sparcv9/Makefile
@@ -0,0 +1,24 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MACH_LDLIBS += -L$(ROOT)/usr/lib/smbfs/$(MACH64)
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+DYNFLAGS += -R/usr/lib/smbfs/$(MACH64)
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)