summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
Diffstat (limited to 'usr')
-rw-r--r--usr/src/Makefile13
-rw-r--r--usr/src/boot/Makefile.version2
-rw-r--r--usr/src/boot/lib/libstand/Makefile.inc2
-rw-r--r--usr/src/boot/lib/libstand/arp.c70
-rw-r--r--usr/src/boot/lib/libstand/assert.c8
-rw-r--r--usr/src/boot/lib/libstand/bzipfs.c547
-rw-r--r--usr/src/boot/lib/libstand/netif.c8
-rw-r--r--usr/src/boot/lib/libstand/panic.c (renamed from usr/src/boot/sys/boot/common/panic.c)26
-rw-r--r--usr/src/boot/lib/libstand/sbrk.c35
-rw-r--r--usr/src/boot/lib/libstand/stand.h194
-rw-r--r--usr/src/boot/sys/boot/common/Makefile.inc6
-rw-r--r--usr/src/boot/sys/boot/common/bootstrap.h268
-rw-r--r--usr/src/boot/sys/boot/common/console.c351
-rw-r--r--usr/src/boot/sys/boot/common/interp_forth.c401
-rwxr-xr-xusr/src/boot/sys/boot/common/linenoise/linenoise.c1
-rw-r--r--usr/src/boot/sys/boot/common/multiboot2.c109
-rw-r--r--usr/src/boot/sys/boot/common/tem.c14
-rw-r--r--usr/src/boot/sys/boot/efi/loader/Makefile.common4
-rw-r--r--usr/src/boot/sys/boot/efi/loader/comconsole.c157
-rw-r--r--usr/src/boot/sys/boot/i386/gptzfsboot/Makefile2
-rw-r--r--usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c2
-rw-r--r--usr/src/boot/sys/boot/i386/isoboot/Makefile2
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/bio.c2
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/biosdisk.c48
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/comconsole.c249
-rw-r--r--usr/src/boot/sys/boot/i386/loader/Makefile8
-rw-r--r--usr/src/boot/sys/boot/uboot/lib/copy.c18
-rw-r--r--usr/src/boot/sys/boot/uboot/lib/net.c12
-rw-r--r--usr/src/cmd/audio/audioplay/audioplay.c7
-rw-r--r--usr/src/cmd/audio/audiorecord/audiorecord.c6
-rw-r--r--usr/src/cmd/audit/audit.c6
-rw-r--r--usr/src/cmd/auditconfig/auditconfig.c15
-rw-r--r--usr/src/cmd/bhyve/virtio.c15
-rw-r--r--usr/src/cmd/busstat/busstat.c6
-rw-r--r--usr/src/cmd/cat/cat.c13
-rw-r--r--usr/src/cmd/chgrp/Makefile28
-rw-r--r--usr/src/cmd/chgrp/chgrp.c32
-rw-r--r--usr/src/cmd/chown/Makefile29
-rw-r--r--usr/src/cmd/chown/chown.c38
-rw-r--r--usr/src/cmd/cmd-inet/common/kcmd.c11
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile2
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/finger.c6
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/pppd/plugins/passprompt.c7
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c5
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c9
-rw-r--r--usr/src/cmd/compress/compress.c13
-rw-r--r--usr/src/cmd/dfs.cmds/sharemgr/commands.c70
-rw-r--r--usr/src/cmd/dis/dis_util.c3
-rw-r--r--usr/src/cmd/echo/echo.c21
-rw-r--r--usr/src/cmd/fm/fmtopo/common/fmtopo.c57
-rw-r--r--usr/src/cmd/fmthard/fmthard.c5
-rw-r--r--usr/src/cmd/fruadm/fruadm.c10
-rw-r--r--usr/src/cmd/fs.d/smbclnt/Makefile4
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc24
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile104
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/README99
-rwxr-xr-xusr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh32
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d68
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c98
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c150
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c143
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c938
-rw-r--r--usr/src/cmd/fs.d/smbclnt/fksmbcl/shares.c (renamed from usr/src/cmd/fs.d/smbclnt/test/srvenum.c)236
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/Makefile4
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c143
-rw-r--r--usr/src/cmd/fs.d/smbclnt/smbutil/view.c19
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/Makefile85
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/srvinfo.c415
-rw-r--r--usr/src/cmd/fs.d/smbclnt/test/tconn.c171
-rw-r--r--usr/src/cmd/fs.d/ufs/fsck/pass2.c69
-rw-r--r--usr/src/cmd/getconf/getconf.c9
-rw-r--r--usr/src/cmd/infocmp/infocmp.c141
-rw-r--r--usr/src/cmd/ksh/builtins/alias.c6
-rw-r--r--usr/src/cmd/mdb/Makefile.common4
-rw-r--r--usr/src/cmd/mdb/Makefile.module4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_cmds.c4
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_demangle.c5
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_fmt.c113
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_io.c11
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/ldi.c7
-rw-r--r--usr/src/cmd/mdb/common/modules/libc/libc.c222
-rw-r--r--usr/src/cmd/mdb/common/modules/nsmb/nsmb.c98
-rw-r--r--usr/src/cmd/mdb/common/modules/smbfs/smbfs.c63
-rw-r--r--usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile49
-rw-r--r--usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile56
-rw-r--r--usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile48
-rw-r--r--usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile55
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb2
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb.out12
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb4
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb.out32
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb3
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb.out16
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb1
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb.out6
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb4
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb.out14
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-e.mdb2
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-e.mdb.out12
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-g.mdb5
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-g.mdb.out40
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-j.mdb8
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-j.mdb.out238
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-p.mdb1
-rw-r--r--usr/src/cmd/mdb/test/format/tst.format-p.mdb.out6
-rw-r--r--usr/src/cmd/mdb/test/options/tst.autowrap.mdb7
-rw-r--r--usr/src/cmd/mdb/test/options/tst.autowrap.mdb.out11
-rw-r--r--usr/src/cmd/ndmpadm/ndmpadm_main.c7
-rw-r--r--usr/src/cmd/pathchk/pathchk.c19
-rw-r--r--usr/src/cmd/pcitool/pcitool_ui.c3
-rw-r--r--usr/src/cmd/pg/pg.c3
-rw-r--r--usr/src/cmd/savecore/savecore.c38
-rw-r--r--usr/src/cmd/sbdadm/sbdadm.c3
-rw-r--r--usr/src/cmd/sgs/ar/common/main.c6
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.msg2
-rw-r--r--usr/src/cmd/sgs/libld/common/machrel.amd.c3
-rw-r--r--usr/src/cmd/sgs/m4/common/m4.c6
-rw-r--r--usr/src/cmd/sgs/nm/amd64/Makefile6
-rw-r--r--usr/src/cmd/sgs/nm/common/nm.c386
-rw-r--r--usr/src/cmd/sgs/nm/i386/Makefile6
-rw-r--r--usr/src/cmd/sgs/nm/sparc/Makefile1
-rw-r--r--usr/src/cmd/sgs/nm/sparcv9/Makefile1
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README1
-rw-r--r--usr/src/cmd/sgs/pvs/common/pvs.c2
-rw-r--r--usr/src/cmd/sgs/pvs/common/pvs.msg3
-rw-r--r--usr/src/cmd/sgs/test/ld/x64/tls/ie/README9
-rw-r--r--usr/src/cmd/svc/common/notify_params.c4
-rw-r--r--usr/src/cmd/syseventd/daemons/syseventd/sysevent_client.c6
-rw-r--r--usr/src/cmd/truss/codes.c4
-rw-r--r--usr/src/cmd/ucodeadm/ucodeadm.c12
-rw-r--r--usr/src/cmd/ul/ul.c6
-rw-r--r--usr/src/cmd/valtools/ckitem.c8
-rw-r--r--usr/src/cmd/write/write.c7
-rw-r--r--usr/src/cmd/zdump/zdump.c9
-rw-r--r--usr/src/cmd/zpool/zpool_main.c45
-rw-r--r--usr/src/common/ctf/ctf_create.c3
-rw-r--r--usr/src/common/pnglite/pnglite.c24
-rw-r--r--usr/src/common/smbclnt/smbfs_ntacl.c29
-rw-r--r--usr/src/common/smbclnt/smbfs_ntacl.h6
-rw-r--r--usr/src/common/smbios/smb_info.c4
-rw-r--r--usr/src/compat/freebsd/amd64/machine/atomic.h9
-rw-r--r--usr/src/contrib/mDNSResponder/Clients/dns-sd.c2
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c10
-rw-r--r--usr/src/data/hwdata/pci.ids1049
-rw-r--r--usr/src/data/hwdata/usb.ids383
-rw-r--r--usr/src/head/floatingpoint.h2
-rw-r--r--usr/src/head/signal.h2
-rw-r--r--usr/src/lib/Makefile4
-rw-r--r--usr/src/lib/brand/lx/testing/Readme_ltp3
-rw-r--r--usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c3
-rw-r--r--usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c25
-rw-r--r--usr/src/lib/fm/topo/libtopo/Makefile.com1
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_2xml.c282
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_subr.c15
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_xml.c46
-rw-r--r--usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c29
-rw-r--r--usr/src/lib/fm/topo/modules/common/ses/ses.c45
-rw-r--r--usr/src/lib/gss_mechs/mech_dh/dh_common/dh_template.c8
-rw-r--r--usr/src/lib/libc/port/fp/sigfpe.c5
-rw-r--r--usr/src/lib/libcmdutils/common/process_xattrs.c6
-rw-r--r--usr/src/lib/libctf/common/ctf_convert.c6
-rw-r--r--usr/src/lib/libctf/common/ctf_dwarf.c231
-rw-r--r--usr/src/lib/libctf/common/ctf_lib.c97
-rw-r--r--usr/src/lib/libctf/common/ctf_merge.c496
-rw-r--r--usr/src/lib/libctf/common/libctf_impl.h12
-rw-r--r--usr/src/lib/libcustr/common/custr.c120
-rw-r--r--usr/src/lib/libcustr/common/libcustr.h75
-rw-r--r--usr/src/lib/libcustr/common/mapfile-vers6
-rw-r--r--usr/src/lib/libdemangle/Makefile.com4
-rw-r--r--usr/src/lib/libdemangle/common/cxx.c3
-rw-r--r--usr/src/lib/libdemangle/common/demangle-sys.h4
-rw-r--r--usr/src/lib/libdemangle/common/demangle.c130
-rw-r--r--usr/src/lib/libdemangle/common/demangle_int.h15
-rw-r--r--usr/src/lib/libdemangle/common/rust.c543
-rw-r--r--usr/src/lib/libdemangle/common/strview.c107
-rw-r--r--usr/src/lib/libdemangle/common/strview.h140
-rw-r--r--usr/src/lib/libdemangle/common/util.c15
-rw-r--r--usr/src/lib/libdns_sd/Makefile.com2
-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/kstat.c6
-rw-r--r--usr/src/lib/libfakekernel/common/mapfile-vers15
-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/sys/user.h1
-rw-r--r--usr/src/lib/libfakekernel/common/taskq.c2
-rw-r--r--usr/src/lib/libfakekernel/common/uio.c4
-rw-r--r--usr/src/lib/libmlrpc/common/ndr_server.c3
-rw-r--r--usr/src/lib/libpam/pam_framework.c18
-rw-r--r--usr/src/lib/libproc/common/libproc.h4
-rw-r--r--usr/src/lib/libproc/common/mapfile-vers3
-rw-r--r--usr/src/lib/libproc/common/proc_names.c40
-rw-r--r--usr/src/lib/libreparse/common/fs_reparse_lib.c6
-rw-r--r--usr/src/lib/librpcsvc/common/rusers_simple.c13
-rw-r--r--usr/src/lib/libsaveargs/Makefile.com5
-rw-r--r--usr/src/lib/libsaveargs/amd64/saveargs.c2
-rw-r--r--usr/src/lib/libshare/smbfs/libshare_smbfs.c39
-rw-r--r--usr/src/lib/libshare/smbfs/libshare_smbfs.h6
-rw-r--r--usr/src/lib/libshell/common/data/solaris_cmdlist.h2
-rw-r--r--usr/src/lib/libsmbfs/Makefile.com27
-rw-r--r--usr/src/lib/libsmbfs/cflib.h4
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smb_lib.h45
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smbfs_api.h7
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip2
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_api.c8
-rw-r--r--usr/src/lib/libsmbfs/smb/connect.c650
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c246
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c51
-rw-r--r--usr/src/lib/libsmbfs/smb/findvc.c7
-rw-r--r--usr/src/lib/libsmbfs/smb/getaddr.c17
-rw-r--r--usr/src/lib/libsmbfs/smb/iod_wk.c96
-rw-r--r--usr/src/lib/libsmbfs/smb/keychain.c6
-rw-r--r--usr/src/lib/libsmbfs/smb/krb5ssp.c61
-rw-r--r--usr/src/lib/libsmbfs/smb/lgrep.awk68
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers31
-rw-r--r--usr/src/lib/libsmbfs/smb/nb_ssn.c336
-rw-r--r--usr/src/lib/libsmbfs/smb/negprot.c457
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.c47
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlm.h20
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c113
-rw-r--r--usr/src/lib/libsmbfs/smb/print.c33
-rw-r--r--usr/src/lib/libsmbfs/smb/private.h68
-rw-r--r--usr/src/lib/libsmbfs/smb/rap.c446
-rw-r--r--usr/src/lib/libsmbfs/smb/rc_scf.c231
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile.c86
-rw-r--r--usr/src/lib/libsmbfs/smb/rcfile_priv.h28
-rw-r--r--usr/src/lib/libsmbfs/smb/rq.c467
-rw-r--r--usr/src/lib/libsmbfs/smb/signing.c263
-rw-r--r--usr/src/lib/libsmbfs/smb/ssnsetup.c459
-rw-r--r--usr/src/lib/libstmfproxy/common/stmftransport.c10
-rw-r--r--usr/src/lib/libumem/Makefile.com20
-rw-r--r--usr/src/lib/libumem/amd64/umem_genasm.c96
-rw-r--r--usr/src/lib/libumem/common/envvar.c9
-rw-r--r--usr/src/lib/libumem/common/mapfile-vers4
-rw-r--r--usr/src/lib/libumem/common/umem.c20
-rw-r--r--usr/src/lib/libumem/common/umem_base.h4
-rw-r--r--usr/src/lib/libumem/common/vmem.c25
-rw-r--r--usr/src/lib/libumem/i386/umem_genasm.c91
-rw-r--r--usr/src/lib/libumem/sparc/umem_genasm.c7
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h2
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c21
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers1
-rw-r--r--usr/src/lib/libzfs_core/common/libzfs_core.c34
-rw-r--r--usr/src/lib/libzfs_core/common/libzfs_core.h3
-rw-r--r--usr/src/lib/libzfs_core/common/mapfile-vers7
-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.com109
-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-vers134
-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.com139
-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
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.c8
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c4
-rw-r--r--usr/src/man/man1/chgrp.176
-rw-r--r--usr/src/man/man1/chown.1326
-rw-r--r--usr/src/man/man1/dis.14
-rw-r--r--usr/src/man/man1/dump.14
-rw-r--r--usr/src/man/man1/elfdump.14
-rw-r--r--usr/src/man/man1/gprof.14
-rw-r--r--usr/src/man/man1/mdb.17
-rw-r--r--usr/src/man/man1/nm.139
-rw-r--r--usr/src/man/man1/pvs.14
-rw-r--r--usr/src/man/man1m/Makefile3
-rw-r--r--usr/src/man/man1m/ipadm.1m12
-rw-r--r--usr/src/man/man1m/savecore.1m23
-rw-r--r--usr/src/man/man1m/zfs.1m7
-rw-r--r--usr/src/man/man1m/zpool.1m16
-rwxr-xr-xusr/src/man/man1m/ztest.1m169
-rw-r--r--usr/src/man/man3c/sigfpe.3c14
-rw-r--r--usr/src/man/man3lib/libproc.3lib31
-rw-r--r--usr/src/man/man3proc/Makefile5
-rw-r--r--usr/src/man/man3proc/proc_fltname.3proc24
-rw-r--r--usr/src/man/man4/nsmbrc.435
-rw-r--r--usr/src/man/man5/smf_method.57
-rw-r--r--usr/src/man/man9e/open.9e17
-rw-r--r--usr/src/man/man9e/put.9e12
-rw-r--r--usr/src/man/man9e/srv.9e12
-rw-r--r--usr/src/pkg/manifests/system-file-system-zfs.mf1
-rw-r--r--usr/src/pkg/manifests/system-header.mf1
-rw-r--r--usr/src/pkg/manifests/system-library.man3proc.inc3
-rw-r--r--usr/src/pkg/manifests/system-test-elftest.mf57
-rw-r--r--usr/src/pkg/manifests/system-test-utiltest.mf15
-rw-r--r--usr/src/pkg/manifests/system-test-zfstest.mf14
-rw-r--r--usr/src/pkg/manifests/system-xopen-xcu4.mf4
-rw-r--r--usr/src/test/Makefile11
-rw-r--r--usr/src/test/elf-tests/Makefile20
-rw-r--r--usr/src/test/elf-tests/cmd/Makefile38
-rw-r--r--usr/src/test/elf-tests/cmd/elftest.ksh49
-rw-r--r--usr/src/test/elf-tests/doc/Makefile36
-rw-r--r--usr/src/test/elf-tests/doc/README59
-rw-r--r--usr/src/test/elf-tests/runfiles/Makefile40
-rw-r--r--usr/src/test/elf-tests/runfiles/default.run37
-rw-r--r--usr/src/test/elf-tests/tests/Makefile21
-rw-r--r--usr/src/test/elf-tests/tests/assert-deflib/Makefile48
-rw-r--r--usr/src/test/elf-tests/tests/assert-deflib/link.c (renamed from usr/src/cmd/sgs/test/ld/assert-deflib/link.c)0
-rw-r--r--usr/src/test/elf-tests/tests/assert-deflib/test-deflib.sh (renamed from usr/src/cmd/sgs/test/ld/assert-deflib/test-deflib.sh)9
-rw-r--r--usr/src/test/elf-tests/tests/tls/Makefile19
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/Makefile19
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/Makefile58
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/Makefile.test (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/Makefile)20
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/README5
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/amd64-ie-test.sh (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/x64-ie-test.sh)8
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style1-func.c (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style1-func.c)0
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style1-main.c (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style1-main.c)0
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style2.c (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style2.c)0
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func-with-r12.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func-with-r12.s)2
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func-with-r13.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func-with-r13.s)0
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func.s)0
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style1-main.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-main.s)0
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-badness.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-badness.s)2
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-r12.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-r12.s)3
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-r13.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-r13.s)2
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ie/style2.s (renamed from usr/src/cmd/sgs/test/ld/x64/tls/ie/style2.s)2
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile51
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile.test38
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ld/amd64-ld-test.sh46
-rw-r--r--usr/src/test/elf-tests/tests/tls/amd64/ld/ld-with-addend.s43
-rw-r--r--usr/src/test/elf-tests/tests/tls/i386/Makefile19
-rw-r--r--usr/src/test/elf-tests/tests/tls/i386/ld/Makefile51
-rw-r--r--usr/src/test/elf-tests/tests/tls/i386/ld/Makefile.test38
-rw-r--r--usr/src/test/elf-tests/tests/tls/i386/ld/half-ldm.s49
-rw-r--r--usr/src/test/elf-tests/tests/tls/i386/ld/i386-ld-test.sh43
-rw-r--r--usr/src/test/util-tests/runfiles/default.run1
-rw-r--r--usr/src/test/util-tests/tests/Makefile6
-rw-r--r--usr/src/test/util-tests/tests/chown/Makefile45
-rw-r--r--usr/src/test/util-tests/tests/chown/chown_test.ksh103
-rw-r--r--usr/src/test/util-tests/tests/chown/files/Makefile50
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout010
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout110
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout1010
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout1110
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout120
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout210
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout310
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout410
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout510
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout610
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout710
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout810
-rw-r--r--usr/src/test/util-tests/tests/chown/files/cout910
-rw-r--r--usr/src/test/util-tests/tests/ctf/Makefile149
-rw-r--r--usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com92
-rw-r--r--usr/src/test/util-tests/tests/ctf/README54
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-array.c116
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-common.c802
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-common.h141
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-enum.c143
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-float.c80
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-forward.c130
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-function.c88
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-int.c88
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-dedup.c82
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-forward.c132
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-reduction.c72
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-static.c290
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-merge-weak.c70
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-reference.c197
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-sou.c405
-rw-r--r--usr/src/test/util-tests/tests/ctf/check-weak.c70
-rw-r--r--usr/src/test/util-tests/tests/ctf/ctftest.ksh257
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-array.c29
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-enum.c74
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-float.c28
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-forward.c34
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-function.c71
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-int.c34
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest39
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c27
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c27
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c27
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c33
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest30
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c29
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c32
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest92
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers37
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c25
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c29
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest42
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c24
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c28
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest23
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c33
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-reference.c44
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-sou.c246
-rw-r--r--usr/src/test/util-tests/tests/ctf/test-weak.c25
-rw-r--r--usr/src/test/util-tests/tests/demangle/Makefile9
-rw-r--r--usr/src/test/util-tests/tests/demangle/rust.c214
-rw-r--r--usr/src/test/zfs-tests/include/libtest.shlib20
-rw-r--r--usr/src/test/zfs-tests/runfiles/delphix.run3
-rw-r--r--usr/src/test/zfs-tests/runfiles/omnios.run6
-rw-r--r--usr/src/test/zfs-tests/runfiles/openindiana.run6
-rw-r--r--usr/src/test/zfs-tests/runfiles/smartos.run17
-rw-r--r--usr/src/test/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib28
-rw-r--r--usr/src/test/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg7
-rw-r--r--usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/Makefile21
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh32
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh34
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh88
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh44
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/cleanup.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_001_pos.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_002_pos.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_003_pos.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_004_neg.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_005_pos.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_006_pos.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_007_neg.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/large_dnode/setup.ksh5
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/rsend/send_freeobjects.ksh81
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh111
-rw-r--r--usr/src/test/zfs-tests/tests/functional/slog/slog_014_pos.ksh1
-rw-r--r--usr/src/test/zfs-tests/tests/functional/snapshot/deadlist_lock.ksh14
-rw-r--r--usr/src/tools/cpcgen/cpcgen.c4
-rw-r--r--usr/src/tools/onbld/Checks/Comments.py20
-rw-r--r--usr/src/tools/onbld/Checks/SpellCheck.py43
-rwxr-xr-xusr/src/tools/quick/make-smbclnt45
-rwxr-xr-xusr/src/tools/quick/make-zfs6
-rw-r--r--usr/src/tools/scripts/cstyle.pl8
-rw-r--r--usr/src/tools/scripts/wsdiff.py118
-rw-r--r--usr/src/uts/common/Makefile.files7
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_brand.c28
-rw-r--r--usr/src/uts/common/brand/lx/syscall/lx_open.c25
-rw-r--r--usr/src/uts/common/brand/sn1/sn1_brand.c6
-rw-r--r--usr/src/uts/common/brand/solaris10/s10_brand.c6
-rw-r--r--usr/src/uts/common/crypto/io/dca.c24
-rw-r--r--usr/src/uts/common/exec/elf/elf.c1124
-rw-r--r--usr/src/uts/common/exec/elf/elf_impl.h17
-rw-r--r--usr/src/uts/common/exec/intp/intp.c6
-rw-r--r--usr/src/uts/common/exec/java/java.c4
-rw-r--r--usr/src/uts/common/exec/shbin/shbin.c6
-rw-r--r--usr/src/uts/common/fs/fs_subr.h2
-rw-r--r--usr/src/uts/common/fs/proc/prioctl.c10
-rw-r--r--usr/src/uts/common/fs/proc/prsubr.c21
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple22
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip1
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov29
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip1
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c180
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/offsets.in85
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c382
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h44
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c253
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c1325
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c148
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h231
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c269
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c1597
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h39
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c322
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h50
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c171
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h73
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c810
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h105
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c349
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c215
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h20
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c262
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h3
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c622
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c54
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c36
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c49
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c3
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h7
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c2514
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c926
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c896
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c294
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h184
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c9
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c112
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c396
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c186
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_ioctl.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_transact.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dfs.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vss.c2
-rw-r--r--usr/src/uts/common/fs/zfs/arc.c52
-rw-r--r--usr/src/uts/common/fs/zfs/dbuf.c7
-rw-r--r--usr/src/uts/common/fs/zfs/ddt_zap.c14
-rw-r--r--usr/src/uts/common/fs/zfs/dmu.c12
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_object.c2
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_objset.c15
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_recv.c2264
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_send.c2206
-rw-r--r--usr/src/uts/common/fs/zfs/dnode.c33
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c2
-rw-r--r--usr/src/uts/common/fs/zfs/metaslab.c48
-rw-r--r--usr/src/uts/common/fs/zfs/sys/arc.h1
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu_impl.h2
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu_recv.h64
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu_send.h28
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dnode.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_bookmark.h1
-rw-r--r--usr/src/uts/common/fs/zfs/sys/metaslab_impl.h9
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zap.h5
-rw-r--r--usr/src/uts/common/fs/zfs/zap.c46
-rw-r--r--usr/src/uts/common/fs/zfs/zap_micro.c31
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c44
-rw-r--r--usr/src/uts/common/inet/ip.h7
-rw-r--r--usr/src/uts/common/inet/ip/ip.c5
-rw-r--r--usr/src/uts/common/inet/ip/ip_ndp.c292
-rw-r--r--usr/src/uts/common/inet/ip/ipsecah.c28
-rw-r--r--usr/src/uts/common/inet/ip/ipsecesp.c26
-rw-r--r--usr/src/uts/common/inet/ip/keysock.c37
-rw-r--r--usr/src/uts/common/inet/ip/spdsock.c79
-rw-r--r--usr/src/uts/common/inet/ip_stack.h23
-rw-r--r--usr/src/uts/common/inet/ipd/ipd.c4
-rw-r--r--usr/src/uts/common/inet/nca/ncaddi.c16
-rw-r--r--usr/src/uts/common/io/aac/aac.c10
-rw-r--r--usr/src/uts/common/io/bpf/bpf.c4
-rw-r--r--usr/src/uts/common/io/conskbd.c4
-rw-r--r--usr/src/uts/common/io/devinfo.c12
-rw-r--r--usr/src/uts/common/io/dld/dld_proto.c2
-rw-r--r--usr/src/uts/common/io/dld/dld_str.c6
-rw-r--r--usr/src/uts/common/io/dls/dls.c16
-rw-r--r--usr/src/uts/common/io/dump.c4
-rw-r--r--usr/src/uts/common/io/ecpp.c36
-rw-r--r--usr/src/uts/common/io/fd.c6
-rw-r--r--usr/src/uts/common/io/hxge/hxge_hw.c6
-rw-r--r--usr/src/uts/common/io/hxge/hxge_kstats.c20
-rw-r--r--usr/src/uts/common/io/hxge/hxge_main.c10
-rw-r--r--usr/src/uts/common/io/hxge/hxge_pfc.c10
-rw-r--r--usr/src/uts/common/io/hxge/hxge_rxdma.c26
-rw-r--r--usr/src/uts/common/io/hxge/hxge_txdma.c4
-rw-r--r--usr/src/uts/common/io/i40e/i40e_main.c14
-rw-r--r--usr/src/uts/common/io/i40e/i40e_stats.c8
-rw-r--r--usr/src/uts/common/io/i40e/i40e_sw.h4
-rw-r--r--usr/src/uts/common/io/i40e/i40e_transceiver.c771
-rw-r--r--usr/src/uts/common/io/ib/clients/rds/rdsddi.c7
-rw-r--r--usr/src/uts/common/io/iwscons.c4
-rw-r--r--usr/src/uts/common/io/mac/mac_util.c12
-rw-r--r--usr/src/uts/common/io/mii/mii.c6
-rw-r--r--usr/src/uts/common/io/mr_sas/mr_sas.c12
-rw-r--r--usr/src/uts/common/io/nxge/nxge_mac.c39
-rw-r--r--usr/src/uts/common/io/ppp/sppp/sppp.c31
-rw-r--r--usr/src/uts/common/io/ppp/sppp/sppp.h14
-rw-r--r--usr/src/uts/common/io/ppp/sppp/sppp_mod.c18
-rw-r--r--usr/src/uts/common/io/ptm.c33
-rw-r--r--usr/src/uts/common/io/pts.c35
-rw-r--r--usr/src/uts/common/io/rwn/rt2860.c10
-rw-r--r--usr/src/uts/common/io/sata/adapters/ahci/ahci.c21
-rw-r--r--usr/src/uts/common/io/scsi/targets/st.c77
-rw-r--r--usr/src/uts/common/io/softmac/softmac_dev.c45
-rw-r--r--usr/src/uts/common/io/tem.c2
-rw-r--r--usr/src/uts/common/io/tty_pts.c12
-rw-r--r--usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c50
-rw-r--r--usr/src/uts/common/io/usb/clients/usbser/usbftdi/uftdi_dsd.c2
-rw-r--r--usr/src/uts/common/io/usb/usbdevs2669
-rw-r--r--usr/src/uts/common/netsmb/mchain.h25
-rw-r--r--usr/src/uts/common/netsmb/smb.h62
-rw-r--r--usr/src/uts/common/netsmb/smb2.h465
-rw-r--r--usr/src/uts/common/netsmb/smb_dev.h178
-rw-r--r--usr/src/uts/common/os/brand.c8
-rw-r--r--usr/src/uts/common/os/core.c20
-rw-r--r--usr/src/uts/common/os/dumpsubr.c2
-rw-r--r--usr/src/uts/common/os/exec.c8
-rw-r--r--usr/src/uts/common/os/sunmdi.c10
-rw-r--r--usr/src/uts/common/os/sysent.c14
-rw-r--r--usr/src/uts/common/smb/Makefile4
-rw-r--r--usr/src/uts/common/smb/ntaccess.h (renamed from usr/src/uts/common/smbsrv/ntaccess.h)4
-rw-r--r--usr/src/uts/common/smb/winioctl.h (renamed from usr/src/uts/common/smbsrv/winioctl.h)8
-rw-r--r--usr/src/uts/common/smbsrv/Makefile4
-rw-r--r--usr/src/uts/common/smbsrv/smb.h4
-rw-r--r--usr/src/uts/common/sys/brand.h11
-rw-r--r--usr/src/uts/common/sys/conf.h10
-rw-r--r--usr/src/uts/common/sys/debug.h4
-rw-r--r--usr/src/uts/common/sys/dirent.h2
-rw-r--r--usr/src/uts/common/sys/dld_impl.h2
-rw-r--r--usr/src/uts/common/sys/dnlc.h6
-rw-r--r--usr/src/uts/common/sys/exec.h28
-rw-r--r--usr/src/uts/common/sys/file.h17
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h1
-rw-r--r--usr/src/uts/common/sys/ieeefp.h6
-rw-r--r--usr/src/uts/common/sys/model.h2
-rw-r--r--usr/src/uts/common/sys/modhash.h2
-rw-r--r--usr/src/uts/common/sys/poll.h2
-rw-r--r--usr/src/uts/common/sys/prsystm.h4
-rw-r--r--usr/src/uts/common/sys/share.h2
-rw-r--r--usr/src/uts/common/sys/signal.h2
-rw-r--r--usr/src/uts/common/sys/stream.h6
-rw-r--r--usr/src/uts/common/sys/strsubr.h17
-rw-r--r--usr/src/uts/common/sys/t_kuser.h1
-rw-r--r--usr/src/uts/i86pc/Makefile.files2
-rw-r--r--usr/src/uts/i86pc/Makefile.rules3
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic_common.c41
-rw-r--r--usr/src/uts/i86pc/io/viona/viona.c12
-rw-r--r--usr/src/uts/i86pc/io/vmm/amd/svm.c122
-rw-r--r--usr/src/uts/i86pc/io/vmm/amd/svm_msr.c26
-rw-r--r--usr/src/uts/i86pc/io/vmm/amd/svm_softc.h15
-rw-r--r--usr/src/uts/i86pc/io/vmm/amd/svm_support.s188
-rw-r--r--usr/src/uts/i86pc/io/vmm/intel/vmx.c6
-rw-r--r--usr/src/uts/i86pc/io/vmm/intel/vmx.h3
-rw-r--r--usr/src/uts/i86pc/io/vmm/intel/vmx_support.s40
-rw-r--r--usr/src/uts/i86pc/io/vmm/vm/vm_glue.h1
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c15
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_rvi.c297
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c16
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_support.s54
-rw-r--r--usr/src/uts/i86pc/io/vmm/x86.c12
-rw-r--r--usr/src/uts/i86pc/os/cpuid.c80
-rw-r--r--usr/src/uts/i86pc/os/fakebop.c18
-rw-r--r--usr/src/uts/i86pc/os/hma.c332
-rw-r--r--usr/src/uts/i86pc/os/mlsetup.c20
-rw-r--r--usr/src/uts/i86pc/sys/Makefile1
-rw-r--r--usr/src/uts/i86pc/sys/apic_common.h10
-rw-r--r--usr/src/uts/i86pc/sys/hma.h10
-rw-r--r--usr/src/uts/i86pc/sys/vmm.h4
-rw-r--r--usr/src/uts/intel/ip/ip.global-objs.debug644
-rw-r--r--usr/src/uts/intel/ip/ip.global-objs.obj644
-rw-r--r--usr/src/uts/intel/nsmb/ioc_check.ref89
-rw-r--r--usr/src/uts/intel/pcbe/core_pcbe.c3
-rw-r--r--usr/src/uts/intel/sys/bootconf.h4
-rw-r--r--usr/src/uts/intel/sys/controlregs.h12
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h12
-rw-r--r--usr/src/uts/sparc/ip/ip.global-objs.debug644
-rw-r--r--usr/src/uts/sparc/ip/ip.global-objs.obj644
-rw-r--r--usr/src/uts/sparc/nsmb/ioc_check.ref89
692 files changed, 48630 insertions, 16152 deletions
diff --git a/usr/src/Makefile b/usr/src/Makefile
index e29a4c518a..47afb31733 100644
--- a/usr/src/Makefile
+++ b/usr/src/Makefile
@@ -193,8 +193,19 @@ sgs: rootdirs .WAIT sysheaders userheaders .WAIT \
#
setup: closedbins bldtools sgs mapfiles
+#
+# Always build tools as non-DEBUG.
+# When nightly launches a build it first builds non-DEBUG tools and then
+# configures the environment so that these tools are used for building
+# subsequently. If a recursive build from usr/src then builds DEBUG tools,
+# the tools will be rebuilt using themselves resulting in a race condition
+# that can cause the build to fail - see https://www.illumos.org/issues/10462
+# for more details.
+# A manual build in usr/src/tools in a DEBUG bldenv will still do a DEBUG
+# tools build.
+#
bldtools:
- @cd tools; pwd; $(MAKE) install
+ @cd tools; pwd; $(MAKE) RELEASE_BUILD= install
# /var/mail/:saved is a special case because of the colon in the name.
#
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version
index 302dd133b6..205b3d6065 100644
--- a/usr/src/boot/Makefile.version
+++ b/usr/src/boot/Makefile.version
@@ -33,4 +33,4 @@ LOADER_VERSION = 1.1
# Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
# The version is processed from left to right, the version number can only
# be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2019.02.16.1
+BOOT_VERSION = $(LOADER_VERSION)-2019.03.07.2
diff --git a/usr/src/boot/lib/libstand/Makefile.inc b/usr/src/boot/lib/libstand/Makefile.inc
index 1fb9e216f9..8bb6258ac0 100644
--- a/usr/src/boot/lib/libstand/Makefile.inc
+++ b/usr/src/boot/lib/libstand/Makefile.inc
@@ -29,7 +29,7 @@ SRCS += $(SASRC)/sbrk.c $(SASRC)/twiddle.c
SRCS += $(SASRC)/zalloc.c $(SASRC)/zalloc_malloc.c
OBJS= __main.o assert.o bcd.o environment.o \
- getopt.o gets.o globals.o pager.o printf.o \
+ getopt.o gets.o globals.o pager.o panic.o printf.o \
strdup.o strerror.o strtol.o strtoul.o random.o \
sbrk.o twiddle.o zalloc.o zalloc_malloc.o
diff --git a/usr/src/boot/lib/libstand/arp.c b/usr/src/boot/lib/libstand/arp.c
index 65e421d1bb..7f836689c8 100644
--- a/usr/src/boot/lib/libstand/arp.c
+++ b/usr/src/boot/lib/libstand/arp.c
@@ -51,11 +51,11 @@
#include "net.h"
/* Cache stuff */
-#define ARP_NUM 8 /* need at most 3 arp entries */
+#define ARP_NUM 8 /* need at most 3 arp entries */
struct arp_list {
struct in_addr addr;
- u_char ea[6];
+ uchar_t ea[6];
} arp_list[ARP_NUM] = {
/* XXX - net order `INADDR_BROADCAST' must be a constant */
{ {0xffffffff}, BA }
@@ -67,7 +67,7 @@ static ssize_t arpsend(struct iodesc *, void *, size_t);
static ssize_t arprecv(struct iodesc *, void **, void **, time_t, void *);
/* Broadcast an ARP packet, asking who has addr on interface d */
-u_char *
+uchar_t *
arpwhohas(struct iodesc *d, struct in_addr addr)
{
int i;
@@ -78,7 +78,7 @@ arpwhohas(struct iodesc *d, struct in_addr addr)
struct ether_header eh;
struct {
struct ether_arp arp;
- u_char pad[18]; /* 60 - sizeof(...) */
+ uchar_t pad[18]; /* 60 - sizeof (...) */
} data;
} wbuf;
@@ -94,21 +94,21 @@ arpwhohas(struct iodesc *d, struct in_addr addr)
}
#ifdef ARP_DEBUG
- if (debug)
- printf("arpwhohas: send request for %s\n", inet_ntoa(addr));
+ if (debug)
+ printf("arpwhohas: send request for %s\n", inet_ntoa(addr));
#endif
- bzero((char*)&wbuf.data, sizeof(wbuf.data));
+ bzero((char *)&wbuf.data, sizeof (wbuf.data));
ah = &wbuf.data.arp;
ah->arp_hrd = htons(ARPHRD_ETHER);
ah->arp_pro = htons(ETHERTYPE_IP);
- ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */
- ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
+ ah->arp_hln = sizeof (ah->arp_sha); /* hardware address length */
+ ah->arp_pln = sizeof (ah->arp_spa); /* protocol address length */
ah->arp_op = htons(ARPOP_REQUEST);
MACPY(d->myea, ah->arp_sha);
- bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa));
+ bcopy(&d->myip, ah->arp_spa, sizeof (ah->arp_spa));
/* Leave zeros in arp_tha */
- bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
+ bcopy(&addr, ah->arp_tpa, sizeof (ah->arp_tpa));
/* Store ip address in cache (incomplete entry). */
al->addr = addr;
@@ -116,16 +116,14 @@ arpwhohas(struct iodesc *d, struct in_addr addr)
pkt = NULL;
ah = NULL;
i = sendrecv(d,
- arpsend, &wbuf.data, sizeof(wbuf.data),
+ arpsend, &wbuf.data, sizeof (wbuf.data),
arprecv, &pkt, (void **)&ah, NULL);
- if (i == -1) {
- panic("arp: no response for %s\n",
- inet_ntoa(addr));
- }
+ if (i == -1)
+ panic("arp: no response for %s", inet_ntoa(addr));
/* Store ethernet address in cache */
#ifdef ARP_DEBUG
- if (debug) {
+ if (debug) {
struct ether_header *eh;
eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN);
@@ -146,7 +144,7 @@ arpsend(struct iodesc *d, void *pkt, size_t len)
{
#ifdef ARP_DEBUG
- if (debug)
+ if (debug)
printf("arpsend: called\n");
#endif
@@ -162,18 +160,18 @@ arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, void *extra)
{
ssize_t n;
struct ether_arp *ah;
- u_int16_t etype; /* host order */
+ uint16_t etype; /* host order */
void *ptr;
#ifdef ARP_DEBUG
- if (debug)
+ if (debug)
printf("arprecv: ");
#endif
ptr = NULL;
n = readether(d, &ptr, (void **)&ah, tleft, &etype);
errno = 0; /* XXX */
- if (n == -1 || n < sizeof(struct ether_arp)) {
+ if (n == -1 || n < sizeof (struct ether_arp)) {
#ifdef ARP_DEBUG
if (debug)
printf("bad len=%d\n", n);
@@ -194,9 +192,8 @@ arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, void *extra)
/* Ethernet address now checked in readether() */
if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
ah->arp_pro != htons(ETHERTYPE_IP) ||
- ah->arp_hln != sizeof(ah->arp_sha) ||
- ah->arp_pln != sizeof(ah->arp_spa) )
- {
+ ah->arp_hln != sizeof (ah->arp_sha) ||
+ ah->arp_pln != sizeof (ah->arp_spa)) {
#ifdef ARP_DEBUG
if (debug)
printf("bad hrd/pro/hln/pln\n");
@@ -225,9 +222,7 @@ arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, void *extra)
}
/* Is the reply from the source we want? */
- if (bcmp(&arp_list[arp_num].addr,
- ah->arp_spa, sizeof(ah->arp_spa)))
- {
+ if (bcmp(&arp_list[arp_num].addr, ah->arp_spa, sizeof (ah->arp_spa))) {
#ifdef ARP_DEBUG
if (debug)
printf("unwanted address\n");
@@ -239,7 +234,7 @@ arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, void *extra)
/* We have our answer. */
#ifdef ARP_DEBUG
- if (debug)
+ if (debug)
printf("got it\n");
#endif
*pkt = ptr;
@@ -258,9 +253,8 @@ arp_reply(struct iodesc *d, void *pkt)
if (arp->arp_hrd != htons(ARPHRD_ETHER) ||
arp->arp_pro != htons(ETHERTYPE_IP) ||
- arp->arp_hln != sizeof(arp->arp_sha) ||
- arp->arp_pln != sizeof(arp->arp_spa) )
- {
+ arp->arp_hln != sizeof (arp->arp_sha) ||
+ arp->arp_pln != sizeof (arp->arp_spa)) {
#ifdef ARP_DEBUG
if (debug)
printf("arp_reply: bad hrd/pro/hln/pln\n");
@@ -277,7 +271,7 @@ arp_reply(struct iodesc *d, void *pkt)
}
/* If we are not the target, ignore the request. */
- if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa)))
+ if (bcmp(arp->arp_tpa, &d->myip, sizeof (arp->arp_tpa)))
return;
#ifdef ARP_DEBUG
@@ -288,16 +282,16 @@ arp_reply(struct iodesc *d, void *pkt)
arp->arp_op = htons(ARPOP_REPLY);
/* source becomes target */
- bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha));
- bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa));
+ bcopy(arp->arp_sha, arp->arp_tha, sizeof (arp->arp_tha));
+ bcopy(arp->arp_spa, arp->arp_tpa, sizeof (arp->arp_tpa));
/* here becomes source */
- bcopy(d->myea, arp->arp_sha, sizeof(arp->arp_sha));
- bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa));
+ bcopy(d->myea, arp->arp_sha, sizeof (arp->arp_sha));
+ bcopy(&d->myip, arp->arp_spa, sizeof (arp->arp_spa));
/*
* No need to get fancy here. If the send fails, the
* requestor will just ask again.
*/
- (void) sendether(d, pkt, sizeof(*arp) + 18,
- arp->arp_tha, ETHERTYPE_ARP);
+ (void) sendether(d, pkt, sizeof (*arp) + 18,
+ arp->arp_tha, ETHERTYPE_ARP);
}
diff --git a/usr/src/boot/lib/libstand/assert.c b/usr/src/boot/lib/libstand/assert.c
index 8eec63a472..7ed70d70ee 100644
--- a/usr/src/boot/lib/libstand/assert.c
+++ b/usr/src/boot/lib/libstand/assert.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith.
* All rights reserved.
*
@@ -25,7 +25,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
#include <assert.h>
@@ -35,10 +34,9 @@ void
__assert(const char *func, const char *file, int line, const char *expression)
{
if (func == NULL)
- panic("Assertion failed: (%s), file %s, line %d.\n",
+ panic("Assertion failed: (%s), file %s, line %d.",
expression, file, line);
else
- panic(
- "Assertion failed: (%s), function %s, file %s, line %d.\n",
+ panic("Assertion failed: (%s), function %s, file %s, line %d.",
expression, func, file, line);
}
diff --git a/usr/src/boot/lib/libstand/bzipfs.c b/usr/src/boot/lib/libstand/bzipfs.c
index d99014ade7..1c2cc39904 100644
--- a/usr/src/boot/lib/libstand/bzipfs.c
+++ b/usr/src/boot/lib/libstand/bzipfs.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1998 Michael Smith.
* Copyright (c) 2000 Maxim Sobolev
* All rights reserved.
@@ -37,71 +37,79 @@
#include <sys/unistd.h>
struct open_file {
- int f_flags; /* see F_* below */
- void *f_fsdata; /* file system specific data */
+ int f_flags; /* see F_* below */
+ void *f_fsdata; /* file system specific data */
};
-#define F_READ 0x0001 /* file opened for reading */
-#define EOFFSET (ELAST+8) /* relative seek not supported */
-static inline u_int min(u_int a, u_int b) { return(a < b ? a : b); }
-#define panic(x, y) abort()
+#define F_READ 0x0001 /* file opened for reading */
+#define EOFFSET (ELAST + 8) /* relative seek not supported */
+#define panic(x, y) abort()
+
+static inline uint_t
+min(uint_t a, uint_t b)
+{
+ return (a < b ? a : b);
+}
#endif
#include <sys/stat.h>
#include <string.h>
#include <bzlib.h>
-#define BZ_BUFSIZE 2048 /* XXX larger? */
+#define BZ_BUFSIZE 2048 /* XXX larger? */
struct bz_file
{
- int bzf_rawfd;
- bz_stream bzf_bzstream;
- char bzf_buf[BZ_BUFSIZE];
- int bzf_endseen;
+ int bzf_rawfd;
+ bz_stream bzf_bzstream;
+ char bzf_buf[BZ_BUFSIZE];
+ int bzf_endseen;
};
-static int bzf_fill(struct bz_file *z);
-static int bzf_open(const char *path, struct open_file *f);
-static int bzf_close(struct open_file *f);
-static int bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid);
-static off_t bzf_seek(struct open_file *f, off_t offset, int where);
-static int bzf_stat(struct open_file *f, struct stat *sb);
+static int bzf_fill(struct bz_file *);
+static int bzf_open(const char *, struct open_file *);
+static int bzf_close(struct open_file *);
+static int bzf_read(struct open_file *, void *, size_t, size_t *);
+static off_t bzf_seek(struct open_file *, off_t, int);
+static int bzf_stat(struct open_file *, struct stat *);
#ifndef REGRESSION
struct fs_ops bzipfs_fsops = {
- "bzip",
- bzf_open,
- bzf_close,
- bzf_read,
- null_write,
- bzf_seek,
- bzf_stat,
- null_readdir
+ .fs_name = "bzip",
+ .fo_open = bzf_open,
+ .fo_close = bzf_close,
+ .fo_read = bzf_read,
+ .fo_write = null_write,
+ .fo_seek = bzf_seek,
+ .fo_stat = bzf_stat,
+ .fo_readdir = null_readdir
};
#endif
static int
bzf_fill(struct bz_file *bzf)
{
- int result;
- int req;
-
- req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in;
- result = 0;
-
- /* If we need more */
- if (req > 0) {
- /* move old data to bottom of buffer */
- if (req < BZ_BUFSIZE)
- bcopy(bzf->bzf_buf + req, bzf->bzf_buf, BZ_BUFSIZE - req);
-
- /* read to fill buffer and update availibility data */
- result = read(bzf->bzf_rawfd, bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req);
- bzf->bzf_bzstream.next_in = bzf->bzf_buf;
- if (result >= 0)
- bzf->bzf_bzstream.avail_in += result;
- }
- return(result);
+ int result;
+ int req;
+
+ req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in;
+ result = 0;
+
+ /* If we need more */
+ if (req > 0) {
+ /* move old data to bottom of buffer */
+ if (req < BZ_BUFSIZE) {
+ bcopy(bzf->bzf_buf + req, bzf->bzf_buf,
+ BZ_BUFSIZE - req);
+ }
+
+ /* read to fill buffer and update availibility data */
+ result = read(bzf->bzf_rawfd,
+ bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req);
+ bzf->bzf_bzstream.next_in = bzf->bzf_buf;
+ if (result >= 0)
+ bzf->bzf_bzstream.avail_in += result;
+ }
+ return (result);
}
/*
@@ -112,10 +120,10 @@ bzf_fill(struct bz_file *bzf)
static int
get_byte(struct bz_file *bzf)
{
- if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1))
- return(-1);
- bzf->bzf_bzstream.avail_in--;
- return(*(bzf->bzf_bzstream.next_in)++);
+ if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1))
+ return (-1);
+ bzf->bzf_bzstream.avail_in--;
+ return (*(bzf->bzf_bzstream.next_in)++);
}
static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */
@@ -123,265 +131,274 @@ static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */
static int
check_header(struct bz_file *bzf)
{
- unsigned int len;
- int c;
-
- /* Check the bzip2 magic header */
- for (len = 0; len < 3; len++) {
- c = get_byte(bzf);
- if (c != bz_magic[len]) {
- return(1);
+ unsigned int len;
+ int c;
+
+ /* Check the bzip2 magic header */
+ for (len = 0; len < 3; len++) {
+ c = get_byte(bzf);
+ if (c != bz_magic[len]) {
+ return (1);
+ }
}
- }
- /* Check that the block size is valid */
- c = get_byte(bzf);
- if (c < '1' || c > '9')
- return(1);
+ /* Check that the block size is valid */
+ c = get_byte(bzf);
+ if (c < '1' || c > '9')
+ return (1);
- /* Put back bytes that we've took from the input stream */
- bzf->bzf_bzstream.next_in -= 4;
- bzf->bzf_bzstream.avail_in += 4;
+ /* Put back bytes that we've took from the input stream */
+ bzf->bzf_bzstream.next_in -= 4;
+ bzf->bzf_bzstream.avail_in += 4;
- return(0);
+ return (0);
}
-
+
static int
bzf_open(const char *fname, struct open_file *f)
{
- static char *bzfname;
- int rawfd;
- struct bz_file *bzf;
- char *cp;
- int error;
- struct stat sb;
-
- /* Have to be in "just read it" mode */
- if (f->f_flags != F_READ)
- return(EPERM);
-
- /* If the name already ends in .gz or .bz2, ignore it */
- if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
- || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
- return(ENOENT);
-
- /* Construct new name */
- bzfname = malloc(strlen(fname) + 5);
- if (bzfname == NULL)
- return(ENOMEM);
- sprintf(bzfname, "%s.bz2", fname);
-
- /* Try to open the compressed datafile */
- rawfd = open(bzfname, O_RDONLY);
- free(bzfname);
- if (rawfd == -1)
- return(ENOENT);
-
- if (fstat(rawfd, &sb) < 0) {
- printf("bzf_open: stat failed\n");
- close(rawfd);
- return(ENOENT);
- }
- if (!S_ISREG(sb.st_mode)) {
- printf("bzf_open: not a file\n");
- close(rawfd);
- return(EISDIR); /* best guess */
- }
-
- /* Allocate a bz_file structure, populate it */
- bzf = malloc(sizeof(struct bz_file));
- if (bzf == NULL)
- return(ENOMEM);
- bzero(bzf, sizeof(struct bz_file));
- bzf->bzf_rawfd = rawfd;
-
- /* Verify that the file is bzipped */
- if (check_header(bzf)) {
- close(bzf->bzf_rawfd);
- free(bzf);
- return(EFTYPE);
- }
+ static char *bzfname;
+ int rawfd;
+ struct bz_file *bzf;
+ char *cp;
+ int error;
+ struct stat sb;
+
+ /* Have to be in "just read it" mode */
+ if (f->f_flags != F_READ)
+ return (EPERM);
+
+ /* If the name already ends in .gz or .bz2, ignore it */
+ if ((cp = strrchr(fname, '.')) &&
+ ((strcmp(cp, ".gz") == 0) ||
+ (strcmp(cp, ".bz2") == 0) ||
+ (strcmp(cp, ".split") == 0)))
+ return (ENOENT);
+
+ /* Construct new name */
+ bzfname = malloc(strlen(fname) + 5);
+ if (bzfname == NULL)
+ return (ENOMEM);
+ sprintf(bzfname, "%s.bz2", fname);
+
+ /* Try to open the compressed datafile */
+ rawfd = open(bzfname, O_RDONLY);
+ free(bzfname);
+ if (rawfd == -1)
+ return (ENOENT);
+
+ if (fstat(rawfd, &sb) < 0) {
+ printf("bzf_open: stat failed\n");
+ close(rawfd);
+ return (ENOENT);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ printf("bzf_open: not a file\n");
+ close(rawfd);
+ return (EISDIR); /* best guess */
+ }
- /* Initialise the inflation engine */
- if ((error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1)) != BZ_OK) {
- printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error);
- close(bzf->bzf_rawfd);
- free(bzf);
- return(EIO);
- }
+ /* Allocate a bz_file structure, populate it */
+ bzf = malloc(sizeof (struct bz_file));
+ if (bzf == NULL)
+ return (ENOMEM);
+ bzero(bzf, sizeof (struct bz_file));
+ bzf->bzf_rawfd = rawfd;
+
+ /* Verify that the file is bzipped */
+ if (check_header(bzf)) {
+ close(bzf->bzf_rawfd);
+ free(bzf);
+ return (EFTYPE);
+ }
- /* Looks OK, we'll take it */
- f->f_fsdata = bzf;
- return(0);
+ /* Initialise the inflation engine */
+ error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1);
+ if (error != BZ_OK) {
+ printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error);
+ close(bzf->bzf_rawfd);
+ free(bzf);
+ return (EIO);
+ }
+
+ /* Looks OK, we'll take it */
+ f->f_fsdata = bzf;
+ return (0);
}
static int
bzf_close(struct open_file *f)
{
- struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
-
- BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
- close(bzf->bzf_rawfd);
- free(bzf);
- return(0);
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+
+ BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
+ close(bzf->bzf_rawfd);
+ free(bzf);
+ return (0);
}
-
-static int
+
+static int
bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
{
- struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
- int error;
-
- bzf->bzf_bzstream.next_out = buf; /* where and how much */
- bzf->bzf_bzstream.avail_out = size;
-
- while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) {
- if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) {
- printf("bzf_read: fill error\n");
- return(EIO);
- }
- if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */
- printf("bzf_read: unexpected EOF\n");
- if (bzf->bzf_bzstream.avail_out == size)
- return(EIO);
- break;
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+ int error;
+
+ bzf->bzf_bzstream.next_out = buf; /* where and how much */
+ bzf->bzf_bzstream.avail_out = size;
+
+ while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) {
+ if ((bzf->bzf_bzstream.avail_in == 0) &&
+ (bzf_fill(bzf) == -1)) {
+ printf("bzf_read: fill error\n");
+ return (EIO);
+ }
+ if (bzf->bzf_bzstream.avail_in == 0) {
+ /* oops, unexpected EOF */
+ printf("bzf_read: unexpected EOF\n");
+ if (bzf->bzf_bzstream.avail_out == size)
+ return (EIO);
+ break;
+ }
+
+ /* decompression pass */
+ error = BZ2_bzDecompress(&bzf->bzf_bzstream);
+ if (error == BZ_STREAM_END) { /* EOF, all done */
+ bzf->bzf_endseen = 1;
+ break;
+ }
+ if (error != BZ_OK) { /* argh, decompression error */
+ printf("bzf_read: BZ2_bzDecompress returned %d\n",
+ error);
+ return (EIO);
+ }
}
-
- error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */
- if (error == BZ_STREAM_END) { /* EOF, all done */
- bzf->bzf_endseen = 1;
- break;
- }
- if (error != BZ_OK) { /* argh, decompression error */
- printf("bzf_read: BZ2_bzDecompress returned %d\n", error);
- return(EIO);
- }
- }
- if (resid != NULL)
- *resid = bzf->bzf_bzstream.avail_out;
- return(0);
+ if (resid != NULL)
+ *resid = bzf->bzf_bzstream.avail_out;
+ return (0);
}
static int
bzf_rewind(struct open_file *f)
{
- struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
- struct bz_file *bzf_tmp;
-
- /*
- * Since bzip2 does not have an equivalent inflateReset function a crude
- * one needs to be provided. The functions all called in such a way that
- * at any time an error occurs a roll back can be done (effectively making
- * this rewind 'atomic', either the reset occurs successfully or not at all,
- * with no 'undefined' state happening).
- */
-
- /* Allocate a bz_file structure, populate it */
- bzf_tmp = malloc(sizeof(struct bz_file));
- if (bzf_tmp == NULL)
- return(-1);
- bzero(bzf_tmp, sizeof(struct bz_file));
- bzf_tmp->bzf_rawfd = bzf->bzf_rawfd;
-
- /* Initialise the inflation engine */
- if (BZ2_bzDecompressInit(&(bzf_tmp->bzf_bzstream), 0, 1) != BZ_OK) {
- free(bzf_tmp);
- return(-1);
- }
-
- /* Seek back to the beginning of the file */
- if (lseek(bzf->bzf_rawfd, 0, SEEK_SET) == -1) {
- BZ2_bzDecompressEnd(&(bzf_tmp->bzf_bzstream));
- free(bzf_tmp);
- return(-1);
- }
-
- /* Free old bz_file data */
- BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
- free(bzf);
-
- /* Use the new bz_file data */
- f->f_fsdata = bzf_tmp;
-
- return(0);
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+ struct bz_file *bzf_tmp;
+
+ /*
+ * Since bzip2 does not have an equivalent inflateReset function a crude
+ * one needs to be provided. The functions all called in such a way that
+ * at any time an error occurs a roll back can be done (effectively
+ * making this rewind 'atomic', either the reset occurs successfully
+ * or not at all, with no 'undefined' state happening).
+ */
+
+ /* Allocate a bz_file structure, populate it */
+ bzf_tmp = malloc(sizeof (struct bz_file));
+ if (bzf_tmp == NULL)
+ return (-1);
+ bzero(bzf_tmp, sizeof (struct bz_file));
+ bzf_tmp->bzf_rawfd = bzf->bzf_rawfd;
+
+ /* Initialise the inflation engine */
+ if (BZ2_bzDecompressInit(&(bzf_tmp->bzf_bzstream), 0, 1) != BZ_OK) {
+ free(bzf_tmp);
+ return (-1);
+ }
+
+ /* Seek back to the beginning of the file */
+ if (lseek(bzf->bzf_rawfd, 0, SEEK_SET) == -1) {
+ BZ2_bzDecompressEnd(&(bzf_tmp->bzf_bzstream));
+ free(bzf_tmp);
+ return (-1);
+ }
+
+ /* Free old bz_file data */
+ BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
+ free(bzf);
+
+ /* Use the new bz_file data */
+ f->f_fsdata = bzf_tmp;
+
+ return (0);
}
static off_t
bzf_seek(struct open_file *f, off_t offset, int where)
{
- struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
- off_t target;
- char discard[16];
-
- switch (where) {
- case SEEK_SET:
- target = offset;
- break;
- case SEEK_CUR:
- target = offset + bzf->bzf_bzstream.total_out_lo32;
- break;
- default:
- errno = EINVAL;
- return(-1);
- }
-
- /* Can we get there from here? */
- if (target < bzf->bzf_bzstream.total_out_lo32 && bzf_rewind(f) != 0) {
- errno = EOFFSET;
- return -1;
- }
-
- /* if bzf_rewind was called then bzf has changed */
- bzf = (struct bz_file *)f->f_fsdata;
-
- /* skip forwards if required */
- while (target > bzf->bzf_bzstream.total_out_lo32) {
- errno = bzf_read(f, discard, min(sizeof(discard),
- target - bzf->bzf_bzstream.total_out_lo32), NULL);
- if (errno)
- return(-1);
- }
- /* This is where we are (be honest if we overshot) */
- return(bzf->bzf_bzstream.total_out_lo32);
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+ off_t target;
+ char discard[16];
+
+ switch (where) {
+ case SEEK_SET:
+ target = offset;
+ break;
+ case SEEK_CUR:
+ target = offset + bzf->bzf_bzstream.total_out_lo32;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Can we get there from here? */
+ if (target < bzf->bzf_bzstream.total_out_lo32 && bzf_rewind(f) != 0) {
+ errno = EOFFSET;
+ return (-1);
+ }
+
+ /* if bzf_rewind was called then bzf has changed */
+ bzf = (struct bz_file *)f->f_fsdata;
+
+ /* skip forwards if required */
+ while (target > bzf->bzf_bzstream.total_out_lo32) {
+ errno = bzf_read(f, discard, min(sizeof (discard),
+ target - bzf->bzf_bzstream.total_out_lo32), NULL);
+ if (errno)
+ return (-1);
+ }
+ /* This is where we are (be honest if we overshot) */
+ return (bzf->bzf_bzstream.total_out_lo32);
}
static int
bzf_stat(struct open_file *f, struct stat *sb)
{
- struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
- int result;
+ struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
+ int result;
- /* stat as normal, but indicate that size is unknown */
- if ((result = fstat(bzf->bzf_rawfd, sb)) == 0)
- sb->st_size = -1;
- return(result);
+ /* stat as normal, but indicate that size is unknown */
+ if ((result = fstat(bzf->bzf_rawfd, sb)) == 0)
+ sb->st_size = -1;
+ return (result);
}
void
bz_internal_error(int errorcode)
{
- panic("bzipfs: critical error %d in bzip2 library occured\n", errorcode);
+ panic("bzipfs: critical error %d in bzip2 library occured",
+ errorcode);
}
#ifdef REGRESSION
/* Small test case, open and decompress test.bz2 */
-int main()
+int
+main()
{
- struct open_file f;
- char buf[1024];
- size_t resid;
- int err;
-
- memset(&f, '\0', sizeof(f));
- f.f_flags = F_READ;
- err = bzf_open("test", &f);
- if (err != 0)
- exit(1);
- do {
- err = bzf_read(&f, buf, sizeof(buf), &resid);
- } while (err == 0 && resid != sizeof(buf));
-
- if (err != 0)
- exit(2);
- exit(0);
+ struct open_file f;
+ char buf[1024];
+ size_t resid;
+ int err;
+
+ memset(&f, '\0', sizeof (f));
+ f.f_flags = F_READ;
+ err = bzf_open("test", &f);
+ if (err != 0)
+ exit(1);
+ do {
+ err = bzf_read(&f, buf, sizeof (buf), &resid);
+ } while (err == 0 && resid != sizeof (buf));
+
+ if (err != 0)
+ exit(2);
+ exit(0);
}
#endif
diff --git a/usr/src/boot/lib/libstand/netif.c b/usr/src/boot/lib/libstand/netif.c
index 8f46a29668..0e6c71569d 100644
--- a/usr/src/boot/lib/libstand/netif.c
+++ b/usr/src/boot/lib/libstand/netif.c
@@ -179,7 +179,7 @@ netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint)
desc->io_netif = nif;
#ifdef PARANOID
if (drv->netif_init == NULL)
- panic("%s%d: no netif_init support\n", drv->netif_bname,
+ panic("%s%d: no netif_init support", drv->netif_bname,
nif->nif_unit);
#endif
drv->netif_init(desc, machdep_hint);
@@ -198,7 +198,7 @@ netif_detach(struct netif *nif)
#endif
#ifdef PARANOID
if (drv->netif_end == NULL)
- panic("%s%d: no netif_end support\n", drv->netif_bname,
+ panic("%s%d: no netif_end support", drv->netif_bname,
nif->nif_unit);
#endif
drv->netif_end(nif);
@@ -219,7 +219,7 @@ netif_get(struct iodesc *desc, void **pkt, time_t timo)
#endif
#ifdef PARANOID
if (drv->netif_get == NULL)
- panic("%s%d: no netif_get support\n", drv->netif_bname,
+ panic("%s%d: no netif_get support", drv->netif_bname,
nif->nif_unit);
#endif
rv = drv->netif_get(desc, pkt, timo);
@@ -246,7 +246,7 @@ netif_put(struct iodesc *desc, void *pkt, size_t len)
#endif
#ifdef PARANOID
if (drv->netif_put == NULL)
- panic("%s%d: no netif_put support\n", drv->netif_bname,
+ panic("%s%d: no netif_put support", drv->netif_bname,
nif->nif_unit);
#endif
rv = drv->netif_put(desc, pkt, len);
diff --git a/usr/src/boot/sys/boot/common/panic.c b/usr/src/boot/lib/libstand/panic.c
index 6e4c76d0e0..8a3730ce6b 100644
--- a/usr/src/boot/sys/boot/common/panic.c
+++ b/usr/src/boot/lib/libstand/panic.c
@@ -1,7 +1,7 @@
/*
* $NetBSD: panic.c,v 1.2 1997/03/22 01:48:36 thorpej Exp $
*/
-/*-
+/*
* Copyright (c) 1996
* Matthias Drochner. All rights reserved.
*
@@ -34,26 +34,32 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
#include <stand.h>
#include <machine/stdarg.h>
-extern void exit(int) __dead2;
+/*
+ * Boot loaders and other standalone programs that wish to have a
+ * different panic policy can provide their own panic_action rotuine.
+ */
+__weak_symbol void
+panic_action(void)
+{
+ printf("--> Press a key on the console to reboot <--\n");
+ getchar();
+ printf("Rebooting...\n");
+ exit(1);
+}
void
-panic(const char *fmt,...)
+panic(const char *fmt, ...)
{
- va_list ap;
+ va_list ap;
printf("panic: ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
-
- printf("--> Press a key on the console to reboot <--\n");
- getchar();
- printf("Rebooting...\n");
- exit(1);
+ panic_action();
}
diff --git a/usr/src/boot/lib/libstand/sbrk.c b/usr/src/boot/lib/libstand/sbrk.c
index 471e78ecf6..fb2dab1d44 100644
--- a/usr/src/boot/lib/libstand/sbrk.c
+++ b/usr/src/boot/lib/libstand/sbrk.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith
* All rights reserved.
*
@@ -25,7 +25,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
/*
* Minimal sbrk() emulation required for malloc support.
@@ -41,24 +40,26 @@ static void *heapbase;
void
setheap(void *base, void *top)
{
- /* Align start address for the malloc code. Sigh. */
- heapbase = (void *)(((uintptr_t)base + MALLOCALIGN_MASK) &
- ~MALLOCALIGN_MASK);
- maxheap = (char *)top - (char *)heapbase;
+ /* Align start address for the malloc code. Sigh. */
+ heapbase = (void *)(((uintptr_t)base + MALLOCALIGN_MASK) &
+ ~MALLOCALIGN_MASK);
+ maxheap = (char *)top - (char *)heapbase;
}
char *
sbrk(int incr)
{
- char *ret;
-
- if ((heapsize + incr) <= maxheap) {
- ret = (char *)heapbase + heapsize;
- bzero(ret, incr);
- heapsize += incr;
- return(ret);
- }
- errno = ENOMEM;
- return((char *)-1);
-}
+ char *ret;
+ if (heapbase == NULL)
+ panic("No heap setup");
+
+ if ((heapsize + incr) <= maxheap) {
+ ret = (char *)heapbase + heapsize;
+ bzero(ret, incr);
+ heapsize += incr;
+ return (ret);
+ }
+ errno = ENOMEM;
+ return ((char *)-1);
+}
diff --git a/usr/src/boot/lib/libstand/stand.h b/usr/src/boot/lib/libstand/stand.h
index 5039803d6d..1fa3055844 100644
--- a/usr/src/boot/lib/libstand/stand.h
+++ b/usr/src/boot/lib/libstand/stand.h
@@ -69,11 +69,14 @@
/* this header intentionally exports NULL from <string.h> */
#include <string.h>
-#define CHK(fmt, args...) printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args)
-#define PCHK(fmt, args...) {printf("%s(%d): " fmt "\n", __func__, __LINE__ , ##args); getchar();}
+#define CHK(fmt, args...) \
+ printf("%s(%d): " fmt "\n", __func__, __LINE__, ##args)
+#define PCHK(fmt, args...) {\
+ printf("%s(%d): " fmt "\n", __func__, __LINE__, ##args); getchar();\
+}
/* Avoid unwanted userlandish components */
-#define _KERNEL
+#define _KERNEL
#include <sys/errno.h>
#undef _KERNEL
@@ -81,7 +84,7 @@
#define EADAPT (ELAST+1) /* bad adaptor */
#define ECTLR (ELAST+2) /* bad controller */
#define EUNIT (ELAST+3) /* bad unit */
-#define ESLICE (ELAST+4) /* bad slice */
+#define ESLICE (ELAST+4) /* bad slice */
#define EPART (ELAST+5) /* bad partition */
#define ERDLAB (ELAST+6) /* can't read disk label */
#define EUNLAB (ELAST+7) /* unlabeled disk */
@@ -99,16 +102,16 @@ struct open_file;
* filesystems that they require.
*/
struct fs_ops {
- const char *fs_name;
- int (*fo_open)(const char *path, struct open_file *f);
- int (*fo_close)(struct open_file *f);
- int (*fo_read)(struct open_file *f, void *buf,
- size_t size, size_t *resid);
- int (*fo_write)(struct open_file *f, const void *buf,
- size_t size, size_t *resid);
- off_t (*fo_seek)(struct open_file *f, off_t offset, int where);
- int (*fo_stat)(struct open_file *f, struct stat *sb);
- int (*fo_readdir)(struct open_file *f, struct dirent *d);
+ const char *fs_name;
+ int (*fo_open)(const char *path, struct open_file *f);
+ int (*fo_close)(struct open_file *f);
+ int (*fo_read)(struct open_file *f, void *buf,
+ size_t size, size_t *resid);
+ int (*fo_write)(struct open_file *f, const void *buf,
+ size_t size, size_t *resid);
+ off_t (*fo_seek)(struct open_file *f, off_t offset, int where);
+ int (*fo_stat)(struct open_file *f, struct stat *sb);
+ int (*fo_readdir)(struct open_file *f, struct dirent *d);
};
/*
@@ -135,22 +138,22 @@ extern struct fs_ops pkgfs_fsops;
* Device switch
*/
struct devsw {
- const char dv_name[8];
- int dv_type; /* opaque type constant, arch-dependant */
+ const char dv_name[8];
+ int dv_type; /* opaque type constant, arch-dependant */
#define DEVT_NONE 0
#define DEVT_DISK 1
#define DEVT_NET 2
#define DEVT_CD 3
#define DEVT_ZFS 4
#define DEVT_FD 5
- int (*dv_init)(void); /* early probe call */
- int (*dv_strategy)(void *devdata, int rw, daddr_t blk,
+ int (*dv_init)(void); /* early probe call */
+ int (*dv_strategy)(void *devdata, int rw, daddr_t blk,
size_t size, char *buf, size_t *rsize);
- int (*dv_open)(struct open_file *f, ...);
- int (*dv_close)(struct open_file *f);
- int (*dv_ioctl)(struct open_file *f, u_long cmd, void *data);
- int (*dv_print)(int verbose); /* print device information */
- void (*dv_cleanup)(void);
+ int (*dv_open)(struct open_file *f, ...);
+ int (*dv_close)(struct open_file *f);
+ int (*dv_ioctl)(struct open_file *f, ulong_t cmd, void *data);
+ int (*dv_print)(int verbose); /* print device information */
+ void (*dv_cleanup)(void);
};
/*
@@ -166,22 +169,22 @@ extern int errno;
* overlap.
*/
struct devdesc {
- struct devsw *d_dev;
- int d_unit;
- void *d_opendata;
+ struct devsw *d_dev;
+ int d_unit;
+ void *d_opendata;
};
struct open_file {
- int f_flags; /* see F_* below */
- struct devsw *f_dev; /* pointer to device operations */
- void *f_devdata; /* device specific data */
- struct fs_ops *f_ops; /* pointer to file system operations */
- void *f_fsdata; /* file system specific data */
- off_t f_offset; /* current file offset */
- char *f_rabuf; /* readahead buffer pointer */
- size_t f_ralen; /* valid data in readahead buffer */
- off_t f_raoffset; /* consumer offset in readahead buffer */
-#define SOPEN_RASIZE 512
+ int f_flags; /* see F_* below */
+ struct devsw *f_dev; /* pointer to device operations */
+ void *f_devdata; /* device specific data */
+ struct fs_ops *f_ops; /* pointer to file system operations */
+ void *f_fsdata; /* file system specific data */
+ off_t f_offset; /* current file offset */
+ char *f_rabuf; /* readahead buffer pointer */
+ size_t f_ralen; /* valid data in readahead buffer */
+ off_t f_raoffset; /* consumer offset in readahead buffer */
+#define SOPEN_RASIZE 512
};
#define SOPEN_MAX 64
@@ -198,51 +201,51 @@ extern struct open_file files[];
/* Mode modifier for strategy() */
#define F_NORA (0x01 << 16) /* Disable Read-Ahead */
-#define isascii(c) (((c) & ~0x7F) == 0)
+#define isascii(c) (((c) & ~0x7F) == 0)
static __inline int isupper(int c)
{
- return c >= 'A' && c <= 'Z';
+ return (c >= 'A' && c <= 'Z');
}
static __inline int islower(int c)
{
- return c >= 'a' && c <= 'z';
+ return (c >= 'a' && c <= 'z');
}
static __inline int isspace(int c)
{
- return c == ' ' || (c >= 0x9 && c <= 0xd);
+ return (c == ' ' || (c >= 0x9 && c <= 0xd));
}
static __inline int isdigit(int c)
{
- return c >= '0' && c <= '9';
+ return (c >= '0' && c <= '9');
}
static __inline int isxdigit(int c)
{
- return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+ return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
static __inline int isalpha(int c)
{
- return isupper(c) || islower(c);
+ return (isupper(c) || islower(c));
}
static __inline int isalnum(int c)
{
- return isalpha(c) || isdigit(c);
+ return (isalpha(c) || isdigit(c));
}
static __inline int toupper(int c)
{
- return islower(c) ? c - 'a' + 'A' : c;
+ return (islower(c) ? c - 'a' + 'A' : c);
}
static __inline int tolower(int c)
{
- return isupper(c) ? c - 'A' + 'a' : c;
+ return (isupper(c) ? c - 'A' + 'a' : c);
}
/* sbrk emulation */
@@ -252,7 +255,6 @@ extern char *sbrk(int incr);
/* Matt Dillon's zalloc/zmalloc */
extern void *malloc(size_t bytes);
extern void free(void *ptr);
-/*#define free(p) {CHK("free %p", p); free(p);} */ /* use for catching guard violations */
extern void *calloc(size_t n1, size_t n2);
extern void *realloc(void *ptr, size_t size);
extern void *reallocf(void *ptr, size_t size);
@@ -262,34 +264,35 @@ extern int printf(const char *fmt, ...) __printflike(1, 2);
extern void vprintf(const char *fmt, __va_list);
extern int asprintf(char **buf, const char *cfmt, ...) __printflike(2, 3);
extern int sprintf(char *buf, const char *cfmt, ...) __printflike(2, 3);
-extern int snprintf(char *buf, size_t size, const char *cfmt, ...) __printflike(3, 4);
+extern int snprintf(char *buf, size_t size, const char *cfmt, ...) \
+ __printflike(3, 4);
extern void vsprintf(char *buf, const char *cfmt, __va_list);
extern void vsnprintf(char *buf, size_t size, const char *cfmt, __va_list);
-extern void twiddle(u_int callerdiv);
-extern void twiddle_divisor(u_int globaldiv);
+extern void twiddle(uint_t callerdiv);
+extern void twiddle_divisor(uint_t globaldiv);
extern void ngets(char *, int);
-#define gets(x) ngets((x), 0)
+#define gets(x) ngets((x), 0)
extern int fgetstr(char *buf, int size, int fd);
extern int open(const char *, int);
#define O_RDONLY 0x0
-#define O_WRONLY 0x1
-#define O_RDWR 0x2
+#define O_WRONLY 0x1
+#define O_RDWR 0x2
extern int close(int);
extern void closeall(void);
extern ssize_t read(int, void *, size_t);
extern ssize_t write(int, const void *, size_t);
extern struct dirent *readdirfd(int);
-extern void srandom(u_long seed);
-extern u_long random(void);
+extern void srandom(ulong_t seed);
+extern ulong_t random(void);
/* imports from stdlib, locally modified */
extern long strtol(const char *, char **, int);
extern unsigned long strtoul(const char *, char **, int);
-extern char *optarg; /* getopt(3) external variables */
+extern char *optarg; /* getopt(3) external variables */
extern int optind, opterr, optopt, optreset;
extern int getopt(int, char * const [], const char *);
@@ -300,13 +303,16 @@ extern int pager_output(const char *lines);
extern int pager_file(const char *fname);
/* No signal state to preserve */
-#define setjmp _setjmp
-#define longjmp _longjmp
+#define setjmp _setjmp
+#define longjmp _longjmp
/* environment.c */
-#define EV_DYNAMIC (1<<0) /* value was dynamically allocated, free if changed/unset */
-#define EV_VOLATILE (1<<1) /* value is volatile, make a copy of it */
-#define EV_NOHOOK (1<<2) /* don't call hook when setting */
+/* value was dynamically allocated, free if changed/unset */
+#define EV_DYNAMIC (1<<0)
+/* value is volatile, make a copy of it */
+#define EV_VOLATILE (1<<1)
+/* don't call hook when setting */
+#define EV_NOHOOK (1<<2)
struct env_var;
typedef char *(ev_format_t)(struct env_var *ev);
@@ -327,11 +333,11 @@ extern struct env_var *environ;
extern struct env_var *env_getenv(const char *name);
extern int env_setenv(const char *name, int flags,
- const void *value, ev_sethook_t sethook,
- ev_unsethook_t unsethook);
+ const void *value, ev_sethook_t sethook,
+ ev_unsethook_t unsethook);
extern char *getenv(const char *name);
extern int setenv(const char *name, const char *value,
- int overwrite);
+ int overwrite);
extern int putenv(const char *string);
extern int unsetenv(const char *name);
@@ -339,8 +345,8 @@ extern ev_sethook_t env_noset; /* refuse set operation */
extern ev_unsethook_t env_nounset; /* refuse unset operation */
/* BCD conversions (undocumented) */
-extern u_char const bcd2bin_data[];
-extern u_char const bin2bcd_data[];
+extern uchar_t const bcd2bin_data[];
+extern uchar_t const bin2bcd_data[];
extern char const hex2ascii_data[];
#define bcd2bin(bcd) (bcd2bin_data[bcd])
@@ -352,38 +358,40 @@ static __inline int imax(int a, int b) { return (a > b ? a : b); }
static __inline int imin(int a, int b) { return (a < b ? a : b); }
static __inline long lmax(long a, long b) { return (a > b ? a : b); }
static __inline long lmin(long a, long b) { return (a < b ? a : b); }
-static __inline u_int max(u_int a, u_int b) { return (a > b ? a : b); }
-static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); }
+static __inline uint_t max(uint_t a, uint_t b) { return (a > b ? a : b); }
+static __inline uint_t min(uint_t a, uint_t b) { return (a < b ? a : b); }
static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); }
static __inline quad_t qmin(quad_t a, quad_t b) { return (a < b ? a : b); }
-static __inline u_long ulmax(u_long a, u_long b) { return (a > b ? a : b); }
-static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); }
+static __inline ulong_t ulmax(ulong_t a, ulong_t b) { return (a > b ? a : b); }
+static __inline ulong_t ulmin(ulong_t a, ulong_t b) { return (a < b ? a : b); }
/* null functions for device/filesystem switches (undocumented) */
extern int nodev(void);
-extern int noioctl(struct open_file *, u_long, void *);
+extern int noioctl(struct open_file *, ulong_t, void *);
extern void nullsys(void);
-extern int null_open(const char *path, struct open_file *f);
-extern int null_close(struct open_file *f);
-extern int null_read(struct open_file *f, void *buf, size_t size, size_t *resid);
-extern int null_write(struct open_file *f, const void *buf, size_t size, size_t *resid);
-extern off_t null_seek(struct open_file *f, off_t offset, int where);
-extern int null_stat(struct open_file *f, struct stat *sb);
-extern int null_readdir(struct open_file *f, struct dirent *d);
+extern int null_open(const char *, struct open_file *);
+extern int null_close(struct open_file *);
+extern int null_read(struct open_file *, void *, size_t, size_t *);
+extern int null_write(struct open_file *, const void *, size_t, size_t *);
+extern off_t null_seek(struct open_file *, off_t, int);
+extern int null_stat(struct open_file *, struct stat *);
+extern int null_readdir(struct open_file *, struct dirent *);
/*
* Machine dependent functions and data, must be provided or stubbed by
* the consumer
*/
-extern int getchar(void);
-extern int ischar(void);
-extern void putchar(int);
-extern int devopen(struct open_file *, const char *, const char **);
-extern int devclose(struct open_file *f);
-extern void panic(const char *, ...) __dead2 __printflike(1, 2);
-extern time_t getsecs(void);
+extern void exit(int) __dead2;
+extern int getchar(void);
+extern int ischar(void);
+extern void putchar(int);
+extern int devopen(struct open_file *, const char *, const char **);
+extern int devclose(struct open_file *f);
+extern void panic(const char *, ...) __dead2 __printflike(1, 2);
+extern void panic_action(void) __weak_symbol __dead2;
+extern time_t getsecs(void);
extern struct fs_ops *file_system[];
extern struct fs_ops *exclusive_file_system;
extern struct devsw *devsw[];
@@ -413,15 +421,15 @@ void *Realloc(void *, size_t, const char *, int);
void Free(void *, const char *, int);
#if 1
-#define malloc(x) Malloc(x, __FILE__, __LINE__)
-#define calloc(x, y) Calloc(x, y, __FILE__, __LINE__)
-#define free(x) Free(x, __FILE__, __LINE__)
-#define realloc(x, y) Realloc(x, y, __FILE__, __LINE__)
+#define malloc(x) Malloc(x, __FILE__, __LINE__)
+#define calloc(x, y) Calloc(x, y, __FILE__, __LINE__)
+#define free(x) Free(x, __FILE__, __LINE__)
+#define realloc(x, y) Realloc(x, y, __FILE__, __LINE__)
#else
-#define malloc(x) Malloc(x, NULL, 0)
-#define calloc(x, y) Calloc(x, y, NULL, 0)
-#define free(x) Free(x, NULL, 0)
-#define realloc(x, y) Realloc(x, y, NULL, 0)
+#define malloc(x) Malloc(x, NULL, 0)
+#define calloc(x, y) Calloc(x, y, NULL, 0)
+#define free(x) Free(x, NULL, 0)
+#define realloc(x, y) Realloc(x, y, NULL, 0)
#endif
#endif /* STAND_H */
diff --git a/usr/src/boot/sys/boot/common/Makefile.inc b/usr/src/boot/sys/boot/common/Makefile.inc
index a02ef4732e..bbf81332d2 100644
--- a/usr/src/boot/sys/boot/common/Makefile.inc
+++ b/usr/src/boot/sys/boot/common/Makefile.inc
@@ -1,8 +1,8 @@
# $FreeBSD$
-SRCS+= boot.c commands.c console.c devopen.c interp.c
-SRCS+= interp_backslash.c interp_parse.c ls.c misc.c
-SRCS+= module.c panic.c
+SRCS+= boot.c commands.c console.c devopen.c interp.c
+SRCS+= interp_backslash.c interp_parse.c ls.c misc.c
+SRCS+= module.c
.if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64"
SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c
diff --git a/usr/src/boot/sys/boot/common/bootstrap.h b/usr/src/boot/sys/boot/common/bootstrap.h
index 0ffe65f725..b691df0ac3 100644
--- a/usr/src/boot/sys/boot/common/bootstrap.h
+++ b/usr/src/boot/sys/boot/common/bootstrap.h
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
* All rights reserved.
*
@@ -37,11 +37,11 @@ typedef int (bootblk_cmd_t)(int argc, char *argv[]);
#define COMMAND_ERRBUFSZ (256)
extern const char *command_errmsg;
extern char command_errbuf[COMMAND_ERRBUFSZ];
-#define CMD_OK 0
-#define CMD_WARN 1
-#define CMD_ERROR 2
-#define CMD_CRIT 3
-#define CMD_FATAL 4
+#define CMD_OK 0
+#define CMD_WARN 1
+#define CMD_ERROR 2
+#define CMD_CRIT 3
+#define CMD_FATAL 4
/* interp.c */
void interact(const char *rc);
@@ -84,10 +84,10 @@ int bcache_strategy(void *devdata, int rw, daddr_t blk,
*/
struct bcache_devdata
{
- int (*dv_strategy)(void *devdata, int rw, daddr_t blk,
- size_t size, char *buf, size_t *rsize);
- void *dv_devdata;
- void *dv_cache;
+ int (*dv_strategy)(void *devdata, int rw, daddr_t blk,
+ size_t size, char *buf, size_t *rsize);
+ void *dv_devdata;
+ void *dv_cache;
};
/*
@@ -95,64 +95,78 @@ struct bcache_devdata
*/
struct console
{
- const char *c_name;
- const char *c_desc;
- int c_flags;
-#define C_PRESENTIN (1<<0) /* console can provide input */
-#define C_PRESENTOUT (1<<1) /* console can provide output */
-#define C_ACTIVEIN (1<<2) /* user wants input from console */
-#define C_ACTIVEOUT (1<<3) /* user wants output to console */
-#define C_WIDEOUT (1<<4) /* c_out routine groks wide chars */
-#define C_MODERAW (1<<5) /* raw mode */
- void (*c_probe)(struct console *); /* set c_flags to match hardware */
- int (*c_init)(struct console *, int); /* reinit XXX may need more args */
- void (*c_out)(struct console *, int); /* emit c */
- int (*c_in)(struct console *); /* wait for and return input */
- int (*c_ready)(struct console *); /* return nonzer if input waiting */
- int (*c_ioctl)(struct console *, int, void *);
- void *c_private; /* private data */
+ const char *c_name;
+ const char *c_desc;
+ int c_flags;
+#define C_PRESENTIN (1<<0) /* console can provide input */
+#define C_PRESENTOUT (1<<1) /* console can provide output */
+#define C_ACTIVEIN (1<<2) /* user wants input from console */
+#define C_ACTIVEOUT (1<<3) /* user wants output to console */
+#define C_WIDEOUT (1<<4) /* c_out routine groks wide chars */
+#define C_MODERAW (1<<5) /* raw mode */
+
+ /* set c_flags to match hardware */
+ void (*c_probe)(struct console *);
+ /* reinit XXX may need more args */
+ int (*c_init)(struct console *, int);
+ /* emit c */
+ void (*c_out)(struct console *, int);
+ /* wait for and return input */
+ int (*c_in)(struct console *);
+ /* return nonzero if input is waiting */
+ int (*c_ready)(struct console *);
+ int (*c_ioctl)(struct console *, int, void *);
+ void *c_private; /* private data */
};
extern struct console *consoles[];
-void cons_probe(void);
-void cons_mode(int);
-void autoload_font(void);
+void cons_probe(void);
+void cons_mode(int);
+void autoload_font(void);
/*
* Plug-and-play enumerator/configurator interface.
*/
struct pnphandler
{
- const char *pp_name; /* handler/bus name */
- void (* pp_enumerate)(void); /* enumerate PnP devices, add to chain */
+ const char *pp_name; /* handler/bus name */
+ /* enumerate PnP devices, add to chain */
+ void (*pp_enumerate)(void);
};
struct pnpident
{
- char *id_ident; /* ASCII identifier, actual format varies with bus/handler */
- STAILQ_ENTRY(pnpident) id_link;
+ /* ASCII identifier, actual format varies with bus/handler */
+ char *id_ident;
+ STAILQ_ENTRY(pnpident) id_link;
};
struct pnpinfo
{
- char *pi_desc; /* ASCII description, optional */
- int pi_revision; /* optional revision (or -1) if not supported */
- char *pi_module; /* module/args nominated to handle device */
- int pi_argc; /* module arguments */
- char **pi_argv;
- struct pnphandler *pi_handler; /* handler which detected this device */
- STAILQ_HEAD(,pnpident) pi_ident; /* list of identifiers */
- STAILQ_ENTRY(pnpinfo) pi_link;
+ /* ASCII description, optional */
+ char *pi_desc;
+ /* optional revision (or -1) if not supported */
+ int pi_revision;
+ /* module/args nominated to handle device */
+ char *pi_module;
+ /* module arguments */
+ int pi_argc;
+ char **pi_argv;
+ /* handler which detected this device */
+ struct pnphandler *pi_handler;
+ /* list of identifiers */
+ STAILQ_HEAD(, pnpident) pi_ident;
+ STAILQ_ENTRY(pnpinfo) pi_link;
};
STAILQ_HEAD(pnpinfo_stql, pnpinfo);
-extern struct pnphandler *pnphandlers[]; /* provided by MD code */
+extern struct pnphandler *pnphandlers[]; /* provided by MD code */
void pnp_addident(struct pnpinfo *pi, char *ident);
struct pnpinfo *pnp_allocinfo(void);
void pnp_freeinfo(struct pnpinfo *pi);
void pnp_addinfo(struct pnpinfo *pi);
-char *pnp_eisaformat(u_int8_t *data);
+char *pnp_eisaformat(uint8_t *data);
/*
* < 0 - No ISA in system
@@ -174,10 +188,11 @@ extern char bootprog_info[];
*/
struct file_metadata
{
- size_t md_size;
- u_int16_t md_type;
- struct file_metadata *md_next;
- char md_data[1]; /* data are immediately appended */
+ size_t md_size;
+ uint16_t md_type;
+ struct file_metadata *md_next;
+ /* data are immediately appended */
+ char md_data[1];
};
struct preloaded_file;
@@ -185,11 +200,11 @@ struct mod_depend;
struct kernel_module
{
- char *m_name; /* module name */
- int m_version; /* module version */
- char *m_args; /* arguments for the module */
- struct preloaded_file *m_fp;
- struct kernel_module *m_next;
+ char *m_name; /* module name */
+ int m_version; /* module version */
+ char *m_args; /* arguments for the module */
+ struct preloaded_file *m_fp;
+ struct kernel_module *m_next;
};
/*
@@ -203,31 +218,40 @@ struct kernel_module
*/
struct preloaded_file
{
- char *f_name; /* file name */
- char *f_type; /* verbose file type, eg 'ELF kernel', 'pnptable', etc. */
- char *f_args; /* arguments for the file */
- struct file_metadata *f_metadata; /* metadata that will be placed in the module directory */
- int f_loader; /* index of the loader that read the file */
- vm_offset_t f_addr; /* load address */
- size_t f_size; /* file size */
- struct kernel_module *f_modules; /* list of modules if any */
- struct preloaded_file *f_next; /* next file */
+ char *f_name; /* file name */
+ /* verbose file type, eg 'ELF kernel', 'pnptable', etc. */
+ char *f_type;
+ char *f_args; /* arguments for the file */
+ /* metadata that will be placed in the module directory */
+ struct file_metadata *f_metadata;
+ /* index of the loader that read the file */
+ int f_loader;
+ vm_offset_t f_addr; /* load address */
+ size_t f_size; /* file size */
+ struct kernel_module *f_modules; /* list of modules if any */
+ struct preloaded_file *f_next; /* next file */
};
struct file_format
{
- /* Load function must return EFTYPE if it can't handle the module supplied */
- int (* l_load)(char *filename, u_int64_t dest, struct preloaded_file **result);
- /* Only a loader that will load a kernel (first module) should have an exec handler */
- int (* l_exec)(struct preloaded_file *mp);
+ /*
+ * Load function must return EFTYPE if it can't handle the module
+ * supplied.
+ */
+ int (*l_load)(char *, uint64_t, struct preloaded_file **);
+ /*
+ * Only a loader that will load a kernel (first module)
+ * should have an exec handler.
+ */
+ int (*l_exec)(struct preloaded_file *);
};
-extern struct file_format *file_formats[]; /* supplied by consumer */
-extern struct preloaded_file *preloaded_files;
+extern struct file_format *file_formats[]; /* supplied by consumer */
+extern struct preloaded_file *preloaded_files;
-int mod_load(char *name, struct mod_depend *verinfo, int argc, char *argv[]);
-int mod_loadkld(const char *name, int argc, char *argv[]);
-void unload(void);
+int mod_load(char *name, struct mod_depend *verinfo, int argc, char *argv[]);
+int mod_loadkld(const char *name, int argc, char *argv[]);
+void unload(void);
struct preloaded_file *file_alloc(void);
struct preloaded_file *file_findfile(const char *name, const char *type);
@@ -235,9 +259,9 @@ struct file_metadata *file_findmetadata(struct preloaded_file *fp, int type);
struct preloaded_file *file_loadraw(const char *name, char *type, int argc,
char **argv, int insert);
void file_discard(struct preloaded_file *fp);
-void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p);
-int file_addmodule(struct preloaded_file *fp, char *modname, int version,
- struct kernel_module **newmp);
+void file_addmetadata(struct preloaded_file *, int, size_t, void *);
+int file_addmodule(struct preloaded_file *, char *, int,
+ struct kernel_module **);
void build_environment_module(void);
void build_font_module(void);
vm_offset_t bi_copyenv(vm_offset_t);
@@ -246,14 +270,14 @@ bool sha1(void *, size_t, uint8_t *);
/* MI module loaders */
#ifdef __elfN
/* Relocation types. */
-#define ELF_RELOC_REL 1
-#define ELF_RELOC_RELA 2
+#define ELF_RELOC_REL 1
+#define ELF_RELOC_RELA 2
/* Relocation offset for some architectures */
-extern u_int64_t __elfN(relocation_offset);
+extern uint64_t __elfN(relocation_offset);
struct elf_file;
-typedef Elf_Addr (symaddr_fn)(struct elf_file *ef, Elf_Size symidx);
+typedef Elf_Addr (symaddr_fn)(struct elf_file *, Elf_Size);
int elf64_loadfile(char *, uint64_t, struct preloaded_file **);
int elf32_loadfile(char *, uint64_t, struct preloaded_file **);
@@ -273,12 +297,12 @@ int elf32_load_modmetadata(struct preloaded_file *, uint64_t);
*/
struct bootblk_command
{
- const char *c_name;
- const char *c_desc;
- bootblk_cmd_t *c_fn;
+ const char *c_name;
+ const char *c_desc;
+ bootblk_cmd_t *c_fn;
};
-#define COMMAND_SET(tag, key, desc, func) \
+#define COMMAND_SET(tag, key, desc, func) \
static bootblk_cmd_t func; \
static struct bootblk_command _cmd_ ## tag = { key, desc, func }; \
DATA_SET(Xcommand_set, _cmd_ ## tag)
@@ -293,49 +317,55 @@ SET_DECLARE(Xcommand_set, struct bootblk_command);
*/
struct arch_switch
{
- /* Automatically load modules as required by detected hardware */
- int (*arch_autoload)(void);
- /* Locate the device for (name), return pointer to tail in (*path) */
- int (*arch_getdev)(void **dev, const char *name, const char **path);
- /* Copy from local address space to module address space, similar to bcopy() */
- ssize_t (*arch_copyin)(const void *src, vm_offset_t dest,
- const size_t len);
- /* Copy to local address space from module address space, similar to bcopy() */
- ssize_t (*arch_copyout)(const vm_offset_t src, void *dest,
+ /* Automatically load modules as required by detected hardware */
+ int (*arch_autoload)(void);
+ /* Locate the device for (name), return pointer to tail in (*path) */
+ int (*arch_getdev)(void **dev, const char *name, const char **path);
+ /*
+ * Copy from local address space to module address space,
+ * similar to bcopy()
+ */
+ ssize_t (*arch_copyin)(const void *src, vm_offset_t dest,
+ const size_t len);
+ /*
+ * Copy to local address space from module address space,
+ * similar to bcopy()
+ */
+ ssize_t (*arch_copyout)(const vm_offset_t src, void *dest,
const size_t len);
- /* Read from file to module address space, same semantics as read() */
- ssize_t (*arch_readin)(const int fd, vm_offset_t dest,
- const size_t len);
- /* Perform ISA byte port I/O (only for systems with ISA) */
- int (*arch_isainb)(int port);
- void (*arch_isaoutb)(int port, int value);
-
- /*
- * Interface to adjust the load address according to the "object"
- * being loaded.
- */
- vm_offset_t (*arch_loadaddr)(u_int type, void *data, vm_offset_t addr);
+ /* Read from file to module address space, same semantics as read() */
+ ssize_t (*arch_readin)(const int fd, vm_offset_t dest,
+ const size_t len);
+ /* Perform ISA byte port I/O (only for systems with ISA) */
+ int (*arch_isainb)(int port);
+ void (*arch_isaoutb)(int port, int value);
+
+ /*
+ * Interface to adjust the load address according to the "object"
+ * being loaded.
+ */
+ vm_offset_t (*arch_loadaddr)(uint_t type, void *data, vm_offset_t addr);
#define LOAD_ELF 1 /* data points to the ELF header. */
#define LOAD_RAW 2 /* data points to the module file name. */
#define LOAD_KERN 3 /* data points to the kernel file name. */
#define LOAD_MEM 4 /* data points to int for buffer size. */
- /*
- * Interface to release the load address.
- */
- void (*arch_free_loadaddr)(vm_offset_t addr, size_t pages);
-
- /*
- * Interface to inform MD code about a loaded (ELF) segment. This
- * can be used to flush caches and/or set up translations.
- */
+ /*
+ * Interface to release the load address.
+ */
+ void (*arch_free_loadaddr)(vm_offset_t addr, size_t pages);
+
+ /*
+ * Interface to inform MD code about a loaded (ELF) segment. This
+ * can be used to flush caches and/or set up translations.
+ */
#ifdef __elfN
- void (*arch_loadseg)(Elf_Ehdr *eh, Elf_Phdr *ph, uint64_t delta);
+ void (*arch_loadseg)(Elf_Ehdr *eh, Elf_Phdr *ph, uint64_t delta);
#else
- void (*arch_loadseg)(void *eh, void *ph, uint64_t delta);
+ void (*arch_loadseg)(void *eh, void *ph, uint64_t delta);
#endif
- /* Probe ZFS pool(s), if needed. */
- void (*arch_zfs_probe)(void);
+ /* Probe ZFS pool(s), if needed. */
+ void (*arch_zfs_probe)(void);
};
extern struct arch_switch archsw;
@@ -344,10 +374,10 @@ void delay(int delay);
void dev_cleanup(void);
-#ifndef CTASSERT /* Allow lint to override */
-#define CTASSERT(x) _CTASSERT(x, __LINE__)
-#define _CTASSERT(x, y) __CTASSERT(x, y)
-#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]
+#ifndef CTASSERT /* Allow lint to override */
+#define CTASSERT(x) _CTASSERT(x, __LINE__)
+#define _CTASSERT(x, y) __CTASSERT(x, y)
+#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]
#endif
#endif /* !_BOOTSTRAP_H_ */
diff --git a/usr/src/boot/sys/boot/common/console.c b/usr/src/boot/sys/boot/common/console.c
index 0530a2993e..1bcc6074a7 100644
--- a/usr/src/boot/sys/boot/common/console.c
+++ b/usr/src/boot/sys/boot/common/console.c
@@ -50,67 +50,68 @@ static int twiddle_set(struct env_var *ev, int flags, const void *value);
void
cons_probe(void)
{
- int cons;
- int active;
- char *prefconsole;
-
- /* We want a callback to install the new value when this var changes. */
- env_setenv("twiddle_divisor", EV_VOLATILE, "1", twiddle_set, env_nounset);
-
- /* Do all console probes */
- for (cons = 0; consoles[cons] != NULL; cons++) {
- consoles[cons]->c_flags = 0;
- consoles[cons]->c_probe(consoles[cons]);
- }
- /* Now find the first working one */
- active = -1;
- for (cons = 0; consoles[cons] != NULL && active == -1; cons++) {
- consoles[cons]->c_flags = 0;
- consoles[cons]->c_probe(consoles[cons]);
- if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT))
- active = cons;
- }
- /* Force a console even if all probes failed */
- if (active == -1)
- active = 0;
+ int cons;
+ int active;
+ char *prefconsole;
- /* Check to see if a console preference has already been registered */
- prefconsole = getenv("console");
- if (prefconsole != NULL)
- prefconsole = strdup(prefconsole);
- if (prefconsole != NULL) {
- unsetenv("console"); /* we want to replace this */
- cons_change(prefconsole);
- } else {
- consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
- consoles[active]->c_init(consoles[active], 0);
- prefconsole = strdup(consoles[active]->c_name);
- }
-
- printf("Consoles: ");
- for (cons = 0; consoles[cons] != NULL; cons++)
- if (consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT))
- printf("%s ", consoles[cons]->c_desc);
- printf("\n");
-
- if (prefconsole != NULL) {
- env_setenv("console", EV_VOLATILE, prefconsole, cons_set,
+ /* We want a callback to install the new value when this var changes. */
+ env_setenv("twiddle_divisor", EV_VOLATILE, "1", twiddle_set,
env_nounset);
- free(prefconsole);
- }
+
+ /* Do all console probes */
+ for (cons = 0; consoles[cons] != NULL; cons++) {
+ consoles[cons]->c_flags = 0;
+ consoles[cons]->c_probe(consoles[cons]);
+ }
+ /* Now find the first working one */
+ active = -1;
+ for (cons = 0; consoles[cons] != NULL && active == -1; cons++) {
+ consoles[cons]->c_flags = 0;
+ consoles[cons]->c_probe(consoles[cons]);
+ if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT))
+ active = cons;
+ }
+ /* Force a console even if all probes failed */
+ if (active == -1)
+ active = 0;
+
+ /* Check to see if a console preference has already been registered */
+ prefconsole = getenv("console");
+ if (prefconsole != NULL)
+ prefconsole = strdup(prefconsole);
+ if (prefconsole != NULL) {
+ unsetenv("console"); /* we want to replace this */
+ cons_change(prefconsole);
+ } else {
+ consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
+ consoles[active]->c_init(consoles[active], 0);
+ prefconsole = strdup(consoles[active]->c_name);
+ }
+
+ printf("Consoles: ");
+ for (cons = 0; consoles[cons] != NULL; cons++)
+ if (consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT))
+ printf("%s ", consoles[cons]->c_desc);
+ printf("\n");
+
+ if (prefconsole != NULL) {
+ env_setenv("console", EV_VOLATILE, prefconsole, cons_set,
+ env_nounset);
+ free(prefconsole);
+ }
}
void
cons_mode(int raw)
{
- int cons;
-
- for (cons = 0; consoles[cons] != NULL; cons++) {
- if (raw == 0)
- consoles[cons]->c_flags &= ~C_MODERAW;
- else
- consoles[cons]->c_flags |= C_MODERAW;
- }
+ int cons;
+
+ for (cons = 0; consoles[cons] != NULL; cons++) {
+ if (raw == 0)
+ consoles[cons]->c_flags &= ~C_MODERAW;
+ else
+ consoles[cons]->c_flags |= C_MODERAW;
+ }
}
int
@@ -125,11 +126,11 @@ getchar(void)
* this code expects all ->c_in() implementations to effectively do an
* ischar() check first, returning -1 if there's not a char ready.
*/
- for(;;) {
+ for (;;) {
for (cons = 0; consoles[cons] != NULL; cons++) {
if ((consoles[cons]->c_flags & flags) == flags &&
((rv = consoles[cons]->c_in(consoles[cons])) != -1))
- return(rv);
+ return (rv);
}
delay(30 * 1000); /* delay 30ms */
}
@@ -138,29 +139,30 @@ getchar(void)
int
ischar(void)
{
- int cons;
-
- for (cons = 0; consoles[cons] != NULL; cons++)
- if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) ==
- (C_PRESENTIN | C_ACTIVEIN) &&
- (consoles[cons]->c_ready(consoles[cons]) != 0))
- return(1);
- return(0);
+ int cons;
+
+ for (cons = 0; consoles[cons] != NULL; cons++)
+ if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) ==
+ (C_PRESENTIN | C_ACTIVEIN) &&
+ (consoles[cons]->c_ready(consoles[cons]) != 0))
+ return (1);
+ return (0);
}
void
putchar(int c)
{
- int cons;
-
- /* Expand newlines if not in raw mode */
- for (cons = 0; consoles[cons] != NULL; cons++)
- if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) ==
- (C_PRESENTOUT | C_ACTIVEOUT)) {
- if (c == '\n' && (consoles[cons]->c_flags & C_MODERAW) == 0)
- consoles[cons]->c_out(consoles[cons], '\r');
- consoles[cons]->c_out(consoles[cons], c);
- }
+ int cons;
+
+ /* Expand newlines if not in raw mode */
+ for (cons = 0; consoles[cons] != NULL; cons++)
+ if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) ==
+ (C_PRESENTOUT | C_ACTIVEOUT)) {
+ if (c == '\n' &&
+ (consoles[cons]->c_flags & C_MODERAW) == 0)
+ consoles[cons]->c_out(consoles[cons], '\r');
+ consoles[cons]->c_out(consoles[cons], c);
+ }
}
/*
@@ -169,12 +171,12 @@ putchar(int c)
static int
cons_find(const char *name)
{
- int cons;
+ int cons;
- for (cons = 0; consoles[cons] != NULL; cons++)
- if (!strcmp(consoles[cons]->c_name, name))
- return (cons);
- return (-1);
+ for (cons = 0; consoles[cons] != NULL; cons++)
+ if (strcmp(consoles[cons]->c_name, name) == 0)
+ return (cons);
+ return (-1);
}
/*
@@ -183,22 +185,23 @@ cons_find(const char *name)
static int
cons_set(struct env_var *ev, int flags, const void *value)
{
- int ret;
-
- if ((value == NULL) || (cons_check(value) == 0)) {
- /*
- * Return CMD_OK instead of CMD_ERROR to prevent forth syntax error,
- * which would prevent it processing any further loader.conf entries.
- */
- return (CMD_OK);
- }
+ int ret;
+
+ if ((value == NULL) || (cons_check(value) == 0)) {
+ /*
+ * Return CMD_OK instead of CMD_ERROR to prevent forth syntax
+ * error, which would prevent it processing any further
+ * loader.conf entries.
+ */
+ return (CMD_OK);
+ }
- ret = cons_change(value);
- if (ret != CMD_OK)
- return (ret);
+ ret = cons_change(value);
+ if (ret != CMD_OK)
+ return (ret);
- env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
- return (CMD_OK);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ return (CMD_OK);
}
/*
@@ -207,36 +210,36 @@ cons_set(struct env_var *ev, int flags, const void *value)
static int
cons_check(const char *string)
{
- int cons, found, failed;
- char *curpos, *dup, *next;
-
- dup = next = strdup(string);
- found = failed = 0;
- while (next != NULL) {
- curpos = strsep(&next, " ,");
- if (*curpos != '\0') {
- cons = cons_find(curpos);
- if (cons == -1) {
- printf("console %s is invalid!\n", curpos);
- failed++;
- } else {
- found++;
- }
+ int cons, found, failed;
+ char *curpos, *dup, *next;
+
+ dup = next = strdup(string);
+ found = failed = 0;
+ while (next != NULL) {
+ curpos = strsep(&next, " ,");
+ if (*curpos != '\0') {
+ cons = cons_find(curpos);
+ if (cons == -1) {
+ printf("console %s is invalid!\n", curpos);
+ failed++;
+ } else {
+ found++;
+ }
+ }
}
- }
- free(dup);
+ free(dup);
- if (found == 0)
- printf("no valid consoles!\n");
+ if (found == 0)
+ printf("no valid consoles!\n");
- if (found == 0 || failed != 0) {
- printf("Available consoles:\n");
- for (cons = 0; consoles[cons] != NULL; cons++)
- printf(" %s\n", consoles[cons]->c_name);
- }
+ if (found == 0 || failed != 0) {
+ printf("Available consoles:\n");
+ for (cons = 0; consoles[cons] != NULL; cons++)
+ printf(" %s\n", consoles[cons]->c_name);
+ }
- return (found);
+ return (found);
}
/*
@@ -245,51 +248,63 @@ cons_check(const char *string)
static int
cons_change(const char *string)
{
- int cons, active;
- char *curpos, *dup, *next;
-
- /* Disable all consoles */
- for (cons = 0; consoles[cons] != NULL; cons++) {
- consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
- }
-
- /* Enable selected consoles */
- dup = next = strdup(string);
- active = 0;
- while (next != NULL) {
- curpos = strsep(&next, " ,");
- if (*curpos == '\0')
- continue;
- cons = cons_find(curpos);
- if (cons >= 0) {
- consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
- consoles[cons]->c_init(consoles[cons], 0);
- if ((consoles[cons]->c_flags & (C_PRESENTIN | C_PRESENTOUT)) ==
- (C_PRESENTIN | C_PRESENTOUT)) {
- active++;
- continue;
- }
+ int cons, active;
+ char *curpos, *dup, *next;
+
+ /* Disable all consoles */
+ for (cons = 0; consoles[cons] != NULL; cons++) {
+ consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
}
- }
- free(dup);
+ /* Enable selected consoles */
+ dup = next = strdup(string);
+ active = 0;
+ while (next != NULL) {
+ curpos = strsep(&next, " ,");
+ if (*curpos == '\0')
+ continue;
+ cons = cons_find(curpos);
+ if (cons >= 0) {
+ consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
+ consoles[cons]->c_init(consoles[cons], 0);
+ if ((consoles[cons]->c_flags &
+ (C_PRESENTIN | C_PRESENTOUT)) ==
+ (C_PRESENTIN | C_PRESENTOUT)) {
+ active++;
+ continue;
+ }
+
+ if (active != 0) {
+ /*
+ * If no consoles have initialised we wouldn't
+ * see this.
+ */
+ printf("console %s failed to initialize\n",
+ consoles[cons]->c_name);
+ }
+ }
+ }
- if (active == 0) {
- /* All requested consoles failed to initialise, try to recover. */
- for (cons = 0; consoles[cons] != NULL; cons++) {
- consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
- consoles[cons]->c_init(consoles[cons], 0);
- if ((consoles[cons]->c_flags &
- (C_PRESENTIN | C_PRESENTOUT)) ==
- (C_PRESENTIN | C_PRESENTOUT))
- active++;
+ free(dup);
+
+ if (active == 0) {
+ /*
+ * All requested consoles failed to initialise, try to recover.
+ */
+ for (cons = 0; consoles[cons] != NULL; cons++) {
+ consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
+ consoles[cons]->c_init(consoles[cons], 0);
+ if ((consoles[cons]->c_flags &
+ (C_PRESENTIN | C_PRESENTOUT)) ==
+ (C_PRESENTIN | C_PRESENTOUT))
+ active++;
}
if (active == 0)
- return (CMD_ERROR); /* Recovery failed. */
- }
+ return (CMD_ERROR); /* Recovery failed. */
+ }
- return (CMD_OK);
+ return (CMD_OK);
}
/*
@@ -303,16 +318,16 @@ cons_change(const char *string)
static int
twiddle_set(struct env_var *ev, int flags, const void *value)
{
- u_long tdiv;
- char * eptr;
-
- tdiv = strtoul(value, &eptr, 0);
- if (*(const char *)value == 0 || *eptr != 0) {
- printf("invalid twiddle_divisor '%s'\n", (const char *)value);
- return (CMD_ERROR);
- }
- twiddle_divisor((u_int)tdiv);
- env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
-
- return(CMD_OK);
+ ulong_t tdiv;
+ char *eptr;
+
+ tdiv = strtoul(value, &eptr, 0);
+ if (*(const char *)value == 0 || *eptr != 0) {
+ printf("invalid twiddle_divisor '%s'\n", (const char *)value);
+ return (CMD_ERROR);
+ }
+ twiddle_divisor((uint_t)tdiv);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+
+ return (CMD_OK);
}
diff --git a/usr/src/boot/sys/boot/common/interp_forth.c b/usr/src/boot/sys/boot/common/interp_forth.c
index b3eebaede4..0151c52b49 100644
--- a/usr/src/boot/sys/boot/common/interp_forth.c
+++ b/usr/src/boot/sys/boot/common/interp_forth.c
@@ -37,9 +37,9 @@ extern unsigned bootprog_rev;
/* #define BFORTH_DEBUG */
#ifdef BFORTH_DEBUG
-# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
+#define DEBUG(fmt, args...) printf("%s: " fmt "\n", __func__, ## args)
#else
-# define DEBUG(fmt, args...)
+#define DEBUG(fmt, args...)
#endif
/*
@@ -47,7 +47,7 @@ extern unsigned bootprog_rev;
* elsewhere, possibly bootstrap.h. For now, just this code, used
* just in this file, it is getting defined.
*/
-#define BF_PARSE 100
+#define BF_PARSE 100
/*
* FreeBSD loader default dictionary cells
@@ -71,94 +71,100 @@ ficlVm *bf_vm;
static void
bf_command(ficlVm *vm)
{
- char *name, *line, *tail, *cp;
- size_t len;
- struct bootblk_command **cmdp;
- bootblk_cmd_t *cmd;
- int nstrings, i;
- int argc, result;
- char **argv;
-
- /* Get the name of the current word */
- name = vm->runningWord->name;
-
- /* Find our command structure */
- cmd = NULL;
- SET_FOREACH(cmdp, Xcommand_set) {
- if (((*cmdp)->c_name != NULL) && !strcmp(name, (*cmdp)->c_name))
- cmd = (*cmdp)->c_fn;
- }
- if (cmd == NULL)
- panic("callout for unknown command '%s'", name);
-
- /* Check whether we have been compiled or are being interpreted */
- if (ficlStackPopInteger(ficlVmGetDataStack(vm))) {
+ char *name, *line, *tail, *cp;
+ size_t len;
+ struct bootblk_command **cmdp;
+ bootblk_cmd_t *cmd;
+ int nstrings, i;
+ int argc, result;
+ char **argv;
+
+ /* Get the name of the current word */
+ name = vm->runningWord->name;
+
+ /* Find our command structure */
+ cmd = NULL;
+ SET_FOREACH(cmdp, Xcommand_set) {
+ if (((*cmdp)->c_name != NULL) &&
+ strcmp(name, (*cmdp)->c_name) == 0)
+ cmd = (*cmdp)->c_fn;
+ }
+ if (cmd == NULL)
+ panic("callout for unknown command '%s'", name);
+
+ /* Check whether we have been compiled or are being interpreted */
+ if (ficlStackPopInteger(ficlVmGetDataStack(vm))) {
+ /*
+ * Get parameters from stack, in the format:
+ * an un ... a2 u2 a1 u1 n --
+ * Where n is the number of strings, a/u are pairs of
+ * address/size for strings, and they will be concatenated
+ * in LIFO order.
+ */
+ nstrings = ficlStackPopInteger(ficlVmGetDataStack(vm));
+ for (i = 0, len = 0; i < nstrings; i++) {
+ ficlStack *stack = ficlVmGetDataStack(vm);
+ len += ficlStackFetch(stack, i * 2).i + 1;
+ }
+ line = malloc(strlen(name) + len + 1);
+ strcpy(line, name);
+
+ if (nstrings)
+ for (i = 0; i < nstrings; i++) {
+ ficlStack *stack = ficlVmGetDataStack(vm);
+
+ len = ficlStackPopInteger(stack);
+ cp = ficlStackPopPointer(stack);
+ strcat(line, " ");
+ strncat(line, cp, len);
+ }
+ } else {
+ /* Get remainder of invocation */
+ tail = ficlVmGetInBuf(vm);
+
+ len = 0;
+ cp = tail;
+ for (; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++)
+ len++;
+
+ line = malloc(strlen(name) + len + 2);
+ strcpy(line, name);
+ if (len > 0) {
+ strcat(line, " ");
+ strncat(line, tail, len);
+ ficlVmUpdateTib(vm, tail + len);
+ }
+ }
+ DEBUG("cmd '%s'", line);
+
+ command_errmsg = command_errbuf;
+ command_errbuf[0] = 0;
+ if (!parse(&argc, &argv, line)) {
+ result = (cmd)(argc, argv);
+ free(argv);
+ } else {
+ result = BF_PARSE;
+ }
+
+ switch (result) {
+ case CMD_CRIT:
+ printf("%s\n", command_errmsg);
+ command_errmsg = NULL;
+ break;
+ case CMD_FATAL:
+ panic("%s", command_errmsg);
+ }
+
+ free(line);
/*
- * Get parameters from stack, in the format:
- * an un ... a2 u2 a1 u1 n --
- * Where n is the number of strings, a/u are pairs of
- * address/size for strings, and they will be concatenated
- * in LIFO order.
+ * If there was error during nested ficlExec(), we may no longer have
+ * valid environment to return. Throw all exceptions from here.
*/
- nstrings = ficlStackPopInteger(ficlVmGetDataStack(vm));
- for (i = 0, len = 0; i < nstrings; i++)
- len += ficlStackFetch(ficlVmGetDataStack(vm), i * 2).i + 1;
- line = malloc(strlen(name) + len + 1);
- strcpy(line, name);
-
- if (nstrings)
- for (i = 0; i < nstrings; i++) {
- len = ficlStackPopInteger(ficlVmGetDataStack(vm));
- cp = ficlStackPopPointer(ficlVmGetDataStack(vm));
- strcat(line, " ");
- strncat(line, cp, len);
- }
- } else {
- /* Get remainder of invocation */
- tail = ficlVmGetInBuf(vm);
-
- len = 0;
- for (cp = tail; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++)
- len++;
-
- line = malloc(strlen(name) + len + 2);
- strcpy(line, name);
- if (len > 0) {
- strcat(line, " ");
- strncat(line, tail, len);
- ficlVmUpdateTib(vm, tail + len);
- }
- }
- DEBUG("cmd '%s'", line);
-
- command_errmsg = command_errbuf;
- command_errbuf[0] = 0;
- if (!parse(&argc, &argv, line)) {
- result = (cmd)(argc, argv);
- free(argv);
- } else {
- result = BF_PARSE;
- }
-
- switch (result) {
- case CMD_CRIT:
- printf("%s\n", command_errmsg);
- command_errmsg = NULL;
- break;
- case CMD_FATAL:
- panic("%s\n", command_errmsg);
- }
-
- free(line);
- /*
- * If there was error during nested ficlExec(), we may no longer have
- * valid environment to return. Throw all exceptions from here.
- */
- if (result != CMD_OK)
- ficlVmThrow(vm, result);
-
- /* This is going to be thrown!!! */
- ficlStackPushInteger(ficlVmGetDataStack(vm),result);
+ if (result != CMD_OK)
+ ficlVmThrow(vm, result);
+
+ /* This is going to be thrown!!! */
+ ficlStackPushInteger(ficlVmGetDataStack(vm), result);
}
/*
@@ -229,25 +235,25 @@ bf_command(ficlVm *vm)
* (if you edit this definition, pay attention to trailing spaces after
* each word -- I warned you! :-) )
*/
-#define BUILTIN_CONSTRUCTOR \
+#define BUILTIN_CONSTRUCTOR \
": builtin: " \
- ">in @ " /* save the tib index pointer */ \
- "' " /* get next word's xt */ \
- "swap >in ! " /* point again to next word */ \
- "create " /* create a new definition of the next word */ \
- ", " /* save previous definition's xt */ \
- "immediate " /* make the new definition an immediate word */ \
+ ">in @ " /* save the tib index pointer */ \
+ "' " /* get next word's xt */ \
+ "swap >in ! " /* point again to next word */ \
+ "create " /* create a new definition of the next word */ \
+ ", " /* save previous definition's xt */ \
+ "immediate " /* make the new definition an immediate word */ \
\
- "does> " /* Now, the *new* definition will: */ \
- "state @ if " /* if in compiling state: */ \
- "1 postpone literal " /* pass 1 flag to indicate compile */ \
- "@ compile, " /* compile in previous definition */ \
- "postpone throw " /* throw stack-returned result */ \
- "else " /* if in interpreting state: */ \
- "0 swap " /* pass 0 flag to indicate interpret */ \
- "@ execute " /* call previous definition */ \
- "throw " /* throw stack-returned result */ \
- "then ; "
+ "does> " /* Now, the *new* definition will: */ \
+ "state @ if " /* if in compiling state: */ \
+ "1 postpone literal " /* pass 1 flag to indicate compile */ \
+ "@ compile, " /* compile in previous definition */ \
+ "postpone throw " /* throw stack-returned result */ \
+ "else " /* if in interpreting state: */ \
+ "0 swap " /* pass 0 flag to indicate interpret */ \
+ "@ execute " /* call previous definition */ \
+ "throw " /* throw stack-returned result */ \
+ "then ; "
/*
* Initialise the Forth interpreter, create all our commands as words.
@@ -255,72 +261,73 @@ bf_command(ficlVm *vm)
void
bf_init(char *rc)
{
- struct bootblk_command **cmdp;
- char create_buf[41]; /* 31 characters-long builtins */
- int fd, rv;
- ficlDictionary *dict;
- ficlDictionary *env;
-
- fsi = malloc(sizeof(ficlSystemInformation));
- ficlSystemInformationInitialize(fsi);
- fsi->dictionarySize = BF_DICTSIZE;
-
- bf_sys = ficlSystemCreate(fsi);
- bf_vm = ficlSystemCreateVm(bf_sys);
-
- /* Put all private definitions in a "builtins" vocabulary */
- rv = ficlVmEvaluate(bf_vm, "vocabulary builtins also builtins definitions");
- if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
- panic("error interpreting forth: %d\n", rv);
- }
-
- /* Builtin constructor word */
- rv = ficlVmEvaluate(bf_vm, BUILTIN_CONSTRUCTOR);
- if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
- panic("error interpreting forth: %d\n", rv);
- }
-
- /* make all commands appear as Forth words */
- dict = ficlSystemGetDictionary(bf_sys);
- SET_FOREACH(cmdp, Xcommand_set) {
- ficlDictionaryAppendPrimitive(dict, (char *)(*cmdp)->c_name,
- bf_command, FICL_WORD_DEFAULT);
- rv = ficlVmEvaluate(bf_vm, "forth definitions builtins");
+ struct bootblk_command **cmdp;
+ char create_buf[41]; /* 31 characters-long builtins */
+ int fd, rv;
+ ficlDictionary *dict;
+ ficlDictionary *env;
+
+ fsi = malloc(sizeof (ficlSystemInformation));
+ ficlSystemInformationInitialize(fsi);
+ fsi->dictionarySize = BF_DICTSIZE;
+
+ bf_sys = ficlSystemCreate(fsi);
+ bf_vm = ficlSystemCreateVm(bf_sys);
+
+ /* Put all private definitions in a "builtins" vocabulary */
+ rv = ficlVmEvaluate(bf_vm,
+ "vocabulary builtins also builtins definitions");
if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
- panic("error interpreting forth: %d\n", rv);
+ panic("error interpreting forth: %d", rv);
}
- sprintf(create_buf, "builtin: %s", (*cmdp)->c_name);
- rv = ficlVmEvaluate(bf_vm, create_buf);
+
+ /* Builtin constructor word */
+ rv = ficlVmEvaluate(bf_vm, BUILTIN_CONSTRUCTOR);
if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
- panic("error interpreting forth: %d\n", rv);
+ panic("error interpreting forth: %d", rv);
+ }
+
+ /* make all commands appear as Forth words */
+ dict = ficlSystemGetDictionary(bf_sys);
+ SET_FOREACH(cmdp, Xcommand_set) {
+ ficlDictionaryAppendPrimitive(dict, (char *)(*cmdp)->c_name,
+ bf_command, FICL_WORD_DEFAULT);
+ rv = ficlVmEvaluate(bf_vm, "forth definitions builtins");
+ if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
+ panic("error interpreting forth: %d", rv);
+ }
+ sprintf(create_buf, "builtin: %s", (*cmdp)->c_name);
+ rv = ficlVmEvaluate(bf_vm, create_buf);
+ if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
+ panic("error interpreting forth: %d", rv);
+ }
+ rv = ficlVmEvaluate(bf_vm, "builtins definitions");
+ if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
+ panic("error interpreting forth: %d", rv);
+ }
}
- rv = ficlVmEvaluate(bf_vm, "builtins definitions");
+ rv = ficlVmEvaluate(bf_vm, "only forth definitions");
if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
- panic("error interpreting forth: %d\n", rv);
+ panic("error interpreting forth: %d", rv);
}
- }
- rv = ficlVmEvaluate(bf_vm, "only forth definitions");
- if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
- panic("error interpreting forth: %d\n", rv);
- }
-
- /*
- * Export some version numbers so that code can detect the loader/host
- * version
- */
- env = ficlSystemGetEnvironment(bf_sys);
- ficlDictionarySetConstant(env, "loader_version", bootprog_rev);
-
- /* try to load and run init file if present */
- if (rc == NULL)
- rc = "/boot/forth/boot.4th";
- if (*rc != '\0') {
- fd = open(rc, O_RDONLY);
- if (fd != -1) {
- (void)ficlExecFD(bf_vm, fd);
- close(fd);
+
+ /*
+ * Export some version numbers so that code can detect the loader/host
+ * version
+ */
+ env = ficlSystemGetEnvironment(bf_sys);
+ ficlDictionarySetConstant(env, "loader_version", bootprog_rev);
+
+ /* try to load and run init file if present */
+ if (rc == NULL)
+ rc = "/boot/forth/boot.4th";
+ if (*rc != '\0') {
+ fd = open(rc, O_RDONLY);
+ if (fd != -1) {
+ (void) ficlExecFD(bf_vm, fd);
+ close(fd);
+ }
}
- }
}
/*
@@ -329,39 +336,39 @@ bf_init(char *rc)
int
bf_run(char *line)
{
- int result;
- ficlString s;
-
- FICL_STRING_SET_FROM_CSTRING(s, line);
- result = ficlVmExecuteString(bf_vm, s);
-
- DEBUG("ficlExec '%s' = %d", line, result);
- switch (result) {
- case FICL_VM_STATUS_OUT_OF_TEXT:
- case FICL_VM_STATUS_ABORTQ:
- case FICL_VM_STATUS_QUIT:
- case FICL_VM_STATUS_ERROR_EXIT:
- break;
- case FICL_VM_STATUS_USER_EXIT:
- printf("No where to leave to!\n");
- break;
- case FICL_VM_STATUS_ABORT:
- printf("Aborted!\n");
- break;
- case BF_PARSE:
- printf("Parse error!\n");
- break;
- default:
- if (command_errmsg != NULL) {
- printf("%s\n", command_errmsg);
- command_errmsg = NULL;
+ int result;
+ ficlString s;
+
+ FICL_STRING_SET_FROM_CSTRING(s, line);
+ result = ficlVmExecuteString(bf_vm, s);
+
+ DEBUG("ficlExec '%s' = %d", line, result);
+ switch (result) {
+ case FICL_VM_STATUS_OUT_OF_TEXT:
+ case FICL_VM_STATUS_ABORTQ:
+ case FICL_VM_STATUS_QUIT:
+ case FICL_VM_STATUS_ERROR_EXIT:
+ break;
+ case FICL_VM_STATUS_USER_EXIT:
+ printf("No where to leave to!\n");
+ break;
+ case FICL_VM_STATUS_ABORT:
+ printf("Aborted!\n");
+ break;
+ case BF_PARSE:
+ printf("Parse error!\n");
+ break;
+ default:
+ if (command_errmsg != NULL) {
+ printf("%s\n", command_errmsg);
+ command_errmsg = NULL;
+ }
}
- }
- /* bye is same as reboot and will behave depending on platform */
- if (result == FICL_VM_STATUS_USER_EXIT)
- bf_run("reboot");
- setenv("interpret", bf_vm->state ? "" : "ok", 1);
+ /* bye is same as reboot and will behave depending on platform */
+ if (result == FICL_VM_STATUS_USER_EXIT)
+ bf_run("reboot");
+ setenv("interpret", bf_vm->state ? "" : "ok", 1);
- return (result);
+ return (result);
}
diff --git a/usr/src/boot/sys/boot/common/linenoise/linenoise.c b/usr/src/boot/sys/boot/common/linenoise/linenoise.c
index 871ffb5437..e3a72151a4 100755
--- a/usr/src/boot/sys/boot/common/linenoise/linenoise.c
+++ b/usr/src/boot/sys/boot/common/linenoise/linenoise.c
@@ -650,6 +650,7 @@ static int linenoiseEdit(char *buf, size_t buflen, const char *prompt)
buf[0] = '\0';
l.pos = l.len = 0;
refreshLine(&l);
+ break;
case BACKSPACE: /* backspace */
case 8: /* ctrl-h */
linenoiseEditBackspace(&l);
diff --git a/usr/src/boot/sys/boot/common/multiboot2.c b/usr/src/boot/sys/boot/common/multiboot2.c
index 5b2cb9d397..67c28b1528 100644
--- a/usr/src/boot/sys/boot/common/multiboot2.c
+++ b/usr/src/boot/sys/boot/common/multiboot2.c
@@ -57,7 +57,7 @@ static void (*trampoline)(uint32_t, struct relocator *, uint64_t);
#include "platform/acfreebsd.h"
#include "acconfig.h"
-#define ACPI_SYSTEM_XFACE
+#define ACPI_SYSTEM_XFACE
#include "actypes.h"
#include "actbl.h"
@@ -66,7 +66,7 @@ extern ACPI_TABLE_RSDP *rsdp;
/* MB data heap pointer. */
static vm_offset_t last_addr;
-static int multiboot2_loadfile(char *, u_int64_t, struct preloaded_file **);
+static int multiboot2_loadfile(char *, uint64_t, struct preloaded_file **);
static int multiboot2_exec(struct preloaded_file *);
struct file_format multiboot2 = { multiboot2_loadfile, multiboot2_exec };
@@ -126,7 +126,7 @@ is_info_request_valid(multiboot_header_tag_information_request_t *rtag)
}
static int
-multiboot2_loadfile(char *filename, u_int64_t dest,
+multiboot2_loadfile(char *filename, uint64_t dest,
struct preloaded_file **result)
{
int fd, error;
@@ -539,12 +539,12 @@ update_cmdline(char *cl, bool mb2)
}
tmp = insert_cmdline(cl, propstr);
- free(propstr);
- if (tmp == NULL)
+ free(propstr);
+ if (tmp == NULL)
return (cl);
- free(cl);
- cl = tmp;
+ free(cl);
+ cl = tmp;
}
if (ttymode != NULL) {
char *propstr;
@@ -554,11 +554,11 @@ update_cmdline(char *cl, bool mb2)
return (cl);
tmp = insert_cmdline(cl, propstr);
- free(propstr);
- if (tmp == NULL)
+ free(propstr);
+ if (tmp == NULL)
return (cl);
- free(cl);
- cl = tmp;
+ free(cl);
+ cl = tmp;
}
return (cl);
@@ -676,7 +676,7 @@ module_size(struct preloaded_file *fp)
return (size);
}
-#if defined (EFI)
+#if defined(EFI)
/*
* Calculate size for UEFI memory map tag.
*/
@@ -725,7 +725,7 @@ biossmap_size(struct preloaded_file *fp)
if (md == NULL)
return (0);
- num = md->md_size / sizeof(struct bios_smap); /* number of entries */
+ num = md->md_size / sizeof (struct bios_smap); /* number of entries */
return (sizeof (multiboot_tag_mmap_t) +
num * sizeof (multiboot_mmap_entry_t));
}
@@ -734,7 +734,7 @@ static size_t
mbi_size(struct preloaded_file *fp, char *cmdline)
{
size_t size;
-#if !defined (EFI)
+#if !defined(EFI)
extern multiboot_tag_framebuffer_t gfx_fb;
#endif
@@ -743,13 +743,13 @@ mbi_size(struct preloaded_file *fp, char *cmdline)
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
-#if !defined (EFI)
+#if !defined(EFI)
size += sizeof (multiboot_tag_basic_meminfo_t);
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
#endif
size += module_size(fp);
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
-#if defined (EFI)
+#if defined(EFI)
size += sizeof (multiboot_tag_efi64_t);
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
size += efimemmap_size();
@@ -764,7 +764,7 @@ mbi_size(struct preloaded_file *fp, char *cmdline)
size += biossmap_size(fp);
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
-#if !defined (EFI)
+#if !defined(EFI)
if (gfx_fb.framebuffer_common.framebuffer_type ==
MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
size += sizeof (struct multiboot_tag_framebuffer_common);
@@ -780,21 +780,21 @@ mbi_size(struct preloaded_file *fp, char *cmdline)
#endif
if (bootp_response != NULL) {
- size += sizeof(multiboot_tag_network_t) + bootp_response_size;
+ size += sizeof (multiboot_tag_network_t) + bootp_response_size;
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
}
if (rsdp != NULL) {
if (rsdp->Revision == 0) {
size += sizeof (multiboot_tag_old_acpi_t) +
- sizeof(ACPI_RSDP_COMMON);
+ sizeof (ACPI_RSDP_COMMON);
} else {
size += sizeof (multiboot_tag_new_acpi_t) +
rsdp->Length;
}
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
}
- size += sizeof(multiboot_tag_t);
+ size += sizeof (multiboot_tag_t);
return (size);
}
@@ -811,7 +811,7 @@ multiboot2_exec(struct preloaded_file *fp)
int rootfs = 0;
size_t size;
struct bios_smap *smap;
-#if defined (EFI)
+#if defined(EFI)
multiboot_tag_module_t *module, *mp;
EFI_MEMORY_DESCRIPTOR *map;
UINTN map_size, desc_size;
@@ -870,7 +870,7 @@ multiboot2_exec(struct preloaded_file *fp)
for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next)
i++;
-#if defined (EFI)
+#if defined(EFI)
/* We need space for kernel + MBI + # modules */
num = (EFI_PAGE_SIZE - offsetof(struct relocator, rel_chunklist)) /
sizeof (struct chunk);
@@ -904,7 +904,7 @@ multiboot2_exec(struct preloaded_file *fp)
{
multiboot_tag_string_t *tag;
i = sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
- tag = (multiboot_tag_string_t *) mb_malloc(i);
+ tag = (multiboot_tag_string_t *)mb_malloc(i);
tag->mb_type = MULTIBOOT_TAG_TYPE_CMDLINE;
tag->mb_size = i;
@@ -916,7 +916,7 @@ multiboot2_exec(struct preloaded_file *fp)
{
multiboot_tag_string_t *tag;
i = sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1;
- tag = (multiboot_tag_string_t *) mb_malloc(i);
+ tag = (multiboot_tag_string_t *)mb_malloc(i);
tag->mb_type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME;
tag->mb_size = i;
@@ -924,7 +924,7 @@ multiboot2_exec(struct preloaded_file *fp)
strlen(bootprog_info) + 1);
}
-#if !defined (EFI)
+#if !defined(EFI)
/* Only set in case of BIOS. */
{
multiboot_tag_basic_meminfo_t *tag;
@@ -960,7 +960,7 @@ multiboot2_exec(struct preloaded_file *fp)
* - Set the tmp to point to physical address of the first module.
* - tmp != mfp->f_addr only in case of EFI.
*/
-#if defined (EFI)
+#if defined(EFI)
tmp = roundup2(load_addr + fp->f_size + 1, MULTIBOOT_MOD_ALIGN);
module = (multiboot_tag_module_t *)last_addr;
#endif
@@ -990,7 +990,7 @@ multiboot2_exec(struct preloaded_file *fp)
tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE;
tag->mb_size = sizeof (*tag) + num;
-#if defined (EFI)
+#if defined(EFI)
/*
* We can assign module addresses only after BS have been
* switched off.
@@ -1014,7 +1014,7 @@ multiboot2_exec(struct preloaded_file *fp)
}
smap = (struct bios_smap *)md->md_data;
- num = md->md_size / sizeof(struct bios_smap); /* number of entries */
+ num = md->md_size / sizeof (struct bios_smap); /* number of entries */
{
multiboot_tag_mmap_t *tag;
@@ -1042,24 +1042,22 @@ multiboot2_exec(struct preloaded_file *fp)
if (bootp_response != NULL) {
multiboot_tag_network_t *tag;
tag = (multiboot_tag_network_t *)
- mb_malloc(sizeof(*tag) + bootp_response_size);
+ mb_malloc(sizeof (*tag) + bootp_response_size);
tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK;
- tag->mb_size = sizeof(*tag) + bootp_response_size;
+ tag->mb_size = sizeof (*tag) + bootp_response_size;
memcpy(tag->mb_dhcpack, bootp_response, bootp_response_size);
}
-#if !defined (EFI)
- {
- multiboot_tag_vbe_t *tag;
- extern multiboot_tag_vbe_t vbestate;
-
- if (VBE_VALID_MODE(vbestate.vbe_mode)) {
- tag = (multiboot_tag_vbe_t *)mb_malloc(sizeof(*tag));
- memcpy(tag, &vbestate, sizeof(*tag));
- tag->mb_type = MULTIBOOT_TAG_TYPE_VBE;
- tag->mb_size = sizeof(*tag);
- }
+#if !defined(EFI)
+ multiboot_tag_vbe_t *tag;
+ extern multiboot_tag_vbe_t vbestate;
+
+ if (VBE_VALID_MODE(vbestate.vbe_mode)) {
+ tag = (multiboot_tag_vbe_t *)mb_malloc(sizeof (*tag));
+ memcpy(tag, &vbestate, sizeof (*tag));
+ tag->mb_type = MULTIBOOT_TAG_TYPE_VBE;
+ tag->mb_size = sizeof (*tag);
}
#endif
@@ -1083,7 +1081,7 @@ multiboot2_exec(struct preloaded_file *fp)
}
}
-#if defined (EFI)
+#if defined(EFI)
#ifdef __LP64__
{
multiboot_tag_efi64_t *tag;
@@ -1110,9 +1108,9 @@ multiboot2_exec(struct preloaded_file *fp)
if (have_framebuffer == true) {
multiboot_tag_framebuffer_t *tag;
extern multiboot_tag_framebuffer_t gfx_fb;
-#if defined (EFI)
+#if defined(EFI)
- tag = (multiboot_tag_framebuffer_t *) mb_malloc(sizeof (*tag));
+ tag = (multiboot_tag_framebuffer_t *)mb_malloc(sizeof (*tag));
memcpy(tag, &gfx_fb, sizeof (*tag));
tag->framebuffer_common.mb_type =
MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
@@ -1132,7 +1130,7 @@ multiboot2_exec(struct preloaded_file *fp)
size = sizeof (gfx_fb);
}
- tag = (multiboot_tag_framebuffer_t *) mb_malloc(size);
+ tag = (multiboot_tag_framebuffer_t *)mb_malloc(size);
memcpy(tag, &gfx_fb, sizeof (*tag));
tag->framebuffer_common.mb_type =
@@ -1148,7 +1146,7 @@ multiboot2_exec(struct preloaded_file *fp)
#endif /* EFI */
}
-#if defined (EFI)
+#if defined(EFI)
/* Leave EFI memmap last as we will also switch off the BS. */
{
multiboot_tag_efi_mmap_t *tag;
@@ -1175,7 +1173,7 @@ multiboot2_exec(struct preloaded_file *fp)
}
tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP;
tag->mb_size = sizeof (*tag) + map_size;
- tag->mb_descr_size = (uint32_t) desc_size;
+ tag->mb_descr_size = (uint32_t)desc_size;
/*
* Find relocater pages. We assume we have free pages
@@ -1195,7 +1193,7 @@ multiboot2_exec(struct preloaded_file *fp)
break;
}
if (map->PhysicalStart == 0)
- panic("Could not find memory for relocater\n");
+ panic("Could not find memory for relocater");
if (keep_bs == 0) {
status = BS->ExitBootServices(IH, key);
@@ -1216,16 +1214,17 @@ multiboot2_exec(struct preloaded_file *fp)
*/
{
multiboot_tag_t *tag = (multiboot_tag_t *)
- mb_malloc(sizeof(*tag));
+ mb_malloc(sizeof (*tag));
tag->mb_type = MULTIBOOT_TAG_TYPE_END;
- tag->mb_size = sizeof(*tag);
+ tag->mb_size = sizeof (*tag);
}
mbi->mbi_total_size = last_addr - (vm_offset_t)mbi;
mbi->mbi_reserved = 0;
-#if defined (EFI)
- /* At this point we have load_addr pointing to kernel load
+#if defined(EFI)
+ /*
+ * At this point we have load_addr pointing to kernel load
* address, module list in MBI having physical addresses,
* module list in fp having logical addresses and tmp pointing to
* physical address for MBI.
@@ -1254,7 +1253,7 @@ multiboot2_exec(struct preloaded_file *fp)
mp->mb_mod_start = efi_physaddr(module, tmp, map,
map_size / desc_size, desc_size, mp->mb_mod_end);
if (mp->mb_mod_start == 0)
- panic("Could not find memory for module\n");
+ panic("Could not find memory for module");
mp->mb_mod_end += mp->mb_mod_start;
chunk->chunk_paddr = mp->mb_mod_start;
@@ -1268,7 +1267,7 @@ multiboot2_exec(struct preloaded_file *fp)
chunk = &relocator->rel_chunklist[i++];
chunk->chunk_vaddr = (EFI_VIRTUAL_ADDRESS)(uintptr_t)mbi;
chunk->chunk_paddr = efi_physaddr(module, tmp, map,
- map_size / desc_size, desc_size, mbi->mbi_total_size);
+ map_size / desc_size, desc_size, mbi->mbi_total_size);
chunk->chunk_size = mbi->mbi_total_size;
STAILQ_INSERT_TAIL(head, chunk, chunk_next);
@@ -1293,7 +1292,7 @@ multiboot2_exec(struct preloaded_file *fp)
error:
if (cmdline != NULL)
free(cmdline);
-#if defined (EFI)
+#if defined(EFI)
if (mbi != NULL)
efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size));
#endif
diff --git a/usr/src/boot/sys/boot/common/tem.c b/usr/src/boot/sys/boot/common/tem.c
index 1bff41718e..4311e0cb64 100644
--- a/usr/src/boot/sys/boot/common/tem.c
+++ b/usr/src/boot/sys/boot/common/tem.c
@@ -428,7 +428,7 @@ env_screen_nounset(struct env_var *ev __unused)
if (tems.ts_p_dimension.width == 0 &&
tems.ts_p_dimension.height == 0)
return (0);
- return(EPERM);
+ return (EPERM);
}
static void
@@ -515,8 +515,9 @@ tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width)
tems.ts_font.vf_bytes =
malloc(font_data->uncompressed_size);
if (tems.ts_font.vf_bytes == NULL)
- panic("out of memory\n");
- (void)lz4_decompress(font_data->compressed_data,
+ panic("out of memory");
+ (void) lz4_decompress(
+ font_data->compressed_data,
tems.ts_font.vf_bytes,
font_data->compressed_size,
font_data->uncompressed_size, 0);
@@ -696,9 +697,10 @@ tems_cursor(struct vis_conscursor *pca)
static void
tem_kdsetmode(int mode)
{
- if (tems.ts_hdl != NULL)
+ if (tems.ts_hdl != NULL) {
(void) tems.ts_hdl->c_ioctl(tems.ts_hdl, KDSETMODE,
- (void *)(intptr_t)mode);
+ (void *)(intptr_t)mode);
+ }
}
static void
@@ -2392,7 +2394,7 @@ tem_cls(struct tem_vt_state *tem)
bg_color = DEFAULT_ANSI_BACKGROUND;
tem_get_color(&fg_color, &bg_color, c);
cl.bg_color = bg_color;
- (void)tems_cls(&cl);
+ (void) tems_cls(&cl);
tem->tvs_c_cursor.row = 0;
tem->tvs_c_cursor.col = 0;
diff --git a/usr/src/boot/sys/boot/efi/loader/Makefile.common b/usr/src/boot/sys/boot/efi/loader/Makefile.common
index c77cc4437c..622fad5d1d 100644
--- a/usr/src/boot/sys/boot/efi/loader/Makefile.common
+++ b/usr/src/boot/sys/boot/efi/loader/Makefile.common
@@ -2,11 +2,11 @@
SRCS += boot.c commands.c console.c devopen.c interp.c
SRCS += interp_backslash.c interp_parse.c ls.c misc.c
-SRCS += module.c panic.c linenoise.c zfs_cmd.c
+SRCS += module.c linenoise.c zfs_cmd.c
OBJS += boot.o commands.o console.o devopen.o interp.o \
interp_backslash.o interp_parse.o ls.o misc.o \
- module.o panic.o linenoise.o zfs_cmd.o
+ module.o linenoise.o zfs_cmd.o
SRCS += load_elf32.c load_elf32_obj.c reloc_elf32.c
SRCS += load_elf64.c load_elf64_obj.c reloc_elf64.c
diff --git a/usr/src/boot/sys/boot/efi/loader/comconsole.c b/usr/src/boot/sys/boot/efi/loader/comconsole.c
index c46971eeda..2399d37760 100644
--- a/usr/src/boot/sys/boot/efi/loader/comconsole.c
+++ b/usr/src/boot/sys/boot/efi/loader/comconsole.c
@@ -28,6 +28,7 @@
#include <stand.h>
#include <sys/errno.h>
#include <bootstrap.h>
+#include <stdbool.h>
#include <efi.h>
#include <efilib.h>
@@ -42,6 +43,8 @@ static EFI_GUID serial = SERIAL_IO_PROTOCOL;
#define COMSPEED 9600
#endif
+#define PNP0501 0x501 /* 16550A-compatible COM port */
+
struct serial {
uint64_t baudrate;
uint8_t databits;
@@ -59,7 +62,7 @@ static void comc_putchar(struct console *, int);
static int comc_getchar(struct console *);
static int comc_ischar(struct console *);
static int comc_ioctl(struct console *, int, void *);
-static void comc_setup(struct console *);
+static bool comc_setup(struct console *);
static char *comc_asprint_mode(struct serial *);
static int comc_parse_mode(struct serial *, const char *);
static int comc_mode_set(struct env_var *, int, const void *);
@@ -118,7 +121,7 @@ struct console ttyd = {
.c_private = NULL
};
-EFI_STATUS
+static EFI_STATUS
efi_serial_init(EFI_HANDLE **handlep, int *nhandles)
{
UINTN bufsz = 0;
@@ -137,7 +140,7 @@ efi_serial_init(EFI_HANDLE **handlep, int *nhandles)
if ((handles = malloc(bufsz)) == NULL)
return (ENOMEM);
- *nhandles = (int)(bufsz/sizeof (EFI_HANDLE));
+ *nhandles = (int)(bufsz / sizeof (EFI_HANDLE));
/*
* get handle array
*/
@@ -150,28 +153,91 @@ efi_serial_init(EFI_HANDLE **handlep, int *nhandles)
return (status);
}
+/*
+ * Find serial device number from device path.
+ * Return -1 if not found.
+ */
+static int
+efi_serial_get_index(EFI_DEVICE_PATH *devpath)
+{
+ ACPI_HID_DEVICE_PATH *acpi;
+
+ while (!IsDevicePathEnd(devpath)) {
+ if (DevicePathType(devpath) == ACPI_DEVICE_PATH &&
+ DevicePathSubType(devpath) == ACPI_DP) {
+
+ acpi = (ACPI_HID_DEVICE_PATH *)devpath;
+ if (acpi->HID == EISA_PNP_ID(PNP0501)) {
+ return (acpi->UID);
+ }
+ }
+
+ devpath = NextDevicePathNode(devpath);
+ }
+ return (-1);
+}
+
+/*
+ * The order of handles from LocateHandle() is not known, we need to
+ * iterate handles, pick device path for handle, and check the device
+ * number.
+ */
+static EFI_HANDLE
+efi_serial_get_handle(int port)
+{
+ EFI_STATUS status;
+ EFI_HANDLE *handles, handle;
+ EFI_DEVICE_PATH *devpath;
+ int index, nhandles;
+
+ if (port == -1)
+ return (NULL);
+
+ handles = NULL;
+ nhandles = 0;
+ status = efi_serial_init(&handles, &nhandles);
+ if (EFI_ERROR(status))
+ return (NULL);
+
+ handle = NULL;
+ for (index = 0; index < nhandles; index++) {
+ devpath = efi_lookup_devpath(handles[index]);
+ if (port == efi_serial_get_index(devpath)) {
+ handle = (handles[index]);
+ break;
+ }
+ }
+
+ /*
+ * In case we did fail to identify the device by path, use port as
+ * array index. Note, we did check port == -1 above.
+ */
+ if (port < nhandles && handle == NULL)
+ handle = handles[port];
+
+ free(handles);
+ return (handle);
+}
+
static void
comc_probe(struct console *cp)
{
EFI_STATUS status;
+ EFI_HANDLE handle;
struct serial *port;
char name[20];
char value[20];
char *env;
- EFI_HANDLE *handles = NULL; /* array of handles */
- int nhandles = 0; /* number of handles in array */
/* are we already set up? */
if (cp->c_private != NULL)
return;
- /* make sure the handles are available */
- status = efi_serial_init(&handles, &nhandles);
-
cp->c_private = malloc(sizeof (struct serial));
port = cp->c_private;
port->baudrate = COMSPEED;
+ port->ioaddr = -1; /* invalid port */
if (strcmp(cp->c_name, "ttya") == 0)
port->ioaddr = 0;
else if (strcmp(cp->c_name, "ttyb") == 0)
@@ -181,9 +247,6 @@ comc_probe(struct console *cp)
else if (strcmp(cp->c_name, "ttyd") == 0)
port->ioaddr = 3;
- if (port->ioaddr >= nhandles)
- port->ioaddr = -1; /* invalid port */
-
port->databits = 8; /* 8,n,1 */
port->parity = NoParity; /* 8,n,1 */
port->stopbits = OneStopBit; /* 8,n,1 */
@@ -191,16 +254,16 @@ comc_probe(struct console *cp)
port->rtsdtr_off = 0; /* rts-dtr is on */
port->sio = NULL;
- if (port->ioaddr != -1) {
- status = BS->OpenProtocol(handles[port->ioaddr],
- &serial, (void**)&port->sio, IH, NULL,
+ handle = efi_serial_get_handle(port->ioaddr);
+
+ if (handle != NULL) {
+ status = BS->OpenProtocol(handle, &serial,
+ (void**)&port->sio, IH, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(status))
- port->ioaddr = -1; /* invalid port */
+ port->sio = NULL;
}
- if (handles != NULL)
- free(handles);
snprintf(name, sizeof (name), "%s-mode", cp->c_name);
env = getenv(name);
@@ -243,18 +306,20 @@ comc_probe(struct console *cp)
port->rtsdtr_off? "true" : "false");
unsetenv(name);
env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset);
- comc_setup(cp);
+
+ cp->c_flags = 0;
+ if (comc_setup(cp))
+ cp->c_flags = C_PRESENTIN | C_PRESENTOUT;
}
static int
comc_init(struct console *cp, int arg __attribute((unused)))
{
- comc_setup(cp);
-
- if ((cp->c_flags & (C_PRESENTIN | C_PRESENTOUT)) ==
- (C_PRESENTIN | C_PRESENTOUT))
+ if (comc_setup(cp))
return (CMD_OK);
+
+ cp->c_flags = 0;
return (CMD_ERROR);
}
@@ -495,7 +560,8 @@ comc_mode_set(struct env_var *ev, int flags, const void *value)
if (comc_parse_mode(cp->c_private, value) == CMD_ERROR)
return (CMD_ERROR);
- comc_setup(cp);
+ (void) comc_setup(cp);
+
env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
return (CMD_OK);
@@ -521,7 +587,8 @@ comc_cd_set(struct env_var *ev, int flags, const void *value)
else
return (CMD_ERROR);
- comc_setup(cp);
+ (void) comc_setup(cp);
+
env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
return (CMD_OK);
@@ -547,50 +614,48 @@ comc_rtsdtr_set(struct env_var *ev, int flags, const void *value)
else
return (CMD_ERROR);
- comc_setup(cp);
+ (void) comc_setup(cp);
+
env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
return (CMD_OK);
}
-static void
+/*
+ * In case of error, we also reset ACTIVE flags, so the console
+ * framefork will try alternate consoles.
+ */
+static bool
comc_setup(struct console *cp)
{
EFI_STATUS status;
UINT32 control;
struct serial *sp = cp->c_private;
- if ((cp->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) == 0)
- return;
-
/* port is not usable */
- if (sp->sio == NULL) {
- cp->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
- return;
- }
+ if (sp->sio == NULL)
+ return (false);
- cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
status = sp->sio->Reset(sp->sio);
- if (EFI_ERROR(status)) {
- cp->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
- }
+ if (EFI_ERROR(status))
+ return (false);
status = sp->sio->SetAttributes(sp->sio, sp->baudrate, 0, 0, sp->parity,
sp->databits, sp->stopbits);
- if (EFI_ERROR(status)) {
- cp->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
- }
+ if (EFI_ERROR(status))
+ return (false);
if (sp->rtsdtr_off) {
status = sp->sio->GetControl(sp->sio, &control);
- if (EFI_ERROR(status)) {
- cp->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
- }
+ if (EFI_ERROR(status))
+ return (false);
control &= ~(EFI_SERIAL_REQUEST_TO_SEND |
EFI_SERIAL_DATA_TERMINAL_READY);
status = sp->sio->SetControl(sp->sio, control);
- if (EFI_ERROR(status)) {
- cp->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
- }
+ if (EFI_ERROR(status))
+ return (false);
}
+ /* Mark this port usable. */
+ cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
+ return (true);
}
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile b/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile
index 201ae6b609..dfe323f6ca 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile
+++ b/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile
@@ -60,7 +60,7 @@ all: $(PROG)
install: all $(ROOTBOOTPROG)
-OBJS = multiboot.o zfsboot.o sio.o cons.o panic.o devopen.o bio.o \
+OBJS = multiboot.o zfsboot.o sio.o cons.o devopen.o bio.o \
part.o biosmem.o smbios.o biosdisk.o devicename.o disk.o bcache.o \
time.o zfs_cmd.o
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
index 5d57d909ce..6c52d8e279 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
+++ b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
@@ -107,7 +107,6 @@ static char *heap_top;
static char *heap_bottom;
static void i386_zfs_probe(void);
-void exit(int);
static void load(void);
static int parse_cmd(void);
@@ -272,6 +271,7 @@ main(void)
void
exit(int x)
{
+ while (1);
}
static void
diff --git a/usr/src/boot/sys/boot/i386/isoboot/Makefile b/usr/src/boot/sys/boot/i386/isoboot/Makefile
index f6337bc3a9..5b13aa6f65 100644
--- a/usr/src/boot/sys/boot/i386/isoboot/Makefile
+++ b/usr/src/boot/sys/boot/i386/isoboot/Makefile
@@ -51,7 +51,7 @@ all: $(PROG)
install: all $(ROOTBOOTPROG)
-OBJS= multiboot.o isoboot.o sio.o drv.o cons.o gptldr.o panic.o
+OBJS= multiboot.o isoboot.o sio.o drv.o cons.o gptldr.o
CLEANFILES += isoboot
diff --git a/usr/src/boot/sys/boot/i386/libi386/bio.c b/usr/src/boot/sys/boot/i386/libi386/bio.c
index 9b72e606eb..07a330a06c 100644
--- a/usr/src/boot/sys/boot/i386/libi386/bio.c
+++ b/usr/src/boot/sys/boot/i386/libi386/bio.c
@@ -62,5 +62,5 @@ bio_free(void *ptr, size_t size)
bio_buffer_ptr -= size;
if (bio_buffer_ptr != ptr)
- panic("bio_alloc()/bio_free() mismatch\n");
+ panic("bio_alloc()/bio_free() mismatch");
}
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
index 608310f97d..38eda5171a 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
+++ b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
@@ -131,7 +131,7 @@ static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
char *buf, size_t *rsize);
static int bd_open(struct open_file *f, ...);
static int bd_close(struct open_file *f);
-static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
+static int bd_ioctl(struct open_file *f, ulong_t cmd, void *data);
static int bd_print(int verbose);
static int cd_print(int verbose);
static int fd_print(int verbose);
@@ -363,29 +363,29 @@ bc_add(int biosdev)
int nbcinfo = 0;
if (!STAILQ_EMPTY(&cdinfo))
- return (-1);
-
- v86.ctl = V86_FLAGS;
- v86.addr = 0x13;
- v86.eax = 0x4b01;
- v86.edx = biosdev;
- v86.ds = VTOPSEG(&bc_sp);
- v86.esi = VTOPOFF(&bc_sp);
- v86int();
- if ((v86.eax & 0xff00) != 0)
- return (-1);
+ return (-1);
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x13;
+ v86.eax = 0x4b01;
+ v86.edx = biosdev;
+ v86.ds = VTOPSEG(&bc_sp);
+ v86.esi = VTOPOFF(&bc_sp);
+ v86int();
+ if ((v86.eax & 0xff00) != 0)
+ return (-1);
if ((bd = calloc(1, sizeof (*bd))) == NULL)
return (-1);
bd->bd_flags = BD_CDROM;
- bd->bd_unit = biosdev;
+ bd->bd_unit = biosdev;
/*
* Ignore result from bd_int13probe(), we will use local
* workaround below.
*/
- (void)bd_int13probe(bd);
+ (void) bd_int13probe(bd);
if (bd->bd_cyl == 0) {
bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) +
@@ -403,10 +403,10 @@ bc_add(int biosdev)
bd->bd_sectors = 4173824;
STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link);
- printf("BIOS CD is cd%d\n", nbcinfo);
- nbcinfo++;
- bcache_add_dev(nbcinfo); /* register cd device in bcache */
- return(0);
+ printf("BIOS CD is cd%d\n", nbcinfo);
+ nbcinfo++;
+ bcache_add_dev(nbcinfo); /* register cd device in bcache */
+ return (0);
}
/*
@@ -789,7 +789,7 @@ bd_open(struct open_file *f, ...)
return (EIO);
}
if (bd->bd_bcache == NULL)
- bd->bd_bcache = bcache_allocate();
+ bd->bd_bcache = bcache_allocate();
if (bd->bd_open == 0)
bd->bd_sectors = bd_disk_get_sectors(dev);
@@ -824,8 +824,8 @@ bd_close(struct open_file *f)
bd->bd_open--;
if (bd->bd_open == 0) {
- bcache_free(bd->bd_bcache);
- bd->bd_bcache = NULL;
+ bcache_free(bd->bd_bcache);
+ bd->bd_bcache = NULL;
}
if (dev->dd.d_dev->dv_type == DEVT_DISK)
rc = disk_close(dev);
@@ -833,7 +833,7 @@ bd_close(struct open_file *f)
}
static int
-bd_ioctl(struct open_file *f, u_long cmd, void *data)
+bd_ioctl(struct open_file *f, ulong_t cmd, void *data)
{
bdinfo_t *bd;
struct disk_devdesc *dev;
@@ -984,7 +984,7 @@ bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
if (bbuf == NULL) {
bio_size = V86_IO_BUFFER_SIZE;
if (bio_size / bd->bd_sectorsize == 0)
- panic("BUG: Real mode buffer is too small\n");
+ panic("BUG: Real mode buffer is too small");
/* Use alternate 4k buffer */
bbuf = PTOV(V86_IO_BUFFER);
@@ -1298,7 +1298,7 @@ bd_getdev(struct i386_devdesc *d)
* we pass -C to the boot args if we are the boot device.
*/
major = ACDMAJOR;
- unit = 0; /* XXX */
+ unit = 0; /* XXX */
}
/* XXX a better kludge to set the root disk unit number */
diff --git a/usr/src/boot/sys/boot/i386/libi386/comconsole.c b/usr/src/boot/sys/boot/i386/libi386/comconsole.c
index 29ed725b89..a1e120a692 100644
--- a/usr/src/boot/sys/boot/i386/libi386/comconsole.c
+++ b/usr/src/boot/sys/boot/i386/libi386/comconsole.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
*
* Redistribution and use in source and binary forms, with or without
@@ -27,17 +27,18 @@
#include <stand.h>
#include <bootstrap.h>
+#include <stdbool.h>
#include <machine/cpufunc.h>
#include <dev/ic/ns16550.h>
#include <dev/pci/pcireg.h>
#include "libi386.h"
-#define COMC_TXWAIT 0x40000 /* transmit timeout */
-#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
-#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */
+#define COMC_TXWAIT 0x40000 /* transmit timeout */
+#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
+#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */
#ifndef COMSPEED
-#define COMSPEED 9600
+#define COMSPEED 9600
#endif
#define COM1_IOADDR 0x3f8
@@ -77,7 +78,7 @@ static int comc_ioctl(struct console *, int, void *);
static uint32_t comc_parse_pcidev(const char *);
static int comc_pcidev_set(struct env_var *, int, const void *);
static int comc_pcidev_handle(struct console *, uint32_t);
-static void comc_setup(struct console *);
+static bool comc_setup(struct console *);
static char *comc_asprint_mode(struct serial *);
static int comc_parse_mode(struct serial *, const char *);
static int comc_mode_set(struct env_var *, int, const void *);
@@ -139,24 +140,26 @@ struct console ttyd = {
static void
comc_probe(struct console *cp)
{
- struct serial *port;
- char name[20];
- char value[20];
- char *cons, *env;
+ struct serial *port;
+ char name[20];
+ char value[20];
+ char *cons, *env;
+
+ if (cp->c_private != NULL)
+ return;
- if (cp->c_private == NULL) {
- cp->c_private = malloc(sizeof(struct serial));
+ cp->c_private = malloc(sizeof (struct serial));
port = cp->c_private;
port->speed = COMSPEED;
if (strcmp(cp->c_name, "ttya") == 0)
- port->ioaddr = COM1_IOADDR;
+ port->ioaddr = COM1_IOADDR;
else if (strcmp(cp->c_name, "ttyb") == 0)
- port->ioaddr = COM2_IOADDR;
+ port->ioaddr = COM2_IOADDR;
else if (strcmp(cp->c_name, "ttyc") == 0)
- port->ioaddr = COM3_IOADDR;
+ port->ioaddr = COM3_IOADDR;
else if (strcmp(cp->c_name, "ttyd") == 0)
- port->ioaddr = COM4_IOADDR;
+ port->ioaddr = COM4_IOADDR;
port->lcr = BITS8; /* 8,n,1 */
port->ignore_cd = 1; /* ignore cd */
@@ -217,54 +220,55 @@ comc_probe(struct console *cp)
snprintf(name, sizeof (name), "%s-pcidev", cp->c_name);
env = getenv(name);
if (env != NULL) {
- port->locator = comc_parse_pcidev(env);
- if (port->locator != 0)
- comc_pcidev_handle(cp, port->locator);
+ port->locator = comc_parse_pcidev(env);
+ if (port->locator != 0)
+ comc_pcidev_handle(cp, port->locator);
}
unsetenv(name);
env_setenv(name, EV_VOLATILE, env, comc_pcidev_set, env_nounset);
- }
- comc_setup(cp);
+
+ cp->c_flags = 0;
+ if (comc_setup(cp))
+ cp->c_flags = C_PRESENTIN | C_PRESENTOUT;
}
static int
comc_init(struct console *cp, int arg __attribute((unused)))
{
- comc_setup(cp);
+ if (comc_setup(cp))
+ return (CMD_OK);
- if ((cp->c_flags & (C_PRESENTIN | C_PRESENTOUT)) ==
- (C_PRESENTIN | C_PRESENTOUT))
- return (CMD_OK);
- return (CMD_ERROR);
+ cp->c_flags = 0;
+ return (CMD_ERROR);
}
static void
comc_putchar(struct console *cp, int c)
{
- int wait;
- struct serial *sp = cp->c_private;
+ int wait;
+ struct serial *sp = cp->c_private;
- for (wait = COMC_TXWAIT; wait > 0; wait--)
- if (inb(sp->ioaddr + com_lsr) & LSR_TXRDY) {
- outb(sp->ioaddr + com_data, (u_char)c);
- break;
- }
+ for (wait = COMC_TXWAIT; wait > 0; wait--)
+ if (inb(sp->ioaddr + com_lsr) & LSR_TXRDY) {
+ outb(sp->ioaddr + com_data, (uchar_t)c);
+ break;
+ }
}
static int
comc_getchar(struct console *cp)
{
- struct serial *sp = cp->c_private;
- return (comc_ischar(cp) ? inb(sp->ioaddr + com_data) : -1);
+ struct serial *sp = cp->c_private;
+ return (comc_ischar(cp) ? inb(sp->ioaddr + com_data) : -1);
}
static int
comc_ischar(struct console *cp)
{
- struct serial *sp = cp->c_private;
- return (inb(sp->ioaddr + com_lsr) & LSR_RXRDY);
+ struct serial *sp = cp->c_private;
+ return (inb(sp->ioaddr + com_lsr) & LSR_RXRDY);
}
static int
@@ -380,7 +384,7 @@ get_console(char *name)
{
struct console *cp = NULL;
- switch(name[3]) {
+ switch (name[3]) {
case 'a': cp = &ttya;
break;
case 'b': cp = &ttyb;
@@ -396,76 +400,76 @@ get_console(char *name)
static int
comc_mode_set(struct env_var *ev, int flags, const void *value)
{
- struct console *cp;
+ struct console *cp;
- if (value == NULL)
- return (CMD_ERROR);
+ if (value == NULL)
+ return (CMD_ERROR);
- if ((cp = get_console(ev->ev_name)) == NULL)
- return (CMD_ERROR);
+ if ((cp = get_console(ev->ev_name)) == NULL)
+ return (CMD_ERROR);
- if (comc_parse_mode(cp->c_private, value) == CMD_ERROR)
- return (CMD_ERROR);
+ if (comc_parse_mode(cp->c_private, value) == CMD_ERROR)
+ return (CMD_ERROR);
- comc_setup(cp);
+ (void) comc_setup(cp);
- env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
- return (CMD_OK);
+ return (CMD_OK);
}
static int
comc_cd_set(struct env_var *ev, int flags, const void *value)
{
- struct console *cp;
- struct serial *sp;
+ struct console *cp;
+ struct serial *sp;
- if (value == NULL)
- return (CMD_ERROR);
+ if (value == NULL)
+ return (CMD_ERROR);
- if ((cp = get_console(ev->ev_name)) == NULL)
- return (CMD_ERROR);
+ if ((cp = get_console(ev->ev_name)) == NULL)
+ return (CMD_ERROR);
- sp = cp->c_private;
- if (strcmp(value, "true") == 0)
- sp->ignore_cd = 1;
- else if (strcmp(value, "false") == 0)
- sp->ignore_cd = 0;
- else
- return (CMD_ERROR);
+ sp = cp->c_private;
+ if (strcmp(value, "true") == 0)
+ sp->ignore_cd = 1;
+ else if (strcmp(value, "false") == 0)
+ sp->ignore_cd = 0;
+ else
+ return (CMD_ERROR);
- comc_setup(cp);
+ (void) comc_setup(cp);
- env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
- return (CMD_OK);
+ return (CMD_OK);
}
static int
comc_rtsdtr_set(struct env_var *ev, int flags, const void *value)
{
- struct console *cp;
- struct serial *sp;
+ struct console *cp;
+ struct serial *sp;
- if (value == NULL)
- return (CMD_ERROR);
+ if (value == NULL)
+ return (CMD_ERROR);
- if ((cp = get_console(ev->ev_name)) == NULL)
- return (CMD_ERROR);
+ if ((cp = get_console(ev->ev_name)) == NULL)
+ return (CMD_ERROR);
- sp = cp->c_private;
- if (strcmp(value, "true") == 0)
- sp->rtsdtr_off = 1;
- else if (strcmp(value, "false") == 0)
- sp->rtsdtr_off = 0;
- else
- return (CMD_ERROR);
+ sp = cp->c_private;
+ if (strcmp(value, "true") == 0)
+ sp->rtsdtr_off = 1;
+ else if (strcmp(value, "false") == 0)
+ sp->rtsdtr_off = 0;
+ else
+ return (CMD_ERROR);
- comc_setup(cp);
+ (void) comc_setup(cp);
- env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
- return (CMD_OK);
+ return (CMD_OK);
}
/*
@@ -476,7 +480,7 @@ static uint32_t
comc_parse_pcidev(const char *string)
{
#ifdef NO_PCI
- (void)string;
+ (void) string;
return (0);
#else
char *p, *p1;
@@ -486,26 +490,26 @@ comc_parse_pcidev(const char *string)
errno = 0;
pres = strtoul(string, &p, 10);
- if (errno != 0 || p == string || *p != ':' || pres < 0 )
+ if (errno != 0 || p == string || *p != ':' || pres < 0)
return (0);
bus = pres;
p1 = ++p;
pres = strtoul(p1, &p, 10);
- if (errno != 0 || p == string || *p != ':' || pres < 0 )
+ if (errno != 0 || p == string || *p != ':' || pres < 0)
return (0);
dev = pres;
p1 = ++p;
pres = strtoul(p1, &p, 10);
- if (errno != 0 || p == string || (*p != ':' && *p != '\0') || pres < 0 )
+ if (errno != 0 || p == string || (*p != ':' && *p != '\0') || pres < 0)
return (0);
func = pres;
if (*p == ':') {
p1 = ++p;
pres = strtoul(p1, &p, 10);
- if (errno != 0 || p == string || *p != '\0' || pres <= 0 )
+ if (errno != 0 || p == string || *p != '\0' || pres <= 0)
return (0);
bar = pres;
} else
@@ -520,15 +524,15 @@ static int
comc_pcidev_handle(struct console *cp, uint32_t locator)
{
#ifdef NO_PCI
- (void)cp;
- (void)locator;
+ (void) cp;
+ (void) locator;
return (CMD_ERROR);
#else
struct serial *sp = cp->c_private;
uint32_t port;
if (biospci_read_config(locator & 0xffff,
- (locator & 0xff0000) >> 16, 2, &port) == -1) {
+ (locator & 0xff0000) >> 16, 2, &port) == -1) {
printf("Cannot read bar at 0x%x\n", locator);
return (CMD_ERROR);
}
@@ -536,9 +540,10 @@ comc_pcidev_handle(struct console *cp, uint32_t locator)
printf("Memory bar at 0x%x\n", locator);
return (CMD_ERROR);
}
- port &= PCIM_BAR_IO_BASE;
+ port &= PCIM_BAR_IO_BASE;
+
+ (void) comc_setup(cp);
- comc_setup(cp);
sp->locator = locator;
return (CMD_OK);
@@ -571,41 +576,51 @@ comc_pcidev_set(struct env_var *ev, int flags, const void *value)
return (CMD_OK);
}
-static void
+/*
+ * In case of error, we also reset ACTIVE flags, so the console
+ * framefork will try alternate consoles.
+ */
+static bool
comc_setup(struct console *cp)
{
- struct serial *sp = cp->c_private;
- static int TRY_COUNT = 1000000;
- int tries;
-
- if ((cp->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) == 0)
- return;
-
- outb(sp->ioaddr + com_cfcr, CFCR_DLAB | sp->lcr);
- outb(sp->ioaddr + com_dlbl, COMC_BPS(sp->speed) & 0xff);
- outb(sp->ioaddr + com_dlbh, COMC_BPS(sp->speed) >> 8);
- outb(sp->ioaddr + com_cfcr, sp->lcr);
- outb(sp->ioaddr + com_mcr,
- sp->rtsdtr_off? ~(MCR_RTS | MCR_DTR):MCR_RTS | MCR_DTR);
-
- tries = 0;
- do
- inb(sp->ioaddr + com_data);
- while (inb(sp->ioaddr + com_lsr) & LSR_RXRDY && ++tries < TRY_COUNT);
-
- if (tries < TRY_COUNT) {
+ struct serial *sp = cp->c_private;
+ static int TRY_COUNT = 1000000;
+ int tries;
+
+#define COMC_TEST 0xbb
+ /*
+ * Write byte to scratch register and read it out.
+ */
+ outb(sp->ioaddr + com_scr, COMC_TEST);
+ if (inb(sp->ioaddr + com_scr) != COMC_TEST)
+ return (false);
+
+ outb(sp->ioaddr + com_cfcr, CFCR_DLAB | sp->lcr);
+ outb(sp->ioaddr + com_dlbl, COMC_BPS(sp->speed) & 0xff);
+ outb(sp->ioaddr + com_dlbh, COMC_BPS(sp->speed) >> 8);
+ outb(sp->ioaddr + com_cfcr, sp->lcr);
+ outb(sp->ioaddr + com_mcr,
+ sp->rtsdtr_off? ~(MCR_RTS | MCR_DTR) : MCR_RTS | MCR_DTR);
+
+ tries = 0;
+ do {
+ inb(sp->ioaddr + com_data);
+ } while (inb(sp->ioaddr + com_lsr) & LSR_RXRDY && ++tries < TRY_COUNT);
+
+ if (tries == TRY_COUNT)
+ return (false);
+ /* Mark this port usable. */
cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
- } else
- cp->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
+ return (true);
}
static int
comc_getspeed(struct serial *sp)
{
- u_int divisor;
- u_char dlbh;
- u_char dlbl;
- u_char cfcr;
+ uint_t divisor;
+ uchar_t dlbh;
+ uchar_t dlbl;
+ uchar_t cfcr;
cfcr = inb(sp->ioaddr + com_cfcr);
outb(sp->ioaddr + com_cfcr, CFCR_DLAB | cfcr);
diff --git a/usr/src/boot/sys/boot/i386/loader/Makefile b/usr/src/boot/sys/boot/i386/loader/Makefile
index a31d1155fe..28e0dfa3e5 100644
--- a/usr/src/boot/sys/boot/i386/loader/Makefile
+++ b/usr/src/boot/sys/boot/i386/loader/Makefile
@@ -56,7 +56,7 @@ LIBFICL= ../../libficl/$(MACH)/libficl.a
# Always add MI sources
SRCS += boot.c commands.c console.c devopen.c interp.c
SRCS += interp_backslash.c interp_parse.c ls.c misc.c
-SRCS += module.c panic.c linenoise.c multiboot2.c
+SRCS += module.c linenoise.c multiboot2.c
SRCS += zfs_cmd.c
SRCS += font.c $(FONT).c list.c tem.c
@@ -169,13 +169,13 @@ install: all $(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_FORTH) \
$(FONT).c: $(FONT_DIR)/$(FONT_SRC)
$(VTFONTCVT) -f compressed-source -o $@ $(FONT_DIR)/$(FONT_SRC)
-$(ROOT_BOOT)/%: ../../forth/%
+$(ROOT_BOOT)/%: ../../forth/% $(ROOT_BOOT)
$(INS.file)
-$(ROOT_BOOT_DEFAULTS)/%: ../../forth/%
+$(ROOT_BOOT_DEFAULTS)/%: ../../forth/% $(ROOT_BOOT_DEFAULTS)
$(INS.file)
-$(ROOT_BOOT_FORTH)/%: ../../forth/%
+$(ROOT_BOOT_FORTH)/%: ../../forth/% $(ROOT_BOOT_FORTH)
$(INS.file)
$(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_CONF) $(ROOT_BOOT_FORTH):
diff --git a/usr/src/boot/sys/boot/uboot/lib/copy.c b/usr/src/boot/sys/boot/uboot/lib/copy.c
index 131b88d858..b41246f179 100644
--- a/usr/src/boot/sys/boot/uboot/lib/copy.c
+++ b/usr/src/boot/sys/boot/uboot/lib/copy.c
@@ -1,6 +1,6 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
- * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
+ * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <stand.h>
@@ -37,7 +36,7 @@ __FBSDID("$FreeBSD$");
#include "libuboot.h"
/*
- * MD primitives supporting placement of module data
+ * MD primitives supporting placement of module data
*/
#ifdef __arm__
@@ -66,7 +65,7 @@ extern void _start(void); /* ubldr entry point address. */
* that each object begins on a page boundary.
*/
uint64_t
-uboot_loadaddr(u_int type, void *data, uint64_t addr)
+uboot_loadaddr(uint_t type, void *data, uint64_t addr)
{
struct sys_info *si;
uint64_t sblock, eblock, subldr, eubldr;
@@ -121,7 +120,8 @@ uboot_loadaddr(u_int type, void *data, uint64_t addr)
}
} else if (subldr < sblock && eubldr < eblock) {
/* Loader is below or engulfs the sblock */
- this_block = (eubldr < sblock) ? sblock : eubldr;
+ this_block = (eubldr < sblock) ?
+ sblock : eubldr;
this_size = eblock - this_block;
} else {
this_block = 0;
@@ -133,16 +133,16 @@ uboot_loadaddr(u_int type, void *data, uint64_t addr)
}
}
if (biggest_size == 0)
- panic("Not enough DRAM to load kernel\n");
+ panic("Not enough DRAM to load kernel");
#if 0
printf("Loading kernel into region 0x%08jx-0x%08jx (%ju MiB)\n",
- (uintmax_t)biggest_block,
+ (uintmax_t)biggest_block,
(uintmax_t)biggest_block + biggest_size - 1,
(uintmax_t)biggest_size / 1024 / 1024);
#endif
return (biggest_block);
}
- return roundup2(addr, PAGE_SIZE);
+ return (roundup2(addr, PAGE_SIZE));
}
ssize_t
diff --git a/usr/src/boot/sys/boot/uboot/lib/net.c b/usr/src/boot/sys/boot/uboot/lib/net.c
index 1f15f3ce0e..ba3909d215 100644
--- a/usr/src/boot/sys/boot/uboot/lib/net.c
+++ b/usr/src/boot/sys/boot/uboot/lib/net.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 2000-2001 Benno Rice
* Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
* All rights reserved.
@@ -118,7 +118,7 @@ get_env_net_params()
*/
if ((envstr = ub_env_get("rootpath")) == NULL)
return;
- strlcpy(rootpath, envstr, sizeof(rootpath));
+ strlcpy(rootpath, envstr, sizeof (rootpath));
setenv("dhcp.root-path", rootpath, 0);
/*
@@ -155,7 +155,7 @@ get_env_net_params()
*/
serveraddr = INADDR_NONE;
if ((envstr = ub_env_get("serverip")) != NULL) {
- if ((serveraddr = inet_addr(envstr)) == INADDR_NONE)
+ if ((serveraddr = inet_addr(envstr)) == INADDR_NONE)
printf("Could not parse serverip '%s'\n", envstr);
}
@@ -323,13 +323,13 @@ net_init(struct iodesc *desc, void *machdep_hint)
sc = nif->nif_devdata = &uboot_softc;
if ((err = ub_dev_open(sc->sc_handle)) != 0)
- panic("%s%d: initialisation failed with error %d\n",
+ panic("%s%d: initialisation failed with error %d",
nif->nif_driver->netif_bname, nif->nif_unit, err);
/* Get MAC address */
di = ub_dev_get(sc->sc_handle);
memcpy(desc->myea, di->di_net.hwaddr, 6);
- if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) {
+ if (memcmp(desc->myea, "\0\0\0\0\0\0", 6) == 0) {
panic("%s%d: empty ethernet address!",
nif->nif_driver->netif_bname, nif->nif_unit);
}
@@ -358,6 +358,6 @@ net_end(struct netif *nif)
int err;
if ((err = ub_dev_close(sc->sc_handle)) != 0)
- panic("%s%d: net_end failed with error %d\n",
+ panic("%s%d: net_end failed with error %d",
nif->nif_driver->netif_bname, nif->nif_unit, err);
}
diff --git a/usr/src/cmd/audio/audioplay/audioplay.c b/usr/src/cmd/audio/audioplay/audioplay.c
index 882c4d9087..ad225bb55e 100644
--- a/usr/src/cmd/audio/audioplay/audioplay.c
+++ b/usr/src/cmd/audio/audioplay/audioplay.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
/* Command-line audio play utility */
#include <stdio.h>
@@ -802,7 +806,8 @@ closeinput:;
(void) close(ifd); /* close input file */
if (Errdetect) {
cnt = 0;
- audio_set_play_error(Audio_fd, (unsigned int *)&cnt);
+ (void) audio_set_play_error(Audio_fd,
+ (unsigned int *)&cnt);
if (cnt) {
Error(stderr,
MGET("%s: output underflow in %s\n"),
diff --git a/usr/src/cmd/audio/audiorecord/audiorecord.c b/usr/src/cmd/audio/audiorecord/audiorecord.c
index 1879f238fa..6195ffe351 100644
--- a/usr/src/cmd/audio/audiorecord/audiorecord.c
+++ b/usr/src/cmd/audio/audiorecord/audiorecord.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
/* Command-line audio record utility */
#include <stdio.h>
@@ -773,7 +777,7 @@ parse_sample_rate(char *s, unsigned *rate)
if (*cp != NULL) {
if ((*cp == 'k') || (*cp == 'K')) {
drate *= 1000.0;
- } else if ((*cp != 'h') || (*cp != 'H')) {
+ } else if ((*cp != 'h') && (*cp != 'H')) {
/* bogus! */
Error(stderr,
MGET("invalid sample rate: %s\n"), s);
diff --git a/usr/src/cmd/audit/audit.c b/usr/src/cmd/audit/audit.c
index 5c4b8ea39b..95eda0da4e 100644
--- a/usr/src/cmd/audit/audit.c
+++ b/usr/src/cmd/audit/audit.c
@@ -23,6 +23,10 @@
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <fcntl.h>
#include <libscf.h>
#include <secdb.h>
@@ -232,7 +236,7 @@ is_audit_config_ok() {
if (strcmp((char *)&(*plugin_kva_ll).plugin_name,
"audit_binfile") == 0) {
cval_str = kva_match(kvlist, "p_dir");
- if (*cval_str == '\0' || cval_str == NULL) {
+ if (cval_str == NULL || cval_str[0] == '\0') {
(void) fprintf(stderr,
gettext("%s: audit_binfile(5) \"p_dir:\" "
"attribute empty\n"), progname);
diff --git a/usr/src/cmd/auditconfig/auditconfig.c b/usr/src/cmd/auditconfig/auditconfig.c
index 197ab63ad3..7fdaf7c59c 100644
--- a/usr/src/cmd/auditconfig/auditconfig.c
+++ b/usr/src/cmd/auditconfig/auditconfig.c
@@ -23,6 +23,10 @@
*/
/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
+/*
* auditconfig - set and display audit parameters
*/
@@ -2572,14 +2576,15 @@ strisnum(char *s)
if (s == NULL || !*s)
return (0);
- for (; *s == '-' || *s == '+'; s++)
-
- if (!*s)
- return (0);
+ for (; *s == '-' || *s == '+'; s++) {
+ if (!*s)
+ return (0);
+ }
- for (; *s; s++)
+ for (; *s; s++) {
if (!isdigit(*s))
return (0);
+ }
return (1);
}
diff --git a/usr/src/cmd/bhyve/virtio.c b/usr/src/cmd/bhyve/virtio.c
index 4c85000796..d3ff5e3951 100644
--- a/usr/src/cmd/bhyve/virtio.c
+++ b/usr/src/cmd/bhyve/virtio.c
@@ -422,6 +422,13 @@ vq_relchain(struct vqueue_info *vq, uint16_t idx, uint32_t iolen)
vue = &vuh->vu_ring[uidx++ & mask];
vue->vu_idx = idx;
vue->vu_tlen = iolen;
+#ifndef __FreeBSD__
+ /*
+ * Ensure the used descriptor is visible before updating the index.
+ * This is necessary on ISAs with memory ordering less strict than x86.
+ */
+ wmb();
+#endif
vuh->vu_idx = uidx;
}
@@ -459,6 +466,14 @@ vq_endchains(struct vqueue_info *vq, int used_all_avail)
vs = vq->vq_vs;
old_idx = vq->vq_save_used;
vq->vq_save_used = new_idx = vq->vq_used->vu_idx;
+#ifndef __FreeBSD__
+ /*
+ * Use full memory barrier between vu_idx store from preceding
+ * vq_relchain() call and the loads from VQ_USED_EVENT_IDX() or
+ * va_flags below.
+ */
+ mb();
+#endif
if (used_all_avail &&
(vs->vs_negotiated_caps & VIRTIO_F_NOTIFY_ON_EMPTY))
intr = 1;
diff --git a/usr/src/cmd/busstat/busstat.c b/usr/src/cmd/busstat/busstat.c
index 23ef251223..94cfdb021b 100644
--- a/usr/src/cmd/busstat/busstat.c
+++ b/usr/src/cmd/busstat/busstat.c
@@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
#include <stdio.h>
#include <stdlib.h>
@@ -398,7 +400,7 @@ parse_cmd(int mode)
"event names or pic values not "
"permitted with -r option.\n"),
pgmname);
- usage();
+ usage();
exit(1);
}
/*
diff --git a/usr/src/cmd/cat/cat.c b/usr/src/cmd/cat/cat.c
index 9a40c4dd37..b447581710 100644
--- a/usr/src/cmd/cat/cat.c
+++ b/usr/src/cmd/cat/cat.c
@@ -27,6 +27,9 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
/*
* Concatenate files.
@@ -271,10 +274,12 @@ main(int argc, char **argv)
!S_ISBLK(target.st_mode) &&
!S_ISSOCK(target.st_mode) &&
IDENTICAL(target, source)) {
- if (!silent)
- (void) fprintf(stderr,
- gettext("cat: input/output files '%s' identical\n"),
- stdinflg?"-": *argv);
+ if (!silent) {
+ (void) fprintf(stderr, gettext("cat: "
+ "input/output files '%s' identical\n"),
+ stdinflg?"-": *argv);
+ }
+
if (fclose(fi) != 0)
(void) fprintf(stderr,
gettext("cat: close error: %s\n"),
diff --git a/usr/src/cmd/chgrp/Makefile b/usr/src/cmd/chgrp/Makefile
index cac25266b7..7de84a25df 100644
--- a/usr/src/cmd/chgrp/Makefile
+++ b/usr/src/cmd/chgrp/Makefile
@@ -19,49 +19,37 @@
# CDDL HEADER END
#
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
PROG= chgrp
-XPG4PROG= chgrp
-XD= exobjs.xpg4
EXOBJS= chgrp.o
-XPG4EXOBJS= exobjs.xpg4/chgrp.o
include ../Makefile.cmd
-$(XPG4) := CFLAGS += -DXPG4
+ROOTXPG4LINK=$(ROOTXPG4BIN)/$(PROG)
+
CPPFLAGS += -D_FILE_OFFSET_BITS=64
LDLIBS += -lcmdutils -lsec
.KEEP_STATE:
-all: $(PROG) $(XPG4)
+all: $(PROG)
$(PROG): $(EXOBJS)
$(LINK.c) -o $@ $(EXOBJS) $(LDLIBS)
$(POST_PROCESS)
-$(XPG4): $(XD) $(XPG4EXOBJS)
- $(LINK.c) -o $@ $(XPG4EXOBJS) $(LDLIBS)
- $(POST_PROCESS)
+$(ROOTXPG4LINK): $(ROOTPROG)
+ -$(RM) $@
+ -$(SYMLINK) ../../bin/chgrp $@
-install: all $(ROOTPROG) $(ROOTXPG4PROG)
+install: all $(ROOTPROG) $(ROOTXPG4LINK)
clean:
- -@rm -rf $(EXOBJS) $(XD)
+ -@rm -rf $(EXOBJS)
lint: lint_PROG
-$(XPG4EXOBJS): $(XD)
-
-$(XD)/%.o: %.c
- $(COMPILE.c) -o $@ $<
-
-$(XD):
- -@mkdir -p $@
-
include ../Makefile.targ
diff --git a/usr/src/cmd/chgrp/chgrp.c b/usr/src/cmd/chgrp/chgrp.c
index a1fe7fefbf..ed27bbd47a 100644
--- a/usr/src/cmd/chgrp/chgrp.c
+++ b/usr/src/cmd/chgrp/chgrp.c
@@ -38,8 +38,6 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* chgrp [-fhR] gid file ...
* chgrp -R [-f] [-H|-L|-P] gid file ...
@@ -82,41 +80,18 @@ static int isnumber(char *);
static int Perror(char *);
static void chgrpr(char *, gid_t);
-#ifdef XPG4
-/*
- * Check to see if we are to follow symlinks specified on the command line.
- * This assumes we've already checked to make sure neither -h or -P was
- * specified, so we are just looking to see if -R -L, or -R -H was specified,
- * or, since -R has the same behavior as -R -L, if -R was specified by itself.
- * Therefore, all we really need to check for is if -R was specified.
- */
-#define FOLLOW_CL_LINKS (rflag)
-#else
/*
* Check to see if we are to follow symlinks specified on the command line.
* This assumes we've already checked to make sure neither -h or -P was
* specified, so we are just looking to see if -R -L, or -R -H was specified.
- * Note: -R by itself will change the group of a directory referenced by a
- * symlink however it will not follow the symlink to any other part of the
- * file hierarchy.
*/
#define FOLLOW_CL_LINKS (rflag && (Hflag || Lflag))
-#endif
-#ifdef XPG4
-/*
- * Follow symlinks when traversing directories. Since -R behaves the
- * same as -R -L, we always want to follow symlinks to other parts
- * of the file hierarchy unless -H was specified.
- */
-#define FOLLOW_D_LINKS (!Hflag)
-#else
/*
* Follow symlinks when traversing directories. Only follow symlinks
* to other parts of the file hierarchy if -L was specified.
*/
#define FOLLOW_D_LINKS (Lflag)
-#endif
#define CHOWN(f, u, g) if (chown(f, u, g) < 0) { \
status += Perror(f); \
@@ -185,6 +160,13 @@ main(int argc, char *argv[])
default:
usage();
}
+ /*
+ * Set Pflag by default for recursive operations
+ * if no other options were specified.
+ */
+ if (rflag && !(Lflag || Hflag || Pflag || hflag)) {
+ Pflag = 1;
+ }
/*
* Check for sufficient arguments
diff --git a/usr/src/cmd/chown/Makefile b/usr/src/cmd/chown/Makefile
index 622030cf38..9ee61bfc5f 100644
--- a/usr/src/cmd/chown/Makefile
+++ b/usr/src/cmd/chown/Makefile
@@ -19,50 +19,37 @@
# CDDL HEADER END
#
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
PROG= chown
-XPG4PROG= chown
-XD= exobjs.xpg4
EXOBJS= chown.o
-XPG4EXOBJS= exobjs.xpg4/chown.o
include ../Makefile.cmd
-$(XPG4) := CFLAGS += -DXPG4
+ROOTXPG4LINK=$(ROOTXPG4BIN)/$(PROG)
+
CPPFLAGS += -D_FILE_OFFSET_BITS=64
LDLIBS += -lcmdutils -lsec
.KEEP_STATE:
-all: $(PROG) $(XPG4)
+all: $(PROG)
$(PROG): $(EXOBJS)
$(LINK.c) -o $@ $(EXOBJS) $(LDLIBS)
$(POST_PROCESS)
-$(XPG4): $(XD) $(XPG4EXOBJS)
- $(LINK.c) -o $@ $(XPG4EXOBJS) $(LDLIBS)
- $(POST_PROCESS)
-
+$(ROOTXPG4LINK): $(ROOTPROG)
+ -$(RM) $@
+ -$(SYMLINK) ../../bin/chown $@
-install: all $(ROOTPROG) $(ROOTXPG4PROG)
+install: all $(ROOTPROG) $(ROOTXPG4LINK)
clean:
- -@rm -rf $(EXOBJS) $(XD)
+ -@rm -rf $(EXOBJS)
lint: lint_PROG
-$(XPG4EXOBJS): $(XD)
-
-$(XD)/%.o: %.c
- $(COMPILE.c) -o $@ $<
-
-$(XD):
- -@mkdir -p $@
-
include ../Makefile.targ
diff --git a/usr/src/cmd/chown/chown.c b/usr/src/cmd/chown/chown.c
index 319f571384..4542ab25bf 100644
--- a/usr/src/cmd/chown/chown.c
+++ b/usr/src/cmd/chown/chown.c
@@ -24,14 +24,16 @@
*/
/* 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
* under license from the Regents of the University of California.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
/*
* chown [-fhR] uid[:gid] file ...
@@ -76,41 +78,18 @@ static int isnumber(char *);
static void chownr(char *, uid_t, gid_t);
static void usage();
-#ifdef XPG4
-/*
- * Check to see if we are to follow symlinks specified on the command line.
- * This assumes we've already checked to make sure neither -h or -P was
- * specified, so we are just looking to see if -R -H, or -R -L was specified,
- * or, since -R has the same behavior as -R -L, if -R was specified by itself.
- * Therefore, all we really need to check for is if -R was specified.
- */
-#define FOLLOW_CL_LINKS (rflag)
-#else
/*
* Check to see if we are to follow symlinks specified on the command line.
* This assumes we've already checked to make sure neither -h or -P was
* specified, so we are just looking to see if -R -H, or -R -L was specified.
- * Note: -R by itself will change the ownership of a directory referenced by a
- * symlink however it will now follow the symlink to any other part of the
- * file hierarchy.
*/
#define FOLLOW_CL_LINKS (rflag && (Hflag || Lflag))
-#endif
-#ifdef XPG4
-/*
- * Follow symlinks when traversing directories. Since -R behaves the
- * same as -R -L, we always want to follow symlinks to other parts
- * of the file hierarchy unless -H was specified.
- */
-#define FOLLOW_D_LINKS (!Hflag)
-#else
/*
* Follow symlinks when traversing directories. Only follow symlinks
* to other parts of the file hierarchy if -L was specified.
*/
#define FOLLOW_D_LINKS (Lflag)
-#endif
#define CHOWN(f, u, g) if (chown(f, u, g) < 0) { \
status += Perror(f); \
@@ -180,6 +159,13 @@ main(int argc, char *argv[])
}
}
/*
+ * Set Pflag by default for recursive operations
+ * if no other options were specified.
+ */
+ if (rflag && !(Lflag || Hflag || Pflag || hflag)) {
+ Pflag = 1;
+ }
+ /*
* Check for sufficient arguments
* or a usage error.
*/
@@ -217,7 +203,7 @@ main(int argc, char *argv[])
if (errno == ERANGE) {
(void) fprintf(stderr, gettext(
"chown: group id too large\n"));
- exit(2);
+ exit(2);
} else {
(void) fprintf(stderr, gettext(
"chown: invalid group id\n"));
diff --git a/usr/src/cmd/cmd-inet/common/kcmd.c b/usr/src/cmd/cmd-inet/common/kcmd.c
index 35d2c4ee96..c4a078c96a 100644
--- a/usr/src/cmd/cmd-inet/common/kcmd.c
+++ b/usr/src/cmd/cmd-inet/common/kcmd.c
@@ -20,6 +20,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
/* derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88 */
#include <unistd.h>
@@ -412,8 +416,11 @@ kcmd(int *sock, char **ahost, ushort_t rport,
*sock = s;
/* pass back credentials if wanted */
- if (cred) (void) krb5_copy_creds(bsd_context, ret_cred, cred);
- krb5_free_creds(bsd_context, ret_cred);
+ if (cred)
+ (void) krb5_copy_creds(bsd_context, ret_cred, cred);
+
+ krb5_free_creds(bsd_context, ret_cred);
+
/*
* Initialize *authconp to auth_context, so
* that the clients can make use of it
diff --git a/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile b/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile
index c58b1a375f..9bc700ab29 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile
@@ -25,7 +25,7 @@ SRCS= ClientCommon.c dns-sd.c
SRCDIR= $(SRC)/contrib/mDNSResponder
CFLAGS += $(CSTD_GNU99)
CPPFLAGS += -I$(SRCDIR)/mDNSShared
-CPPFLAGS += -DMDNS_VERSIONSTR_NODTS
+CPPFLAGS += -DmDNSResponderVersion=878.1.1
LDLIBS += -lsocket -ldns_sd
# not linted
diff --git a/usr/src/cmd/cmd-inet/usr.bin/finger.c b/usr/src/cmd/cmd-inet/usr.bin/finger.c
index cdc94a7be6..d42d90eacf 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/finger.c
+++ b/usr/src/cmd/cmd-inet/usr.bin/finger.c
@@ -38,6 +38,10 @@
*/
/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
+/*
* This is a finger program. It prints out useful information about users
* by digging it up from various system files.
*
@@ -1359,7 +1363,7 @@ AlreadyPrinted(uid_t uid)
while (i++ < PPIndex) {
if (PlanPrinted[i] == uid)
- return (1);
+ return (1);
}
if (i < PPMAX) {
PlanPrinted[i] = uid;
diff --git a/usr/src/cmd/cmd-inet/usr.bin/pppd/plugins/passprompt.c b/usr/src/cmd/cmd-inet/usr.bin/pppd/plugins/passprompt.c
index ce361e9c37..a96fa32ba8 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/pppd/plugins/passprompt.c
+++ b/usr/src/cmd/cmd-inet/usr.bin/pppd/plugins/passprompt.c
@@ -8,6 +8,11 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
@@ -70,7 +75,7 @@ static int promptpass(char *user, char *passwd)
argv[0] = promptprog;
argv[1] = user == NULL ? "" : user;
argv[2] = remote_name;
- slprintf(fdstr, sizeof (fdstr), "%d", p[1]);
+ (void) slprintf(fdstr, sizeof (fdstr), "%d", p[1]);
argv[3] = fdstr;
argv[4] = NULL;
(void) execv(*argv, argv);
diff --git a/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile b/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile
index 7f3365c9ea..afac8667f2 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile
@@ -40,7 +40,7 @@ MDNSFLAGS= -DNOT_HAVE_SA_LEN \
-D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME \
-DHAVE_IPV6=1 -Dasm=__asm -DMDNSD_NOROOT \
-DPID_FILE=\"\" -DMDNSD_USER=\"noaccess\" \
- -DMDNS_VERSIONSTR_NODTS
+ -DmDNSResponderVersion=878.1.1
include ../../../Makefile.cmd
@@ -66,7 +66,7 @@ $(PROG): $(OBJS)
include ../Makefile.lib
-CSTD = $(CSTD_GNU99)
+CSTD= $(CSTD_GNU99)
CPPFLAGS += -D_REENTRANT $(MDNSFLAGS)
CPPFLAGS += -I$(SRCDIR)/mDNSShared -I$(SRCDIR)/mDNSPosix
CPPFLAGS += -I$(SRCDIR)/mDNSCore
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
index 4dbbb83590..30e2f0f549 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2017 Nexenta Systems, Inc.
- * Copyright 2017 Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
* Copyright 2017 Gary Mills
* Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
*/
@@ -1636,8 +1636,7 @@ is_from_gz(const char *lifname)
if (if_info->ifi_cflags & IFIF_L3PROTECT)
ret = _B_TRUE;
- if (if_info)
- ipadm_free_if_info(if_info);
+ ipadm_free_if_info(if_info);
return (ret);
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c b/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c
index c6f8257ae9..9f959976a8 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c
@@ -38,7 +38,7 @@
*/
/*
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <assert.h>
@@ -1989,7 +1989,7 @@ recv_icmp_packet(struct addrinfo *ai_dst, int recv_sock6, int recv_sock,
progname, strerror(errno));
}
continue;
- } if (cc > 0) {
+ } else if (cc > 0) {
check_reply(ai_dst, &in_msg, cc,
udp_src_port);
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c b/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c
index ad5100c1b0..5a9dc9889b 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c
@@ -23,7 +23,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
#include <stdio.h>
#include <stdlib.h>
@@ -2531,7 +2533,7 @@ do_deletepf(int fd, int argc, char **argv)
B_FALSE);
free(section_id);
p_section = p_sectionbak;
- continue;
+ continue;
}
p_section = p_section->section_next;
}
@@ -2751,8 +2753,9 @@ do_rmprefer(int fd, int argc, char **argv)
return (B_FALSE);
pae = plist->ael_head;
while (pae != NULL) {
+ ae_t *next = pae->ae_next;
free(pae);
- pae = pae->ae_next;
+ pae = next;
}
plist->ael_head = plist->ael_tail = NULL;
plist->ael_argc = 0;
diff --git a/usr/src/cmd/compress/compress.c b/usr/src/cmd/compress/compress.c
index de8e62b704..f0fb948239 100644
--- a/usr/src/cmd/compress/compress.c
+++ b/usr/src/cmd/compress/compress.c
@@ -13,7 +13,9 @@
* specifies the terms and conditions for redistribution.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
/*
* Compress - data compression program
@@ -815,7 +817,7 @@ main(int argc, char *argv[])
} else if (!quiet && !do_decomp) {
(void) fprintf(stderr, "%s: ",
*fileptr);
- newline_needed = 1;
+ newline_needed = 1;
}
/* Actually do the compression/decompression */
@@ -1308,7 +1310,7 @@ decompress()
if ((code == CLEAR) && block_compress) {
for (code = 255; code >= 0; code--)
- tab_prefixof(code) = 0;
+ tab_prefixof(code) = 0;
clear_flg = 1;
free_ent = FIRST - 1;
if ((code = getcode()) == -1) /* O, untimely death! */
@@ -1803,8 +1805,9 @@ cl_hash(count_int hsize) /* reset code table */
*(htab_p-1) = m1;
htab_p -= 16;
} while ((i -= 16) >= 0);
- for (i += 16; i > 0; i--)
- *--htab_p = m1;
+
+ for (i += 16; i > 0; i--)
+ *--htab_p = m1;
}
static void
diff --git a/usr/src/cmd/dfs.cmds/sharemgr/commands.c b/usr/src/cmd/dfs.cmds/sharemgr/commands.c
index 15e9cee992..f8cbecf01a 100644
--- a/usr/src/cmd/dfs.cmds/sharemgr/commands.c
+++ b/usr/src/cmd/dfs.cmds/sharemgr/commands.c
@@ -5656,46 +5656,46 @@ sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
if (rsrc != NULL) {
if (share != sa_get_resource_parent(rsrc))
ret = SA_DUPLICATE_NAME;
- } else {
- rsrc = sa_add_resource(share, resource,
- persist, &ret);
- }
- if (features & SA_FEATURE_RESOURCE)
- share = rsrc;
+ } else {
+ rsrc = sa_add_resource(share, resource,
+ persist, &ret);
}
+ if (features & SA_FEATURE_RESOURCE)
+ share = rsrc;
+ }
- /* Have a group to hold this share path */
- if (ret == SA_OK && options != NULL &&
- strlen(options) > 0) {
- ret = sa_parse_legacy_options(share,
- options,
+ /* Have a group to hold this share path */
+ if (ret == SA_OK && options != NULL &&
+ strlen(options) > 0) {
+ ret = sa_parse_legacy_options(share,
+ options,
+ protocol);
+ }
+ if (!zfs) {
+ /*
+ * ZFS shares never have a description
+ * and we can't store the values so
+ * don't try.
+ */
+ if (ret == SA_OK && description != NULL)
+ ret = sa_set_share_description(share,
+ description);
+ }
+ if (ret == SA_OK &&
+ strcmp(groupstatus, "enabled") == 0) {
+ if (rsrc != share)
+ ret = sa_enable_share(share, protocol);
+ else
+ ret = sa_enable_resource(rsrc,
protocol);
- }
- if (!zfs) {
- /*
- * ZFS shares never have a description
- * and we can't store the values so
- * don't try.
- */
- if (ret == SA_OK && description != NULL)
- ret = sa_set_share_description(share,
- description);
- }
if (ret == SA_OK &&
- strcmp(groupstatus, "enabled") == 0) {
- if (rsrc != share)
- ret = sa_enable_share(share, protocol);
- else
- ret = sa_enable_resource(rsrc,
- protocol);
- if (ret == SA_OK &&
- persist == SA_SHARE_PERMANENT) {
- (void) sa_update_legacy(share,
- protocol);
- }
- if (ret == SA_OK)
- ret = sa_update_config(handle);
+ persist == SA_SHARE_PERMANENT) {
+ (void) sa_update_legacy(share,
+ protocol);
}
+ if (ret == SA_OK)
+ ret = sa_update_config(handle);
+ }
}
err:
if (ret != SA_OK) {
diff --git a/usr/src/cmd/dis/dis_util.c b/usr/src/cmd/dis/dis_util.c
index f74e7cef67..af38189cb4 100644
--- a/usr/src/cmd/dis/dis_util.c
+++ b/usr/src/cmd/dis/dis_util.c
@@ -24,6 +24,7 @@
* Use is subject to license terms.
*
* Copyright 2018 Jason King.
+ * Copyright 2018, Joyent, Inc.
*/
#include <dlfcn.h>
@@ -106,6 +107,6 @@ dis_demangle(const char *name)
* from previous invocations is freed.
*/
free(demangled_name);
- demangled_name = sysdemangle(name, SYSDEM_LANG_CPP, NULL);
+ demangled_name = sysdemangle(name, SYSDEM_LANG_AUTO, NULL);
return ((demangled_name != NULL) ? demangled_name : name);
}
diff --git a/usr/src/cmd/echo/echo.c b/usr/src/cmd/echo/echo.c
index ebd8e3868b..e9f9027203 100644
--- a/usr/src/cmd/echo/echo.c
+++ b/usr/src/cmd/echo/echo.c
@@ -25,6 +25,9 @@
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
#include <stdio.h>
#include <stdlib.h>
@@ -55,16 +58,16 @@ main(int argc, char *argv[])
for (i = 1; i <= argc; i++) {
for (cp = argv[i], ep = cp + (int)strlen(cp);
cp < ep; cp += b_len) {
- if ((b_len = mbtowc(&wc, cp, MB_CUR_MAX)) <= 0) {
- (void) putchar(*cp);
- b_len = 1;
- continue;
- }
+ if ((b_len = mbtowc(&wc, cp, MB_CUR_MAX)) <= 0) {
+ (void) putchar(*cp);
+ b_len = 1;
+ continue;
+ }
- if (wc != '\\') {
- (void) putwchar(wc);
- continue;
- }
+ if (wc != '\\') {
+ (void) putwchar(wc);
+ continue;
+ }
cp += b_len;
b_len = 1;
diff --git a/usr/src/cmd/fm/fmtopo/common/fmtopo.c b/usr/src/cmd/fm/fmtopo/common/fmtopo.c
index 5327cf5da9..07fe40fafd 100644
--- a/usr/src/cmd/fm/fmtopo/common/fmtopo.c
+++ b/usr/src/cmd/fm/fmtopo/common/fmtopo.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019, Joyent, Inc. All rights reserved.
*/
@@ -42,7 +42,6 @@
#define FMTOPO_EXIT_USAGE 2
#define STDERR "stderr"
-#define DOTS "..."
#define ALL "all"
static const char *g_pname;
@@ -240,7 +239,7 @@ print_prop_nameval(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl)
{
int err;
topo_type_t type;
- char *tstr, *propn, buf[48], *factype;
+ char *tstr, *propn, *factype;
nvpair_t *pv_nvp;
int i;
uint_t nelem;
@@ -389,12 +388,7 @@ uint32_def:
case DATA_TYPE_STRING: {
char *val;
(void) nvpair_value_string(pv_nvp, &val);
- if (!opt_V && strlen(val) > 48) {
- (void) snprintf(buf, 48, "%s...", val);
- (void) printf(" %s", buf);
- } else {
- (void) printf(" %s", val);
- }
+ (void) printf(" %s", val);
break;
}
case DATA_TYPE_NVLIST: {
@@ -402,19 +396,13 @@ uint32_def:
char *fmri;
(void) nvpair_value_nvlist(pv_nvp, &val);
if (topo_fmri_nvl2str(thp, val, &fmri, &err) != 0) {
- if (opt_V)
- nvlist_print(stdout, nvl);
+ (void) fprintf(stderr, "failed to convert "
+ "FMRI to string: (%s)\n",
+ topo_strerror(err));
+ nvlist_print(stdout, nvl);
break;
}
-
- if (!opt_V && strlen(fmri) > 48) {
- (void) snprintf(buf, 48, "%s", fmri);
- (void) snprintf(&buf[45], 4, "%s", DOTS);
- (void) printf(" %s", buf);
- } else {
- (void) printf(" %s", fmri);
- }
-
+ (void) printf(" %s", fmri);
topo_hdl_strfree(thp, fmri);
break;
}
@@ -468,6 +456,29 @@ uint32_def:
(void) printf("]");
break;
}
+ case DATA_TYPE_NVLIST_ARRAY: {
+ nvlist_t **val;
+ char *fmri;
+ int ret;
+
+ (void) nvpair_value_nvlist_array(pv_nvp, &val, &nelem);
+ (void) printf(" [ ");
+ for (i = 0; i < nelem; i++) {
+ ret = topo_fmri_nvl2str(thp, val[i], &fmri,
+ &err);
+ if (ret != 0) {
+ (void) fprintf(stderr, "failed to "
+ "convert FMRI to string (%s)\n",
+ topo_strerror(err));
+ nvlist_print(stdout, val[i]);
+ break;
+ }
+ (void) printf("\"%s\" ", fmri);
+ topo_hdl_strfree(thp, fmri);
+ }
+ (void) printf("]");
+ break;
+ }
default:
(void) fprintf(stderr, " unknown data type (%d)",
nvpair_type(pv_nvp));
@@ -481,7 +492,6 @@ print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab,
char *nstab, int32_t version)
{
int err;
- char buf[30];
topo_pgroup_info_t *pgi = NULL;
if (pgn == NULL)
@@ -498,11 +508,6 @@ print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab,
if (dstab == NULL || nstab == NULL || version == -1) {
(void) printf(" group: %-30s version: - stability: -/-\n",
pgn);
- } else if (!opt_V && strlen(pgn) > 30) {
- (void) snprintf(buf, 26, "%s", pgn);
- (void) snprintf(&buf[27], 4, "%s", DOTS);
- (void) printf(" group: %-30s version: %-3d stability: %s/%s\n",
- buf, version, nstab, dstab);
} else {
(void) printf(" group: %-30s version: %-3d stability: %s/%s\n",
pgn, version, nstab, dstab);
diff --git a/usr/src/cmd/fmthard/fmthard.c b/usr/src/cmd/fmthard/fmthard.c
index 98faee8db3..02577c1445 100644
--- a/usr/src/cmd/fmthard/fmthard.c
+++ b/usr/src/cmd/fmthard/fmthard.c
@@ -34,6 +34,9 @@
*/
/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+/*
* Sun Microsystems version of fmthard:
*
* Supports the following arguments:
@@ -740,7 +743,7 @@ full size of disk. The full disk capacity is %llu sectors.\n", i, fullsz);
(vtoc->v_part[i].p_size % nblks)) {
(void) fprintf(stderr, "\
fmthard: Partition %d not aligned on cylinder boundary \n", i);
- exit(1);
+ exit(1);
}
if (vtoc->v_part[i].p_start > fullsz ||
vtoc->v_part[i].p_start +
diff --git a/usr/src/cmd/fruadm/fruadm.c b/usr/src/cmd/fruadm/fruadm.c
index 0efb6c5539..94eb9c16b3 100644
--- a/usr/src/cmd/fruadm/fruadm.c
+++ b/usr/src/cmd/fruadm/fruadm.c
@@ -24,6 +24,8 @@
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <limits.h>
@@ -243,9 +245,9 @@ display_data(unsigned char *data, size_t length, fru_elemdef_t *def)
char *disp_str = (char *)alloca(length+1);
for (i = 0; i < length; i++)
disp_str[i] = data[i];
- disp_str[i] = '\0';
- (void) printf("%s", disp_str);
- return;
+ disp_str[i] = '\0';
+ (void) printf("%s", disp_str);
+ return;
}
case FDTYPE_Enumeration:
@@ -592,7 +594,7 @@ updateiter_record(fru_nodehdl_t nodehdl, int cnt, char **ptr,
(void) fprintf(stderr,
gettext("fru_update_field(): %s\n"),
fru_strerror(err));
- return (1);
+ return (1);
}
iter_cnt = 1;
diff --git a/usr/src/cmd/fs.d/smbclnt/Makefile b/usr/src/cmd/fs.d/smbclnt/Makefile
index 5e26c570b3..e6b660643f 100644
--- a/usr/src/cmd/fs.d/smbclnt/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/Makefile
@@ -20,8 +20,8 @@
#
#
-# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -33,7 +33,7 @@ include $(SRC)/Makefile.master
SUBDIRS_CATALOG= smbutil mount umount share
SUBDIRS= $(SUBDIRS_CATALOG) chacl lsacl \
- smbiod smbiod-svc svc test
+ smbiod smbiod-svc svc fksmbcl
# for messaging catalog files
#
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc b/usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc
new file mode 100644
index 0000000000..8c05f688c5
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/.dbxrc
@@ -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.
+#
+
+# set -o emacs
+
+# fksmbcl is always 32-bit
+setenv LD_LIBRARY_PATH ${ROOT}/usr/lib/smbfs:${ROOT}/usr/lib:${ROOT}/lib
+
+echo 'Do one of: attach ${PID}'
+echo 'or: debug ${ROOT}/usr/lib/smbfs/fksmbcl'
+echo 'then: run -v //localhost'
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile
new file mode 100644
index 0000000000..5ae4f56e1b
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Makefile
@@ -0,0 +1,104 @@
+#
+# 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.
+#
+
+PROG= fksmbcl
+
+OBJS_LOCAL = \
+ fksmbcl_main.o \
+ fkdev.o \
+ fknewvc.o \
+ fkiod_cl.o \
+ shares.o
+
+OBJS= ${OBJS_LOCAL}
+SRCS= ${OBJS_LOCAL:.o=.c}
+
+include ../../../Makefile.cmd
+include ../../../Makefile.ctf
+
+# 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$(SRC)/lib/libfakekernel/common
+CPPFLAGS.first += -I$(SRC)/lib/smbclnt/libfknsmb/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
+
+# Allow cpp to find libfknsmb.h etc. via
+# include <libfknsmb/common/libfknsmb.h>
+INCS += -I$(SRC)/lib/smbclnt
+INCS += -I$(SRC)/lib/libsmbfs
+INCS += -I$(SRC)/lib/libsmbfs/netsmb
+
+CPPFLAGS += $(INCS)
+CPPFLAGS += -D_REENTRANT
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+CPPFLAGS += -D_LARGEFILE64_SOURCE=1
+CPPFLAGS += -DFKSMBCL
+# Always want DEBUG here
+CPPFLAGS += -DDEBUG
+
+CSTD= $(CSTD_GNU99)
+
+CFLAGS += $(CCVERBOSE)
+CFLAGS64 += $(CCVERBOSE)
+
+LDFLAGS += $(ZNOLAZYLOAD)
+LDFLAGS += -R/usr/lib/smbfs
+LDLIBS += -L$(ROOT)/usr/lib/smbfs
+LDLIBS += -lsmbfs -lfksmbfs -lfknsmb
+LDLIBS += -lsocket
+
+ROOTSMBDDIR = $(ROOTLIB)/smbfs
+ROOTSMBDFILE = $(PROG:%=$(ROOTSMBDDIR)/%)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ -$(RM) $(OBJS)
+
+# lots of lint due to mixing kernel+user stuff. give up.
+lint: # lint_SRCS
+
+include ../../../Makefile.targ
+
+install: all $(ROOTSMBDFILE)
+
+$(ROOTSMBDDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/README b/usr/src/cmd/fs.d/smbclnt/fksmbcl/README
new file mode 100644
index 0000000000..811401bc65
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/README
@@ -0,0 +1,99 @@
+
+#
+# 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.
+#
+
+This directory builds a program linking all of the SMB client code
+into a user-level process. The result is not a fully functional
+SMB client but is very useful for some kinds of development work.
+
+The architecture of this roughly parallels the in-kernel version,
+where the kernel modules are built as libraries including:
+ libfksmbfs, libfknsmb
+
+Just as with the kernel code, there are mdb modules that know
+how to walk data structures in libfksmbfs, etc.
+
+For debugging, etc. it's easiest to run this as a normal user,
+i.e. yourself (not root)
+
+Now you can run fksmbcl from the proto area using this script:
+ ./Run.sh -df
+
+You can also run it under dbx (see the .dbxrc file).
+To run it under mdb (with mdb modules build here):
+ mdb -L $ROOT/usr/lib/mdb/proc:/usr/lib/mdb/proc ...
+where ... is one of: fksmbcl, core.nnn, -p $PID
+
+There are also some dtrace scripts in here, and in ../dtrace
+for watching either all activity or only selected areas.
+Run these like: dtrace -s Watch-all.d -p $PID -o output
+
+These two (from over in ../dtrace) also work with fksmbcl:
+ dtrace -s fksmbcl.d -p `pgrep fksmbcl` -o output
+
+Here is the help output:
+
+ > help
+ Commands:
+ help
+ exit
+ logon [user [dom [pass]]]
+ logoff [close-driver]
+ shares
+ mount {share} [optstr]
+ umount
+ unmount
+ statfs
+ dir {rdir} [lfile]
+ dirx {rdir} [lfile]
+ get {rfile} [lfile]
+ put {lfile} [rfile]
+ mv {from} {to}
+ rm {rfile}
+ mkdir {rfile}
+ rmdir {rfile}
+ opt {option}
+
+
+Here is an example of how to connect, mount, and list a directory:
+
+ $ ./Run.sh //myserver
+ # Start with:
+ > logon [user [dom [pw]]]
+ > shares
+ > mount {share}
+
+ > logon test test test
+ > shares
+ open pipe: /srvsvc
+ enum strings
+ junk
+ c$
+ Default Share
+ test1
+ ipc$
+ Remote IPC
+ test
+ > mount test
+ > dir
+ 1224750917 .
+ 1224750917 ..
+ 900818955 test9.dat
+ 3908265151 lock1.txt
+ 2452346625 test_dir
+ > umount
+ > logoff
+ > exit
+ $
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh
new file mode 100755
index 0000000000..df731bf733
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Run.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+#
+# 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 program to run fksmbd (user-space smbd for debugging)
+# using binaries from the proto area.
+
+[ -n "$ROOT" ] || {
+ echo "Need a bldenv to set ROOT=..."
+ exit 1;
+}
+
+# OK, setup env. to run it.
+
+LD_LIBRARY_PATH=$ROOT/usr/lib/smbfs:$ROOT/usr/lib:$ROOT/lib
+export LD_LIBRARY_PATH
+
+# run with the passed options
+exec $ROOT/usr/lib/smbfs/fksmbcl "$@"
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d
new file mode 100644
index 0000000000..b36fd13d6f
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/Watch-fksmbcl.d
@@ -0,0 +1,68 @@
+#!/usr/sbin/dtrace -s
+/*
+ * 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 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * User-level dtrace for fksmbcl
+ * Usage: dtrace -s Watch-fksmbcl.d -p $PID
+ */
+
+/*
+ * If traced, print entry/return
+ */
+pid$target:fksmbcl::entry,
+pid$target:libsmbfs.so.1::entry,
+pid$target:libfksmbfs.so.1::entry,
+pid$target:libfknsmb.so.1::entry,
+pid$target:libfakekernel.so.1::entry
+{
+ printf("\t0x%x", arg0);
+ printf("\t0x%x", arg1);
+ printf("\t0x%x", arg2);
+ printf("\t0x%x", arg3);
+ printf("\t0x%x", arg4);
+ printf("\t0x%x", arg5);
+}
+
+pid$target:fksmbcl::return,
+pid$target:libsmbfs.so.1::return,
+pid$target:libfksmbfs.so.1::return,
+pid$target:libfknsmb.so.1::return,
+pid$target:libfakekernel.so.1::entry
+{
+ printf("\t0x%x", arg1);
+}
+
+pid$target::smbfslookup:entry
+{
+ printf("\tname = %s\n", copyinstr(arg1));
+}
+
+pid$target:libfknsmb.so.1:smb_dtrace2:entry
+/copyinstr(arg0) == "debugmsg2"/
+{
+ this->f = copyinstr(arg1);
+ this->m = copyinstr(arg2);
+ printf("\n\t debugmsg2: %s: %s ", this->f, this->m);
+}
+
+pid$target:libfknsmb.so.1:smb_dtrace3:entry
+/copyinstr(arg0) == "debugmsg3"/
+{
+ this->f = copyinstr(arg1);
+ this->m = copyinstr(arg2);
+ printf("\n\t debugmsg3: %s: %s ", this->f, this->m);
+ trace(arg3);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c
new file mode 100644
index 0000000000..34da749e78
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkdev.c
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file implements device open/close/ioctl wrappers that
+ * redirect access from the real "nsmb" device to the in-process
+ * device simulation in libfknsmb.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/byteorder.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <assert.h>
+#include <nss_dbdefs.h>
+
+#include <cflib.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include <libfknsmb/common/libfknsmb.h>
+
+#include "smb/charsets.h"
+#include "smb/private.h"
+
+int
+smb_open_driver(void)
+{
+ dev32_t dev;
+ int fd;
+ int rc;
+
+ rc = nsmb_drv_open(&dev, 0, 0);
+ if (rc != 0) {
+ errno = rc;
+ return (-1);
+ }
+
+ assert((dev & 0xFFFF0000) != 0);
+ fd = (int)dev;
+
+ return (fd);
+}
+
+int
+nsmb_ioctl(int fd, int cmd, void *arg)
+{
+ dev32_t dev;
+ int err;
+
+ dev = (dev32_t)fd;
+ assert((dev & 0xFFFF0000) != 0);
+ err = nsmb_drv_ioctl(dev, cmd, (intptr_t)arg, 0);
+ if (err != 0) {
+ errno = err;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+nsmb_close(int fd)
+{
+ dev32_t dev;
+
+ dev = (dev32_t)fd;
+ assert((dev & 0xFFFF0000) != 0);
+ (void) nsmb_drv_close(dev, 0, 0);
+ return (0);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c
new file mode 100644
index 0000000000..be26854bd3
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fkiod_cl.c
@@ -0,0 +1,150 @@
+/*
+ * 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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Client-side interface to the IO Daemon (IOD)
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <thread.h>
+
+#include <sys/byteorder.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include <assert.h>
+
+#include "smb/charsets.h"
+#include "smb/private.h"
+
+/*
+ * Make sure we don't call the real IOD here.
+ */
+int
+smb_iod_open_door(int *fdp)
+{
+ *fdp = -1;
+ return (ENOTSUP);
+}
+
+/*
+ * Get a door handle to the IOD...
+ */
+int
+smb_iod_start(smb_ctx_t *ctx)
+{
+ return (0);
+}
+
+void *
+iod_work(void *arg)
+{
+ smb_ctx_t *ctx = arg;
+ (void) smb_iod_work(ctx);
+ smb_ctx_free(ctx);
+ return (NULL);
+}
+
+/*
+ * Ask the IOD to connect using the info in ctx.
+ * Called by newvc.
+ *
+ * This function largely follows smbiod.c : iod_newvc()
+ */
+int
+smb_iod_cl_newvc(smb_ctx_t *cl_ctx)
+{
+ smb_ctx_t *ctx;
+ thread_t tid;
+ int err = 0;
+
+ /*
+ * Clone the context, like in smbiod.c
+ */
+ err = smb_ctx_alloc(&ctx);
+ if (err)
+ return (err);
+ bcopy(&cl_ctx->ct_iod_ssn, &ctx->ct_iod_ssn,
+ sizeof (ctx->ct_iod_ssn));
+
+ /*
+ * Create the driver session first...
+ */
+ if ((err = smb_ctx_gethandle(ctx)) != 0)
+ goto out;
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) {
+ err = errno;
+ if (err == EEXIST)
+ err = 0; /* see above */
+ goto out;
+ }
+
+ /*
+ * Do the initial connection setup here, so we can
+ * report the outcome to the door client.
+ */
+ err = smb_iod_connect(ctx);
+ if (err != 0) {
+ fprintf(stderr, "smb_iod_connect, err=%d\n", err);
+ goto out;
+ }
+
+ /* The rest happens in the iod_work thread. */
+ err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid);
+ if (err == 0) {
+ /*
+ * Given to the new thread.
+ * free at end of iod_work
+ */
+ ctx = NULL;
+ }
+
+out:
+ if (ctx != NULL)
+ smb_ctx_free(ctx);
+
+ return (err);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c
new file mode 100644
index 0000000000..7f66b3b5bb
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fknewvc.c
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+/*
+ * Create a new VC given a list of addresses.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "smb/charsets.h"
+#include "smb/private.h"
+
+/*
+ * Ask the IOD to create a VC with this IP address.
+ */
+static int
+fknewvc(struct smb_ctx *ctx, struct addrinfo *ai)
+{
+ char host[256];
+ char svc[32];
+ smbioc_ossn_t *ssn = &ctx->ct_ssn;
+ int err;
+
+ if (smb_debug) {
+ err = getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ host, sizeof (host), svc, sizeof (svc),
+ AI_NUMERICHOST);
+ if (err != 0) {
+ strlcpy(host, "(?)", sizeof (host));
+ strlcpy(svc, "?", sizeof (host));
+ }
+ printf("fknewvc: Try AF=%d %s:%s\n",
+ ai->ai_family, host, svc);
+ }
+
+ /*
+ * Copy the passed address into ssn_srvaddr,
+ * but first sanity-check lengths. Also,
+ * zero it first to avoid trailing junk.
+ */
+ if (ai->ai_addrlen > sizeof (ssn->ssn_srvaddr))
+ return (EINVAL);
+ bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
+ bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
+
+ /* Ask the IOD to connect using the info in ctx. */
+ err = smb_iod_cl_newvc(ctx);
+ if (smb_debug) {
+ printf("fknewvc: iod_cl_newvc err=%d\n", err);
+ }
+
+ return (err);
+}
+
+/*
+ * Setup a new VC via the IOD.
+ * Similar to findvc.c
+ */
+int
+smb_ctx_newvc(struct smb_ctx *ctx)
+{
+ struct addrinfo *ai;
+ int err;
+
+ /* Should already have the address list. */
+ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+ return (EINVAL);
+
+ err = EPROTONOSUPPORT; /* in case no AF match */
+ for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) {
+
+ switch (ai->ai_family) {
+
+ case AF_INET:
+ case AF_INET6:
+ case AF_NETBIOS:
+ err = fknewvc(ctx, ai);
+ if (err == 0)
+ return (0);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * In the error case, the caller may try again
+ * with new auth. info, so keep the door open.
+ * Error return will close in smb_ctx_done.
+ */
+ return (err);
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c
new file mode 100644
index 0000000000..8b1757ea62
--- /dev/null
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/fksmbcl_main.c
@@ -0,0 +1,938 @@
+/*
+ * 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 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Test & debug program for the SMB client
+ *
+ * This implements a simple command reader which accepts
+ * commands to simulate system calls into the file system.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/dirent.h>
+#include <sys/strlog.h> /* SL_NOTE */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <sys/fs/smbfs_mount.h>
+#include <netsmb/smb_lib.h>
+#include <libfknsmb/common/libfknsmb.h>
+#include <libfksmbfs/common/libfksmbfs.h>
+
+#if _FILE_OFFSET_BITS != 64
+#error "This calls (fake) VFS code which requires 64-bit off_t"
+#endif
+
+extern int list_shares(struct smb_ctx *);
+
+#define MAXARG 10
+
+struct cmd_tbl_ent {
+ void (*ce_func)(int, char **);
+ const char *ce_name;
+ const char *ce_argdesc;
+};
+static struct cmd_tbl_ent cmd_tbl[];
+
+static struct smb_ctx *ctx = NULL;
+static char *server = NULL;
+
+static vfs_t *vfsp = NULL;
+
+static void show_dents(vnode_t *, offset_t *, char *, int);
+static void run_cli(void);
+
+#define TBUFSZ 8192
+static char tbuf[TBUFSZ];
+
+static void
+fksmbcl_usage(void)
+{
+ printf("usage: fksmbcl //user@server (like smbutil)\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int error, opt;
+
+ /*
+ * Initializations
+ */
+ nsmb_drv_load();
+ nsmb_drv_init();
+ fksmbfs_init();
+
+ while ((opt = getopt(argc, argv, "dv")) != -1) {
+ switch (opt) {
+ case 'd':
+ smb_debug++;
+ break;
+ case 'v':
+ smb_verbose++;
+ break;
+ case '?':
+ fksmbcl_usage();
+ break;
+ }
+ }
+ if (optind >= argc)
+ fksmbcl_usage();
+ server = argv[optind];
+
+ /*
+ * Setup the libsmbfs context
+ */
+ error = smb_ctx_alloc(&ctx);
+ if (error) {
+ fprintf(stderr, "%s: smb_ctx_alloc failed (%d)\n",
+ argv[0], error);
+ return (1);
+ }
+
+ error = smb_ctx_scan_argv(ctx, argc, argv,
+ SMBL_SERVER, SMBL_SERVER, USE_WILDCARD);
+ if (error) {
+ fprintf(stderr, "logon: smb_ctx_scan_argv, error %d\n", error);
+ return (1);
+ }
+ error = smb_ctx_readrc(ctx);
+ if (error) {
+ fprintf(stderr, "logon: smb_ctx_readrc, error %d\n", error);
+ return (1);
+ }
+
+ /* Do smb_ctx_setshare later, and smb_ctx_resolve. */
+
+ /*
+ * Next would be smb_ctx_get_ssn() but don't do that until
+ * the "logon" command so one can set breakpoints etc.
+ */
+
+ /*
+ * Run the CLI
+ */
+ run_cli();
+
+ /*
+ * Cleanup
+ */
+ fksmbfs_fini();
+ nsmb_drv_fini();
+
+ return (0);
+}
+
+static void
+run_cli()
+{
+ static char cmdbuf[100];
+ int argc, i;
+ char *argv[MAXARG];
+ char *cmd;
+ char *savep = NULL;
+ char *sep = " \t\n";
+ char *prompt = NULL;
+ struct cmd_tbl_ent *ce;
+
+ if (isatty(0)) {
+ fputs("# Start with:\n"
+ "> logon [user [dom [pw]]]\n"
+ "> shares\n"
+ "> mount {share}\n\n",
+ stdout);
+ prompt = "> ";
+ }
+
+ for (;;) {
+ if (prompt) {
+ fputs(prompt, stdout);
+ fflush(stdout);
+ }
+
+ cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin);
+ if (cmd == NULL)
+ break;
+ if (cmd[0] == '#')
+ continue;
+
+ if (prompt == NULL) {
+ /* Put commands in the output too. */
+ fprintf(stdout, "+ %s", cmdbuf);
+ }
+
+ argv[0] = strtok_r(cmd, sep, &savep);
+ if (argv[0] == NULL)
+ continue;
+ for (argc = 1; argc < MAXARG; argc++) {
+ argv[argc] = strtok_r(NULL, sep, &savep);
+ if (argv[argc] == NULL)
+ break;
+ }
+ for (i = argc; i < MAXARG; i++)
+ argv[i++] = NULL;
+
+ for (ce = cmd_tbl; ce->ce_name != NULL; ce++)
+ if (strcmp(ce->ce_name, argv[0]) == 0)
+ break;
+ if (ce->ce_name != NULL) {
+ ce->ce_func(argc, argv);
+ } else {
+ fprintf(stderr, "%s unknown command. Try help\n",
+ argv[0]);
+ }
+ }
+}
+
+/*
+ * Command handlers
+ */
+
+static void
+do_exit(int argc, char **argv)
+{
+ exit(0);
+}
+
+static void
+do_help(int argc, char **argv)
+{
+ struct cmd_tbl_ent *ce;
+
+ printf("Commands:\n");
+ for (ce = cmd_tbl; ce->ce_func != NULL; ce++)
+ printf("%s %s\n", ce->ce_name, ce->ce_argdesc);
+}
+
+static void
+do_logon(int argc, char **argv)
+{
+ int error;
+
+ if (argc > 1) {
+ if (argv[1][0] == '-') {
+ smb_ctx_setuser(ctx, "", B_TRUE);
+ ctx->ct_flags |= SMBCF_NOPWD;
+ } else {
+ smb_ctx_setuser(ctx, argv[1], B_TRUE);
+ }
+ }
+ if (argc > 2)
+ smb_ctx_setdomain(ctx, argv[2], B_TRUE);
+ if (argc > 3)
+ smb_ctx_setpassword(ctx, argv[3], NULL);
+
+ /*
+ * Resolve the server address, setup derived defaults.
+ */
+ error = smb_ctx_resolve(ctx);
+ if (error) {
+ fprintf(stderr, "logon: smb_ctx_resolve, error %d\n", error);
+ return;
+ }
+
+ /*
+ * Have server, share, etc. now.
+ * Get the logon session.
+ */
+again:
+ error = smb_ctx_get_ssn(ctx);
+ if (error == EAUTH) {
+ int err2;
+ err2 = smb_get_authentication(ctx);
+ if (err2 == 0)
+ goto again;
+ }
+ if (error) {
+ fprintf(stderr, "//%s: login failed, error %d\n",
+ ctx->ct_fullserver, error);
+ }
+}
+
+/*
+ * Drop session created by the "logon" command.
+ */
+static void
+do_logoff(int argc, char **argv)
+{
+
+ (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_RELE, NULL);
+ if (argc > 1) {
+ smb_ctx_done(ctx);
+ (void) smb_ctx_init(ctx);
+ }
+}
+
+/*
+ * List shares
+ */
+static void
+do_shares(int argc, char **argv)
+{
+ int error;
+
+ smb_ctx_setshare(ctx, "IPC$", USE_IPC);
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ fprintf(stderr, "shares, tcon IPC$, error=%d\n", error);
+ return;
+ }
+
+ error = list_shares(ctx);
+ if (error) {
+ fprintf(stderr, "shares, enum, error=%d\n", error);
+ }
+
+ (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL);
+}
+
+char mnt_opt_buf[MAX_MNTOPT_STR];
+char mnt_resource[MAXPATHLEN];
+
+/*
+ * Minimal excerpt from vfs.c:domount()
+ */
+void
+do_mount(int argc, char **argv)
+{
+ struct smbfs_args mdata;
+ struct mounta ma;
+ char *shrname;
+ int error;
+
+ if (vfsp != NULL) {
+ fprintf(stderr, "Already mounted\n");
+ return;
+ }
+
+ if (argc < 2) {
+ fprintf(stderr, "%s: missing share name\n", argv[0]);
+ return;
+ }
+ shrname = argv[1];
+ if (argc > 2)
+ strlcpy(mnt_opt_buf, argv[2], sizeof (mnt_opt_buf));
+ else
+ memset(mnt_opt_buf, 0, sizeof (mnt_opt_buf));
+
+ smb_ctx_setshare(ctx, shrname, USE_DISKDEV);
+ error = smb_ctx_get_tree(ctx);
+ if (error) {
+ fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
+ server, shrname, error);
+ return;
+ }
+
+ (void) snprintf(mnt_resource, sizeof (mnt_resource),
+ "//%s/%s", ctx->ct_fullserver, shrname);
+
+ bzero(&mdata, sizeof (mdata));
+ mdata.version = SMBFS_VERSION; /* smbfs mount version */
+ mdata.file_mode = S_IRWXU;
+ mdata.dir_mode = S_IRWXU;
+ mdata.devfd = ctx->ct_dev_fd;
+
+ /* Build mount args */
+ bzero(&ma, sizeof (ma));
+ ma.spec = mnt_resource;
+ ma.dir = "/";
+ ma.flags = MS_DATA | MS_OPTIONSTR | MS_NOSPLICE | MS_NOSUID;
+ ma.fstype = "smbfs";
+ ma.dataptr = (void *) &mdata;
+ ma.datalen = sizeof (mdata);
+ ma.optptr = mnt_opt_buf;
+ ma.optlen = sizeof (mnt_opt_buf);
+
+ error = fake_domount("smbfs", &ma, &vfsp);
+ if (error != 0) {
+ fprintf(stderr, "domount error=%d\n", error);
+ }
+
+ /* Mount takes a ref, so always rele here. */
+ (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL);
+}
+
+void
+do_unmount(int argc, char **argv)
+{
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "Not mounted\n");
+ return;
+ }
+
+ error = fake_dounmount(vfsp, 0);
+ if (error != 0) {
+ fprintf(stderr, "dounmount error=%d\n", error);
+ return;
+ }
+ vfsp = NULL;
+}
+
+void
+do_statfs(int argc, char **argv)
+{
+ statvfs64_t st;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "Not mounted\n");
+ return;
+ }
+
+ error = fsop_statfs(vfsp, &st);
+ if (error != 0) {
+ fprintf(stderr, "df error=%d\n", error);
+ return;
+ }
+ printf("bsize=%ld\n", st.f_bsize);
+ printf("frsize=%ld\n", st.f_frsize);
+ printf("blocks=%" PRIu64 "\n", st.f_blocks);
+ printf(" bfree=%" PRIu64 "\n", st.f_bfree);
+ printf("bavail=%" PRIu64 "\n", st.f_bavail);
+}
+
+void
+do_dir(int argc, char **argv)
+{
+ char *rdir;
+ vnode_t *vp = NULL;
+ offset_t off;
+ int cnt;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc > 1)
+ rdir = argv[1];
+ else
+ rdir = "";
+
+ error = vn_open(rdir, 0, FREAD, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_dir, vn_open error=%d\n", error);
+ return;
+ }
+
+ off = 0;
+ do {
+ cnt = fake_getdents(vp, &off, tbuf, TBUFSZ);
+ if (cnt < 0) {
+ fprintf(stderr, "do_dir, getdents %d\n", -cnt);
+ break;
+ }
+ show_dents(vp, &off, tbuf, cnt);
+ } while (cnt > 0);
+
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+}
+
+void
+do_dirx(int argc, char **argv)
+{
+ char *rdir;
+ vnode_t *vp = NULL;
+ offset_t off;
+ int cnt;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc > 1)
+ rdir = argv[1];
+ else
+ rdir = "";
+
+ error = vn_open(rdir, 0, FREAD|FXATTRDIROPEN, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_dirx, vn_open error=%d\n", error);
+ return;
+ }
+
+ off = 0;
+ do {
+ cnt = fake_getdents(vp, &off, tbuf, TBUFSZ);
+ if (cnt < 0) {
+ fprintf(stderr, "do_dirx, getdents %d\n", -cnt);
+ break;
+ }
+ show_dents(vp, &off, tbuf, cnt);
+ } while (cnt > 0);
+
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+}
+
+static void
+show_dents(vnode_t *dvp, offset_t *offp, char *buf, int cnt)
+{
+ char time_buf[40];
+ struct stat64 st;
+ vnode_t *vp;
+ char *p;
+ dirent_t *d;
+ offset_t offset = (offset_t)-1L;
+ int error;
+ uint_t mode;
+ char type;
+
+ p = buf;
+ while (p < (buf + cnt)) {
+ d = (dirent_t *)(void *)p;
+ p += d->d_reclen;
+ offset = d->d_off;
+
+ error = fake_lookup(dvp, d->d_name, &vp);
+ if (error != 0) {
+ fprintf(stderr, "%s: lookup error=%d\n",
+ d->d_name, error);
+ continue;
+ }
+ error = fake_stat(vp, &st, 0);
+ vn_rele(vp);
+ if (error != 0) {
+ fprintf(stderr, "%s: stat error=%d\n",
+ d->d_name, error);
+ continue;
+ }
+
+ /*
+ * Print type, mode, size, name
+ * First mode (only dir, file expected here)
+ */
+ if (S_ISDIR(st.st_mode)) {
+ type = 'd';
+ } else if (S_ISREG(st.st_mode)) {
+ type = ' ';
+ } else {
+ type = '?';
+ }
+ mode = st.st_mode & 0777;
+ (void) strftime(time_buf, sizeof (time_buf),
+ "%b %e %T %Y", localtime(&st.st_mtime));
+
+ printf("%c 0%3o %9" PRIu64 " %s %s\n",
+ type, mode,
+ (uint64_t)st.st_size,
+ time_buf,
+ d->d_name);
+ }
+ *offp = offset;
+}
+
+/*
+ * get rname [lname]
+ */
+void
+do_get(int argc, char **argv)
+{
+ struct stat64 st;
+ char *rname;
+ char *lname;
+ vnode_t *vp = NULL;
+ offset_t off;
+ ssize_t cnt, x;
+ int oflg = O_RDWR | O_CREAT;
+ int lfd = -1;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+ if (argc > 2) {
+ lname = argv[2];
+ /*
+ * When local name is specified, overwrite.
+ * Convenient for scripts etc.
+ */
+ oflg |= O_TRUNC;
+ } else {
+ lname = rname;
+ /* Local file should not exist. */
+ oflg |= O_EXCL;
+ }
+
+ lfd = open(lname, oflg, 0644);
+ if (lfd < 0) {
+ perror(lname);
+ return;
+ }
+
+ error = vn_open(rname, 0, FREAD, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_get, vn_open error=%d\n", error);
+ goto out;
+ }
+ error = fake_stat(vp, &st, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_get, stat error=%d\n", error);
+ goto out;
+ }
+
+ off = 0;
+ do {
+ cnt = fake_pread(vp, tbuf, TBUFSZ, off);
+ if (cnt < 0) {
+ fprintf(stderr, "do_get, read %d\n", -cnt);
+ goto out;
+ }
+ x = write(lfd, tbuf, cnt);
+ if (x < 0) {
+ fprintf(stderr, "do_get, write %d\n", errno);
+ goto out;
+ }
+ off += x;
+ } while (off < st.st_size);
+
+out:
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+ if (lfd != -1)
+ close(lfd);
+}
+
+/*
+ * put lname [rname]
+ */
+void
+do_put(int argc, char **argv)
+{
+ struct stat64 rst;
+ struct stat st;
+ char *rname;
+ char *lname;
+ vnode_t *vp = NULL;
+ offset_t off;
+ ssize_t cnt, x;
+ int oflg = FREAD|FWRITE|FCREAT;
+ int lfd = -1;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "lname required\n");
+ return;
+ }
+ lname = argv[1];
+ if (argc > 2) {
+ rname = argv[2];
+ /*
+ * When remote name is specified, overwrite.
+ * Convenient for scripts etc.
+ */
+ oflg |= FTRUNC;
+ } else {
+ rname = lname;
+ /* Remote file should not exist. */
+ oflg |= FEXCL;
+ }
+
+ lfd = open(lname, O_RDONLY, 0);
+ if (lfd < 0) {
+ perror(lname);
+ return;
+ }
+ error = fstat(lfd, &st);
+ if (error != 0) {
+ fprintf(stderr, "do_put, stat error=%d\n", error);
+ goto out;
+ }
+
+ error = vn_open(rname, 0, oflg, 0, &vp, 0, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_put, vn_open error=%d\n", error);
+ goto out;
+ }
+
+ off = 0;
+ do {
+ cnt = pread(lfd, tbuf, TBUFSZ, off);
+ if (cnt < 0) {
+ fprintf(stderr, "do_put, read %d\n", errno);
+ goto out;
+ }
+ x = fake_pwrite(vp, tbuf, cnt, off);
+ if (x < 0) {
+ fprintf(stderr, "do_put, write %d\n", -x);
+ goto out;
+ }
+ off += cnt;
+ } while (off < st.st_size);
+
+ /* This getattr should go OtW. */
+ error = fake_stat(vp, &rst, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_put, stat error=%d\n", error);
+ goto out;
+ }
+ if (rst.st_size != st.st_size) {
+ fprintf(stderr, "do_put, wrong size?\n");
+ }
+
+out:
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+ if (lfd != -1)
+ close(lfd);
+}
+
+/*
+ * rm rname
+ */
+void
+do_rm(int argc, char **argv)
+{
+ char *rname;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+
+ error = fake_unlink(rname, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_rm, unlink error=%d\n", error);
+ }
+}
+
+/*
+ * mv fromname toname
+ */
+void
+do_mv(int argc, char **argv)
+{
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 3) {
+ fprintf(stderr, "from_name to_name required\n");
+ return;
+ }
+
+ error = fake_rename(argv[1], argv[2]);
+ if (error != 0) {
+ fprintf(stderr, "do_mv, rename error=%d\n", error);
+ }
+}
+
+/*
+ * mkdir rname
+ */
+void
+do_mkdir(int argc, char **argv)
+{
+ char *rname;
+ vnode_t *vp = NULL;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+
+ error = vn_open(rname, 0, FCREAT, 0, &vp, CRMKDIR, 0);
+ if (error != 0) {
+ fprintf(stderr, "do_mkdir, vn_open error=%d\n", error);
+ }
+
+ if (vp != NULL)
+ vn_close_rele(vp, 0);
+}
+
+/*
+ * rmdir rname
+ */
+void
+do_rmdir(int argc, char **argv)
+{
+ char *rname;
+ int error;
+
+ if (vfsp == NULL) {
+ fprintf(stderr, "mnt required first\n");
+ return;
+ }
+ if (argc < 2) {
+ fprintf(stderr, "rname required\n");
+ return;
+ }
+ rname = argv[1];
+
+ error = fake_unlink(rname, AT_REMOVEDIR);
+ if (error != 0) {
+ fprintf(stderr, "do_rmdir, unlink error=%d\n", error);
+ }
+}
+
+/*
+ * Simple option setting
+ *
+ * Each arg is handled as one line in .nsmbrc [default]
+ */
+void
+do_opt(int argc, char **argv)
+{
+ static char template[20] = "/tmp/fksmbclXXXXXX";
+ static char rcname[30];
+ char *tdname;
+ char *save_home;
+ FILE *fp;
+ int err, i;
+
+ if (argc < 2) {
+ fprintf(stderr, "opt {key}[=value]\n");
+ return;
+ }
+
+ tdname = mkdtemp(template);
+ if (tdname == NULL) {
+ perror("mkdtemp");
+ return;
+ }
+ (void) snprintf(rcname, sizeof (rcname),
+ "%s/.nsmbrc", tdname);
+
+ fp = fopen(rcname, "w");
+ if (fp == NULL) {
+ perror(rcname);
+ goto out;
+ }
+ fprintf(fp, "[default]\n");
+ for (i = 1; i < argc; i++)
+ fprintf(fp, "%s\n", argv[i]);
+ fclose(fp);
+
+ save_home = ctx->ct_home;
+ ctx->ct_home = tdname;
+ err = smb_ctx_readrc(ctx);
+ ctx->ct_home = save_home;
+
+ if (err != 0)
+ fprintf(stderr, "readrc, err=%d\n", err);
+
+out:
+ (void) unlink(rcname);
+ (void) rmdir(tdname);
+}
+
+/*
+ * Command table
+ */
+static struct cmd_tbl_ent
+cmd_tbl[] = {
+ { do_help, "help", "" },
+ { do_exit, "exit", "" },
+ { do_logon, "logon", "[user [dom [pass]]]" },
+ { do_logoff, "logoff", "[close-driver]" },
+ { do_shares, "shares", "" },
+ { do_mount, "mount", "{share} [optstr]" },
+ { do_unmount, "umount", "" },
+ { do_unmount, "unmount", "" },
+ { do_statfs, "statfs", "" },
+ { do_dir, "dir", "{rdir} [lfile]" },
+ { do_dirx, "dirx", "{rdir} [lfile]" },
+ { do_get, "get", "{rfile} [lfile]" },
+ { do_put, "put", "{lfile} [rfile]" },
+ { do_mv, "mv", "{from} {to}" },
+ { do_rm, "rm", "{rfile}" },
+ { do_mkdir, "mkdir", "{rfile}" },
+ { do_rmdir, "rmdir", "{rfile}" },
+ { do_opt, "opt", "{option}" },
+ { NULL, NULL, NULL }
+};
+
+/*
+ * Provide a real function (one that prints something) to replace
+ * the stub in libfakekernel. This prints cmn_err() messages.
+ */
+void
+fakekernel_putlog(char *msg, size_t len, int flags)
+{
+
+ /*
+ * [CE_CONT, CE_NOTE, CE_WARN, CE_PANIC] maps to
+ * [SL_NOTE, SL_NOTE, SL_WARN, SL_FATAL]
+ */
+ if (smb_debug == 0 && (flags & SL_NOTE))
+ return;
+ (void) fwrite(msg, 1, len, stdout);
+ (void) fflush(stdout);
+}
+
+/*
+ * Print nsmb debug messages via driver smb_debugmsg()
+ */
+void
+smb_debugmsg(const char *func, char *msg)
+{
+ if (smb_debug < 2)
+ return;
+ printf("[kmod] %s: %s\n", func, msg);
+}
+
+/*
+ * Enable libumem debugging
+ */
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
diff --git a/usr/src/cmd/fs.d/smbclnt/test/srvenum.c b/usr/src/cmd/fs.d/smbclnt/fksmbcl/shares.c
index ee3aeba014..2d8d0cf6da 100644
--- a/usr/src/cmd/fs.d/smbclnt/test/srvenum.c
+++ b/usr/src/cmd/fs.d/smbclnt/fksmbcl/shares.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 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,27 +36,17 @@
#include <string.h>
#include <unistd.h>
#include <libintl.h>
+#include <ctype.h>
-#include <netsmb/smbfs_api.h>
+#include <netsmb/smb_lib.h>
/*
* This is a quick hack for testing client-side named pipes.
- * Its purpose is to test the ability to connect to a server,
- * open a pipe, send and receive data. The "hack" aspect is
- * the use of hand-crafted RPC messages, which allows testing
- * of the named pipe API separately from the RPC libraries.
- *
- * I captured the two small name pipe messages sent when
- * requesting a share list via RPC over /pipe/srvsvc and
- * dropped them into the arrays below (bind and enum).
- * This program sends the two messages (with adjustments)
- * and just dumps whatever comes back over the pipe.
- * Use wireshark if you want to see decoded messages.
+ * Its purpose is to test SMB named-pipe interface separately
+ * from the RPC implementation. It's a "hack" because it uses
+ * hand-crafted RPC messages (extracted from network traffic).
*/
-extern char *optarg;
-extern int optind, opterr, optopt;
-
/* This is a DCE/RPC bind call for "srvsvc". */
static const uchar_t
srvsvc_bind[] = {
@@ -95,175 +85,35 @@ srvsvc_enum2[] = {
static uchar_t sendbuf[1024];
static uchar_t recvbuf[4096];
-static char *server;
-
-static int pipetest(struct smb_ctx *);
+/*
+ * Print strings found in the buffer.
+ */
static void
-srvenum_usage(void)
+pstrings(const uchar_t *buf, int len)
{
- printf("usage: srvenum [-d domain][-u user][-p passwd] server\n");
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int c, error;
- struct smb_ctx *ctx = NULL;
- char *dom = NULL;
- char *usr = NULL;
- char *pw = NULL;
-
- while ((c = getopt(argc, argv, "vd:u:p:")) != -1) {
- switch (c) {
- case 'v':
- smb_verbose = 1;
- break;
-
- case 'd':
- dom = optarg;
- break;
- case 'u':
- usr = optarg;
- break;
- case 'p':
- pw = optarg;
- break;
- case '?':
- srvenum_usage();
- break;
+ const uchar_t *p = buf;
+ uint16_t u2;
+ boolean_t instr = B_FALSE;
+
+ while (len > 2) {
+ u2 = *p++;
+ u2 |= (*p++) << 8;
+ len -= 2;
+
+ if ((u2 & 0xFF80) == 0 && isprint(u2)) {
+ /* printable */
+ instr = B_TRUE;
+ putchar(u2);
+ } else {
+ /* not printalbe */
+ if (instr)
+ putchar('\n');
+ instr = B_FALSE;
}
}
- if (optind >= argc)
- srvenum_usage();
- server = argv[optind];
-
- if (pw != NULL && (dom == NULL || usr == NULL)) {
- fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
- argv[0]);
- srvenum_usage();
- }
-
- /*
- * This section is intended to demonstrate how an
- * RPC client library might use this interface.
- */
- error = smb_ctx_alloc(&ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Set server, share, domain, user
- * (in the ctx handle).
- */
- smb_ctx_setfullserver(ctx, server);
- smb_ctx_setshare(ctx, "IPC$", USE_IPC);
- if (dom)
- smb_ctx_setdomain(ctx, dom, B_TRUE);
- if (usr)
- smb_ctx_setuser(ctx, usr, B_TRUE);
- if (pw)
- smb_ctx_setpassword(ctx, pw, NULL);
-
-
- /*
- * If this code were in smbutil or mount_smbfs, it would
- * get system and $HOME/.nsmbrc settings here, like this:
- */
-#if 0
- error = smb_ctx_readrc(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_readrc failed\n", argv[0]);
- goto out;
- }
-#endif
-
- /*
- * Resolve the server address,
- * setup derived defaults.
- */
- error = smb_ctx_resolve(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Get the session and tree.
- */
- error = smb_ctx_get_ssn(ctx);
- if (error) {
- fprintf(stderr, "//%s: login failed, error %d\n",
- server, error);
- goto out;
- }
- error = smb_ctx_get_tree(ctx);
- if (error) {
- fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
- server, "IPC$", error);
- goto out;
- }
-
- /*
- * Do some named pipe I/O.
- */
- error = pipetest(ctx);
- if (error) {
- fprintf(stderr, "pipetest, %d\n", error);
- goto out;
- }
-
-out:
- smb_ctx_free(ctx);
-
- return ((error) ? 1 : 0);
-}
-
-static void
-hexdump(const uchar_t *buf, int len) {
- int idx;
- char ascii[24];
- char *pa = ascii;
-
- memset(ascii, '\0', sizeof (ascii));
-
- idx = 0;
- while (len--) {
- if ((idx & 15) == 0) {
- printf("[%04X] ", idx);
- pa = ascii;
- }
- if (*buf > ' ' && *buf <= '~')
- *pa++ = *buf;
- else
- *pa++ = '.';
- printf("%02x ", *buf++);
-
- idx++;
- if ((idx & 7) == 0) {
- *pa++ = ' ';
- putchar(' ');
- }
- if ((idx & 15) == 0) {
- *pa = '\0';
- printf("%s\n", ascii);
- }
- }
-
- if ((idx & 15) != 0) {
- *pa = '\0';
- /* column align the last ascii row */
- do {
- printf(" ");
- idx++;
- if ((idx & 7) == 0)
- putchar(' ');
- } while ((idx & 15) != 0);
- printf("%s\n", ascii);
- }
+ if (instr)
+ putchar('\n');
}
/*
@@ -309,10 +159,6 @@ do_bind(int fid)
printf("xact bind, err=%d\n", err);
return (err);
}
- if (smb_verbose) {
- printf("bind ack, len=%d\n", len);
- hexdump(recvbuf, len);
- }
if (more > 0) {
if (more > sizeof (recvbuf)) {
printf("bogus more=%d\n", more);
@@ -325,17 +171,13 @@ do_bind(int fid)
printf("read enum resp, err=%d\n", err);
return (err);
}
- if (smb_verbose) {
- printf("bind ack (more), len=%d\n", len);
- hexdump(recvbuf, len);
- }
}
return (0);
}
static int
-do_enum(int fid)
+do_enum(char *server, int fid)
{
int err, len, rlen, wlen;
uchar_t *p;
@@ -393,18 +235,22 @@ do_enum(int fid)
return (err);
}
- /* Just dump the response data. */
- printf("enum recv, len=%d\n", rlen);
- hexdump(recvbuf, rlen);
+ /*
+ * Just dump strings found in the response data.
+ * Skip the first 0x90 (RPC wrappers).
+ */
+ printf("enum strings\n");
+ pstrings(recvbuf + 0x90, rlen - 0x90);
return (0);
}
-static int
-pipetest(struct smb_ctx *ctx)
+int
+list_shares(struct smb_ctx *ctx)
{
static char path[] = "/srvsvc";
static uchar_t key[16];
+ char *server = ctx->ct_srvname;
int err, fd;
printf("open pipe: %s\n", path);
@@ -426,7 +272,7 @@ pipetest(struct smb_ctx *ctx)
printf("do_bind: %d\n", err);
goto out;
}
- err = do_enum(fd);
+ err = do_enum(server, fd);
if (err)
printf("do_enum: %d\n", err);
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
index ae9dd15817..3a852c6978 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile
@@ -23,7 +23,7 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
# Copyright (c) 2018, Joyent, Inc.
#
@@ -34,7 +34,7 @@
PROG= smbutil
OBJS= smbutil.o discon.o info.o login.o lookup.o print.o status.o view.o \
- shares_rap.o shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o
+ shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o
SRCS= $(OBJS:%.o=%.c)
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c b/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c
deleted file mode 100644
index f2235e2880..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/shares_rap.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2000-2002, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: Id: view.c,v 1.9 2002/02/20 09:26:42 bp Exp
- */
-
-/*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <netsmb/mchain.h> /* letohs, etc. */
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/smb_rap.h>
-
-#include "common.h"
-
-/*
- * Enumerate shares using Remote Administration Protocol (RAP)
- * Was in libsmbfs netshareenum.c
- */
-
-struct smb_share_info_1 {
- char shi1_netname[13];
- char shi1_pad;
- uint16_t shi1_type;
- uint32_t shi1_remark; /* char * */
-};
-
-static int
-smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
- int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
-{
- struct smb_rap *rap;
- long lval = -1;
- int error;
-
- error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
- if (error)
- return (error);
- smb_rap_setNparam(rap, sLevel); /* W - sLevel */
- smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */
- smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */
- error = smb_rap_request(rap, ctx);
- if (error == 0) {
- *pcEntriesRead = rap->r_entries;
- error = smb_rap_getNparam(rap, &lval);
- *pcTotalAvail = lval;
- /* Copy the data length into the IN/OUT variable. */
- *cbBuffer = rap->r_rcvbuflen;
- }
- error = smb_rap_error(rap, error);
- smb_rap_done(rap);
- return (error);
-}
-
-int
-share_enum_rap(smb_ctx_t *ctx)
-{
- struct smb_share_info_1 *shi;
- void *rpbuf;
- char *cp;
- int error, bufsize, i, rcnt, total;
- int lbound, rbound;
- uint16_t type;
-
- bufsize = 0xffe0; /* samba notes win2k bug for 65535 */
- rpbuf = malloc(bufsize);
- if (rpbuf == NULL)
- return (errno);
-
- error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &rcnt, &total);
- if (error &&
- error != (ERROR_MORE_DATA | SMB_RAP_ERROR))
- goto out;
-
- /*
- * Bounds for offsets to comments strings.
- * After the array, and before the end.
- */
- lbound = rcnt * (sizeof (struct smb_share_info_1));
- rbound = bufsize;
-
- /* Print the header line. */
- view_print_share(NULL, 0, NULL);
-
- for (shi = rpbuf, i = 0; i < rcnt; i++, shi++) {
- type = letohs(shi->shi1_type);
-
- shi->shi1_pad = '\0'; /* ensure null termination */
-
- /*
- * Offsets to comment strings can be trash.
- * Only print when the offset is valid.
- */
- if (shi->shi1_remark >= lbound &&
- shi->shi1_remark < rbound) {
- cp = (char *)rpbuf + shi->shi1_remark;
- } else
- cp = NULL;
-
- /* Convert from OEM to local codeset? */
- view_print_share(shi->shi1_netname, type, cp);
- }
- error = 0;
-
-out:
- free(rpbuf);
- return (error);
-}
diff --git a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
index bf3397c166..18f0488ad3 100644
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.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 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -51,8 +51,6 @@
#include <netsmb/smb_lib.h>
#include "common.h"
-static int use_rap;
-
void
view_usage(void)
{
@@ -86,15 +84,6 @@ cmd_view(int argc, char *argv[])
while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) {
if (opt == '?')
view_usage();
- /*
- * This is an undocumented option, just for testing.
- * Use the old LanMan Remote API Protocol (RAP) for
- * enumerating shares.
- */
- if (opt == 'B') {
- use_rap++;
- continue;
- }
error = smb_ctx_opt(ctx, opt, optarg);
if (error)
goto out;
@@ -137,12 +126,8 @@ again:
/*
* Have IPC$ tcon, now list shares.
- * Try RPC; if that fails, do RAP.
*/
- if (!use_rap)
- error = share_enum_rpc(ctx, ctx->ct_fullserver);
- if (error || use_rap)
- error = share_enum_rap(ctx);
+ error = share_enum_rpc(ctx, ctx->ct_fullserver);
out:
smb_ctx_free(ctx);
diff --git a/usr/src/cmd/fs.d/smbclnt/test/Makefile b/usr/src/cmd/fs.d/smbclnt/test/Makefile
deleted file mode 100644
index affd6d9a00..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/test/Makefile
+++ /dev/null
@@ -1,85 +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 2013 Nexenta Systems, Inc. All rights reserved.
-# Copyright (c) 2019, Joyent, Inc.
-#
-
-include $(SRC)/cmd/Makefile.cmd
-
-PROG= srvenum srvinfo tconn
-OBJS = $(PROG:%=%.o)
-SRCS = $(OBJS:%.o=%.c)
-
-# ROOTFS_PROG= $(LIBPROG)
-# include ../../Makefile.fstype
-
-ROOTOPTPKG = $(ROOT)/opt/smbcl-tests
-TESTDIR = $(ROOTOPTPKG)/tests
-INST_CMDS = $(PROG:%=$(TESTDIR)/%)
-
-# OBJS= $(LIBPROG).o
-# SRCS= $(LIBPROG).c $(FSLIBSRC)
-
-CPPFLAGS += -I../../../../uts/common
-CPPFLAGS += -I../../../../lib/libsmbfs
-
-LDLIBS += -R'$$ORIGIN/../../../usr/lib'
-LDLIBS += -lsmbfs
-LINTLIBS= -L$(ROOTLIB) -lsmbfs
-
-CFLAGS += $(CCVERBOSE)
-CERRWARN += -_gcc=-Wno-unused-variable
-CSTD= $(CSTD_GNU99)
-
-# not linted
-SMATCH=off
-
-LINTFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2
-
-# CLOBBERFILES += $(LIBPROG)
-
-all: $(PROG)
-
-install: all $(ROOTOPTPKG) $(TESTDIR) $(INST_CMDS)
-
-lint:
- for f in $(SRCS); do ;\
- $(LINT.c) $$f $(LINTLIBS) ; done
-
-clobber: clean
- -$(RM) $(PROG)
-
-clean:
- -$(RM) $(OBJS)
-
-$(ROOTOPTPKG):
- $(INS.dir)
-
-$(TESTDIR):
- $(INS.dir)
-
-$(TESTDIR)/%: %
- $(INS.file)
-
-.KEEP_STATE:
diff --git a/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c b/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c
deleted file mode 100644
index 81ba8c9afc..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/test/srvinfo.c
+++ /dev/null
@@ -1,415 +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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * Test program for the smbfs named pipe API.
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <libintl.h>
-
-#include <netsmb/smbfs_api.h>
-
-/*
- * This is a quick hack for testing client-side named pipes.
- * Its purpose is to test the ability to connect to a server,
- * open a pipe, send and receive data. The "hack" aspect is
- * the use of hand-crafted RPC messages, which allows testing
- * of the named pipe API separately from the RPC libraries.
- *
- * I captured the two small name pipe messages sent when
- * requesting a server info via RPC over /pipe/srvsvc and
- * dropped them into the arrays below (bind and info).
- * This program sends the two messages (with adjustments)
- * and just dumps whatever comes back over the pipe.
- * Use wireshark if you want to see decoded messages.
- */
-
-extern char *optarg;
-extern int optind, opterr, optopt;
-
-/* This is a DCE/RPC bind call for "srvsvc". */
-static const uchar_t
-srvsvc_bind[] = {
- 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01,
- 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88,
- 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
- 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
- 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 };
-
-/* This is a srvsvc "get server info" call, in two parts */
-static const uchar_t
-srvsvc_info[] = {
- 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00,
-#define INFO_RPCLEN_OFF 8
- /* V - RPC frag length */
- 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* ... and the operation number is: VVVV */
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x15, 0x00,
-#define INFO_SLEN1_OFF 28
-#define INFO_SLEN2_OFF 36
- /* server name, length 14 vv ... */
- 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00 };
- /* UNC server here, i.e.: "\\192.168.1.6" */
-
-static uchar_t sendbuf[1024];
-static uchar_t recvbuf[1024];
-static char *server;
-
-static int pipetest(struct smb_ctx *);
-
-static void
-srvinfo_usage(void)
-{
- printf("usage: srvinfo [-d domain][-u user][-p passwd] server\n");
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int c, error;
- struct smb_ctx *ctx = NULL;
- char *dom = NULL;
- char *usr = NULL;
- char *pw = NULL;
-
- while ((c = getopt(argc, argv, "vd:u:p:")) != -1) {
- switch (c) {
- case 'v':
- smb_verbose = 1;
- break;
-
- case 'd':
- dom = optarg;
- break;
- case 'u':
- usr = optarg;
- break;
- case 'p':
- pw = optarg;
- break;
- case '?':
- srvinfo_usage();
- break;
- }
- }
- if (optind >= argc)
- srvinfo_usage();
- server = argv[optind];
-
- if (pw != NULL && (dom == NULL || usr == NULL)) {
- fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
- argv[0]);
- srvinfo_usage();
- }
-
- /*
- * This section is intended to demonstrate how an
- * RPC client library might use this interface.
- */
- error = smb_ctx_alloc(&ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Set server, share, domain, user
- * (in the ctx handle).
- */
- smb_ctx_setfullserver(ctx, server);
- smb_ctx_setshare(ctx, "IPC$", USE_IPC);
- if (dom)
- smb_ctx_setdomain(ctx, dom, B_TRUE);
- if (usr)
- smb_ctx_setuser(ctx, usr, B_TRUE);
- if (pw)
- smb_ctx_setpassword(ctx, pw, NULL);
-
-
- /*
- * If this code were in smbutil or mount_smbfs, it would
- * get system and $HOME/.nsmbrc settings here, like this:
- */
-#if 0
- error = smb_ctx_readrc(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_readrc failed\n", argv[0]);
- goto out;
- }
-#endif
-
- /*
- * Resolve the server address,
- * setup derived defaults.
- */
- error = smb_ctx_resolve(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Get the session and tree.
- */
- error = smb_ctx_get_ssn(ctx);
- if (error) {
- fprintf(stderr, "//%s: login failed, error %d\n",
- server, error);
- goto out;
- }
- error = smb_ctx_get_tree(ctx);
- if (error) {
- fprintf(stderr, "//%s/%s: tree connect failed, %d\n",
- server, "IPC$", error);
- goto out;
- }
-
- /*
- * Do some named pipe I/O.
- */
- error = pipetest(ctx);
- if (error) {
- fprintf(stderr, "pipetest, %d\n", error);
- goto out;
- }
-
-out:
- smb_ctx_free(ctx);
-
- return ((error) ? 1 : 0);
-}
-
-static void
-hexdump(const uchar_t *buf, int len) {
- int ofs = 0;
-
- while (len--) {
- if (ofs % 16 == 0)
- printf("\n%02X: ", ofs);
- printf("%02x ", *buf++);
- ofs++;
- }
- printf("\n");
-}
-
-/*
- * Put a unicode UNC server name, including the null.
- * Quick-n-dirty, just for this test...
- */
-static int
-put_uncserver(const char *s, uchar_t *buf)
-{
- uchar_t *p = buf;
- char c;
-
- *p++ = '\\'; *p++ = '\0';
- *p++ = '\\'; *p++ = '\0';
-
- do {
- c = *s++;
- if (c == '/')
- c = '\\';
- *p++ = c;
- *p++ = '\0';
-
- } while (c != 0);
-
- return (p - buf);
-}
-
-/* Get a little-endian int. Just for testing. */
-static int
-getint(const uchar_t *p)
-{
- return (p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24));
-}
-
-/*
- * Send the bind and read the ack.
- * This tests smb_fh_xactnp.
- */
-static int
-do_bind(int fid)
-{
- int err, len, more;
-
- more = 0;
- len = sizeof (recvbuf);
- err = smb_fh_xactnp(fid,
- sizeof (srvsvc_bind), (char *)srvsvc_bind,
- &len, (char *)recvbuf, &more);
- if (err) {
- printf("xact bind, err=%d\n", err);
- return (err);
- }
- if (smb_verbose) {
- printf("bind ack, len=%d\n", len);
- hexdump(recvbuf, len);
- }
- if (more > 0) {
- if (more > sizeof (recvbuf)) {
- printf("bogus more=%d\n", more);
- more = sizeof (recvbuf);
- }
- len = smb_fh_read(fid, 0,
- more, (char *)recvbuf);
- if (len == -1) {
- err = EIO;
- printf("read info resp, err=%d\n", err);
- return (err);
- }
- if (smb_verbose) {
- printf("bind ack (more), len=%d\n", len);
- hexdump(recvbuf, len);
- }
- }
-
- return (0);
-}
-
-static int
-do_info(int fid)
-{
- int err, len, rlen, wlen, x;
- uchar_t *p;
-
- /*
- * Build the info request - two parts.
- * See above: srvsvc_info
- *
- * First part: RPC header, etc.
- */
- p = sendbuf;
- len = sizeof (srvsvc_info); /* 40 */
- memcpy(p, srvsvc_info, len);
- p += len;
-
- /* Second part: UNC server name */
- len = put_uncserver(server, p);
- p += len;
- sendbuf[INFO_SLEN1_OFF] = len / 2;
- sendbuf[INFO_SLEN2_OFF] = len / 2;
-
- /* Third part: level, etc. (align4) */
- for (len = (p - sendbuf) & 3; len; len--)
- *p++ = '\0';
- *p++ = 101; /* the "level" */
- *p++ = 0; *p++ = 0; *p++ = 0;
-
- /*
- * Compute total length, and fixup RPC header.
- */
- len = p - sendbuf;
- sendbuf[INFO_RPCLEN_OFF] = len;
-
- /*
- * Send the info request, read the response.
- * This tests smb_fh_write, smb_fh_read.
- */
- wlen = smb_fh_write(fid, 0, len, (char *)sendbuf);
- if (wlen == -1) {
- err = errno;
- printf("write info req, err=%d\n", err);
- return (err);
- }
- if (wlen != len) {
- printf("write info req, short write %d\n", wlen);
- return (EIO);
- }
-
- rlen = smb_fh_read(fid, 0,
- sizeof (recvbuf), (char *)recvbuf);
- if (rlen == -1) {
- err = errno;
- printf("read info resp, err=%d\n", err);
- return (err);
- }
-
- if (smb_verbose) {
- printf("info recv, len=%d\n", rlen);
- hexdump(recvbuf, rlen);
- }
-
- x = getint(recvbuf + 4);
- if (x != 0x10) {
- printf("Data representation 0x%x not supported\n", x);
- return (ENOTSUP);
- }
- printf("Platform Id: %d\n", getint(recvbuf + 0x20));
- printf("Version Major: %d\n", getint(recvbuf + 0x28));
- printf("Version Minor: %d\n", getint(recvbuf + 0x2c));
- printf("Srv type flags: 0x%x\n", getint(recvbuf + 0x30));
-
- return (0);
-}
-
-static int
-pipetest(struct smb_ctx *ctx)
-{
- static char path[] = "/srvsvc";
- static uchar_t key[16];
- int err, fd;
-
- printf("open pipe: %s\n", path);
- fd = smb_fh_open(ctx, path, O_RDWR);
- if (fd < 0) {
- perror(path);
- return (errno);
- }
-
- /* Test this too. */
- err = smb_fh_getssnkey(fd, key, sizeof (key));
- if (err) {
- printf("getssnkey: %d\n", err);
- goto out;
- }
-
- err = do_bind(fd);
- if (err) {
- printf("do_bind: %d\n", err);
- goto out;
- }
- err = do_info(fd);
- if (err)
- printf("do_info: %d\n", err);
-
-out:
- smb_fh_close(fd);
- return (err);
-}
diff --git a/usr/src/cmd/fs.d/smbclnt/test/tconn.c b/usr/src/cmd/fs.d/smbclnt/test/tconn.c
deleted file mode 100644
index bfeac98fe0..0000000000
--- a/usr/src/cmd/fs.d/smbclnt/test/tconn.c
+++ /dev/null
@@ -1,171 +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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * Test program for opening an SMB connection directly.
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <libintl.h>
-
-#include <netsmb/smb_lib.h>
-
-extern char *optarg;
-extern int optind, opterr, optopt;
-extern int smb_iod_connect(struct smb_ctx *);
-
-static char *server;
-
-static void
-tconn_usage(void)
-{
- printf("usage: tconn [-d domain][-u user][-p passwd] server\n");
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int c, error, aflags;
- struct smb_ctx *ctx = NULL;
- char *dom = NULL;
- char *usr = NULL;
- char *pw = NULL;
- char *secopt = NULL;
- struct addrinfo *ai;
-
- while ((c = getopt(argc, argv, "vd:p:s:u:")) != -1) {
- switch (c) {
- case 'v':
- smb_debug = 1;
- smb_verbose = 1;
- break;
-
- case 'd':
- dom = optarg;
- break;
- case 'u':
- usr = optarg;
- break;
- case 'p':
- pw = optarg;
- break;
- case 's':
- secopt = optarg;
- break;
- case '?':
- tconn_usage();
- break;
- }
- }
- if (optind >= argc)
- tconn_usage();
- server = argv[optind];
-
- if (pw != NULL && (dom == NULL || usr == NULL)) {
- fprintf(stderr, "%s: -p arg requires -d dom -u usr\n",
- argv[0]);
- tconn_usage();
- }
-
- /*
- * This section is intended to demonstrate how an
- * RPC client library might use this interface.
- */
- error = smb_ctx_alloc(&ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_alloc failed\n", argv[0]);
- goto out;
- }
-
- /*
- * Set server, share, domain, user
- * (in the ctx handle).
- */
- smb_ctx_setfullserver(ctx, server);
- smb_ctx_setshare(ctx, "IPC$", USE_IPC);
- if (dom)
- smb_ctx_setdomain(ctx, dom, B_TRUE);
- if (usr)
- smb_ctx_setuser(ctx, usr, B_TRUE);
- if (pw)
- smb_ctx_setpassword(ctx, pw, NULL);
-
- /*
- * Hackish option to override the Authentication Type flags.
- * Sorry about exposing the flag values here, but this is
- * really a programmer's test tool. See smbfs_api.h for
- * the SMB_AT_... flag values.
- */
- if (secopt != NULL) {
- aflags = atoi(secopt);
- if (aflags < 1 || aflags > 0x1f) {
- fprintf(stderr, "%s: -s {0..31}\n", argv[0]);
- tconn_usage();
- }
- smb_ctx_setauthflags(ctx, aflags);
- }
-
- /*
- * Resolve the server address,
- * setup derived defaults.
- */
- error = smb_ctx_resolve(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_ctx_resolve failed\n", argv[0]);
- goto out;
- }
-
- if ((ai = ctx->ct_addrinfo) == NULL) {
- fprintf(stderr, "%s: no ct_addrinfo\n", argv[0]);
- goto out;
- }
- memcpy(&ctx->ct_srvaddr, ai->ai_addr, ai->ai_addrlen);
-
- /*
- * If this code were in smbutil or mount_smbfs, it would
- * get system and $HOME/.nsmbrc settings here, like this:
- */
- error = smb_iod_connect(ctx);
- if (error) {
- fprintf(stderr, "%s: smb_iod_connect failed\n", argv[0]);
- goto out;
- }
-
- printf("Yea, we connected!\n");
-
-out:
- smb_ctx_free(ctx);
-
- return ((error) ? 1 : 0);
-}
diff --git a/usr/src/cmd/fs.d/ufs/fsck/pass2.c b/usr/src/cmd/fs.d/ufs/fsck/pass2.c
index 998f98f3f6..30c23f2d57 100644
--- a/usr/src/cmd/fs.d/ufs/fsck/pass2.c
+++ b/usr/src/cmd/fs.d/ufs/fsck/pass2.c
@@ -4,7 +4,7 @@
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
@@ -25,8 +25,6 @@
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
@@ -50,13 +48,13 @@ static int pass2check(struct inodesc *);
void
pass2(void)
{
- struct dinode *dp, *dp2, *dpattr;
- struct inoinfo **inpp, *inp;
- struct inoinfo **inpend;
- struct inodesc curino;
- struct inodesc ldesc;
- struct dinode dino;
- char pathbuf[MAXPATHLEN + 1];
+ struct dinode *dp, *dp2, *dpattr;
+ struct inoinfo **inpp, *inp;
+ struct inoinfo **inpend;
+ struct inodesc curino;
+ struct inodesc ldesc;
+ struct dinode dino;
+ char pathbuf[MAXPATHLEN + 1];
int found;
int dirtype;
caddr_t errmsg;
@@ -115,7 +113,7 @@ pass2(void)
default:
errexit("BAD STATE 0x%x FOR ROOT INODE\n",
- statemap[UFSROOTINO]);
+ statemap[UFSROOTINO]);
}
statemap[UFSROOTINO] = DFOUND;
@@ -169,12 +167,12 @@ pass2(void)
pwarn("DIRECTORY %s: LENGTH %lld NOT MULTIPLE OF %d",
pathbuf, (longlong_t)inp->i_isize, DIRBLKSIZ);
inp->i_isize = roundup(inp->i_isize,
- (offset_t)DIRBLKSIZ);
+ (offset_t)DIRBLKSIZ);
if (preen || reply("ADJUST") == 1) {
dp = ginode(inp->i_number);
dp->di_size =
- (u_offset_t)roundup(inp->i_isize,
- (offset_t)DIRBLKSIZ);
+ (u_offset_t)roundup(inp->i_isize,
+ (offset_t)DIRBLKSIZ);
inodirty();
if (preen)
(void) printf(" (ADJUSTED)\n");
@@ -197,7 +195,7 @@ pass2(void)
dp = &dino;
dp->di_size = (u_offset_t)inp->i_isize;
(void) memmove((void *)&dp->di_db[0], (void *)&inp->i_blks[0],
- inp->i_blkssize);
+ inp->i_blkssize);
init_inodesc(&curino);
curino.id_type = DATA;
curino.id_func = pass2check;
@@ -240,14 +238,14 @@ pass2(void)
* directory-related states need to be checked. There
* should never be any flags associated with USTATE.
*/
- if ((statemap[inp->i_number] & STMASK) == DCLEAR ||
+ if ((statemap[inp->i_number] & (STMASK | INCLEAR)) == DCLEAR ||
statemap[inp->i_number] == USTATE) {
continue;
}
if (statemap[inp->i_parent] == DFOUND &&
S_IS_DUNFOUND(statemap[inp->i_number])) {
statemap[inp->i_number] = DFOUND |
- (statemap[inp->i_number] & INCLEAR);
+ (statemap[inp->i_number] & INCLEAR);
}
if (inp->i_dotdot == inp->i_parent ||
inp->i_dotdot == (fsck_ino_t)-1) {
@@ -340,7 +338,7 @@ pass2(void)
continue;
}
fileerror(inp->i_parent, inp->i_number,
- "BAD INODE NUMBER FOR '..'");
+ "BAD INODE NUMBER FOR '..'");
if (reply("FIX") == 0) {
iscorrupt = 1;
continue;
@@ -438,7 +436,7 @@ pass2check(struct inodesc *idesc)
entrysize = DIRSIZ(&proto);
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
- dirp->d_name);
+ dirp->d_name);
iscorrupt = 1;
} else if ((int)dirp->d_reclen < entrysize) {
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
@@ -549,7 +547,7 @@ chk1:
* we get called on them.
*/
errexit("pass2check got NULL from getinoinfo at chk1 I=%d\n",
- idesc->id_number);
+ idesc->id_number);
}
proto.d_ino = inp->i_parent;
proto.d_namlen = 2;
@@ -625,7 +623,7 @@ chk1:
* that we're still on the "." entry.
*/
fileerror(idesc->id_number, dirp->d_ino,
- "I OUT OF RANGE");
+ "I OUT OF RANGE");
dirp->d_ino = 0;
if (reply("FIX") == 1) {
ret |= ALTERED;
@@ -647,7 +645,7 @@ chk1:
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
- dirp->d_name);
+ dirp->d_name);
iscorrupt = 1;
inp->i_dotdot = (fsck_ino_t)-1;
} else if ((int)dirp->d_reclen < entrysize) {
@@ -783,8 +781,8 @@ again:
* at this point.
*/
errexit("pass2check found a zero-len "
- "reference to bad I=%d\n",
- dirp->d_ino);
+ "reference to bad I=%d\n",
+ dirp->d_ino);
}
if (inp->i_parent != 0) {
(void) printf(
@@ -842,8 +840,8 @@ again:
* zero-len case above.
*/
errexit("pass2check found bad reference to "
- "hard-linked directory I=%d\n",
- dirp->d_ino);
+ "hard-linked directory I=%d\n",
+ dirp->d_ino);
}
dp = ginode(idesc->id_number);
if (inp->i_parent != 0 && idesc->id_entryno > 2 &&
@@ -858,18 +856,21 @@ again:
pwarn(
"%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n",
pathbuf, namebuf);
- if (preen)
+ if (preen) {
(void) printf(" (IGNORED)\n");
- else if ((act = reply(PASS2B_PROMPT,
- idesc->id_number)) == 1) {
- update_lncntp = 1;
- broke_dir_link = 1;
- break;
+ } else {
+ act = reply(PASS2B_PROMPT,
+ idesc->id_number);
+ if (act == 1) {
+ update_lncntp = 1;
+ broke_dir_link = 1;
+ break;
+ }
}
}
if ((idesc->id_entryno > 2) &&
- (inp->i_extattr != idesc->id_number)) {
+ (inp->i_extattr != idesc->id_number)) {
inp->i_parent = idesc->id_number;
}
/* FALLTHROUGH */
@@ -1003,7 +1004,7 @@ again:
pdirp = ginode(
idesc->id_number);
if (pdirp->di_oeftflag
- != 0) {
+ != 0) {
pdirp->di_oeftflag = 0;
inodirty();
}
diff --git a/usr/src/cmd/getconf/getconf.c b/usr/src/cmd/getconf/getconf.c
index fe2dceb76b..862c9a49c3 100644
--- a/usr/src/cmd/getconf/getconf.c
+++ b/usr/src/cmd/getconf/getconf.c
@@ -30,6 +30,10 @@
*/
/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
+/*
* getconf -- POSIX.2 compatible utility to query configuration specific
* parameters.
* -- XPG4 support added June/93
@@ -936,8 +940,9 @@ main(int argc, char **argv)
* sort the table by the "name" field
* so we print it in sorted order
*/
- qsort(&sctab[0], (sizeof (sctab)/sizeof (struct sctab))-1,
- sizeof (struct sctab), namecmp);
+ qsort(&sctab[0], (sizeof (sctab) /
+ sizeof (struct sctab)) - 1,
+ sizeof (struct sctab), namecmp);
/*
* print all the known symbols and their values
diff --git a/usr/src/cmd/infocmp/infocmp.c b/usr/src/cmd/infocmp/infocmp.c
index cdbcffa447..9e026f8b40 100644
--- a/usr/src/cmd/infocmp/infocmp.c
+++ b/usr/src/cmd/infocmp/infocmp.c
@@ -26,10 +26,10 @@
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2019, Joyent, Inc.
*/
-#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */
-
/*
NAME
infocmp - compare terminfo descriptions, or dump a terminfo
@@ -185,9 +185,10 @@ allocvariables(int argc, int firstoptind)
sizeof (struct strstruct));
/* Allocate array to keep track of which names have been used. */
- if (use)
+ if (use) {
used = (char *) malloc((unsigned) (argc - firstoptind) *
sizeof (char));
+ }
if ((ibool == NULL) || (num == NULL) || (str == NULL) ||
(use && (used == NULL)))
@@ -203,8 +204,9 @@ allocvariables(int argc, int firstoptind)
if (nullseen || (boolfnames[i] == NULL)) {
ibool[i].fullname = "unknown_boolean";
nullseen = TRUE;
- } else
+ } else {
ibool[i].fullname = boolfnames[i];
+ }
ibool[i].changed = FALSE;
ibool[i].seenagain = FALSE;
}
@@ -215,8 +217,9 @@ allocvariables(int argc, int firstoptind)
if (nullseen || (numfnames[i] == NULL)) {
ibool[i].fullname = "unknown_number";
nullseen = TRUE;
- } else
+ } else {
num[i].fullname = numfnames[i];
+ }
num[i].changed = FALSE;
num[i].seenagain = FALSE;
}
@@ -227,8 +230,9 @@ allocvariables(int argc, int firstoptind)
if (nullseen || (strfnames[i] == NULL)) {
str[i].fullname = "unknown_string";
nullseen = TRUE;
- } else
+ } else {
str[i].fullname = strfnames[i];
+ }
str[i].changed = FALSE;
str[i].seenagain = FALSE;
}
@@ -522,9 +526,10 @@ initfirstterm(char *term)
{
register int i;
- if (verbose)
+ if (verbose) {
(void) fprintf(trace, "setting up terminal type '%s'.\n",
term);
+ }
(void) setupterm(term, devnull, (int *) 0);
@@ -542,8 +547,9 @@ initfirstterm(char *term)
_savettytype[TTYLEN] = '\0';
savettytype = _savettytype;
}
- } else
+ } else {
(void) strcpy(_savettytype, ttytype);
+ }
}
if (printing != pr_none) {
@@ -554,12 +560,15 @@ initfirstterm(char *term)
/* Save the values for the first terminal. */
for (i = 0; i < numbools; i++) {
if ((ibool[i].val = tgetflag(ibool[i].capname)) &&
- printing != pr_none)
+ printing != pr_none) {
pr_boolean(ibool[i].infoname, ibool[i].capname,
ibool[i].fullname, 1);
- if (verbose)
+ }
+
+ if (verbose) {
(void) fprintf(trace, "%s=%d.\n", ibool[i].infoname,
ibool[i].val);
+ }
}
if (printing != pr_none) {
@@ -571,12 +580,15 @@ initfirstterm(char *term)
for (i = 0; i < numnums; i++) {
if (((num[i].val = tgetnum(num[i].capname)) > -1) &&
- printing != pr_none)
+ printing != pr_none) {
pr_number(num[i].infoname, num[i].capname,
num[i].fullname, num[i].val);
- if (verbose)
+ }
+
+ if (verbose) {
(void) fprintf(trace, "%s=%d.\n", num[i].infoname,
num[i].val);
+ }
}
if (printing != pr_none) {
@@ -588,9 +600,11 @@ initfirstterm(char *term)
for (i = 0; i < numstrs; i++) {
str[i].val = tgetstr(str[i].capname, (char **)0);
- if ((str[i].val != NULL) && printing != pr_none)
+ if ((str[i].val != NULL) && printing != pr_none) {
pr_string(str[i].infoname, str[i].capname,
str[i].fullname, str[i].val);
+ }
+
if (verbose) {
(void) fprintf(trace, "%s='", str[i].infoname);
PR(trace, str[i].val);
@@ -619,9 +633,10 @@ check_nth_terminal(char *nterm, int n)
if (use)
used[n] = FALSE;
- if (verbose)
+ if (verbose) {
(void) fprintf(trace, "adding in terminal type '%s'.\n",
nterm);
+ }
(void) setupterm(nterm, devnull, (int *) 0);
@@ -679,20 +694,24 @@ check_nth_terminal(char *nterm, int n)
}
}
if (boolval) {
- if (printing != pr_none)
+ if (printing != pr_none) {
pr_boolean(ibool[i].infoname, ibool[i].capname,
ibool[i].fullname, 1);
+ }
+
if (common && (ibool[i].val == boolval))
(void) printf("\t%s= T.\n", ibool[i].infoname);
- } else if (neither && !ibool[i].val)
+ } else if (neither && !ibool[i].val) {
(void) printf("\t!%s.\n", ibool[i].infoname);
+ }
if (diff && (ibool[i].val != boolval))
(void) printf("\t%s: %c:%c.\n", ibool[i].infoname,
ibool[i].val?'T':'F', boolval?'T':'F');
- if (verbose)
+ if (verbose) {
(void) fprintf(trace, "%s: %d:%d, changed=%d, "
"seen=%d.\n", ibool[i].infoname, ibool[i].val,
boolval, ibool[i].changed, ibool[i].seenagain);
+ }
}
if (printing != pr_none) {
@@ -733,22 +752,31 @@ check_nth_terminal(char *nterm, int n)
}
}
if (numval > -1) {
- if (printing != pr_none)
+ if (printing != pr_none) {
pr_number(num[i].infoname, num[i].capname,
num[i].fullname, numval);
- if (common && (num[i].val == numval))
+ }
+
+ if (common && (num[i].val == numval)) {
(void) printf("\t%s= %d.\n", num[i].infoname,
numval);
- } else if (neither && (num[i].val == -1))
- (void) printf("\t!%s.\n", num[i].infoname);
- if (diff && (num[i].val != numval))
- (void) printf("\t%s: %d:%d.\n",
- num[i].infoname, num[i].val, numval);
- if (verbose)
- (void) fprintf(trace, "%s: %d:%d, "
- "changed = %d, seen = %d.\n",
- num[i].infoname, num[i].val, numval,
- num[i].changed, num[i].seenagain);
+ }
+
+ } else if (neither && (num[i].val == -1)) {
+ (void) printf("\t!%s.\n", num[i].infoname);
+ }
+
+ if (diff && (num[i].val != numval)) {
+ (void) printf("\t%s: %d:%d.\n",
+ num[i].infoname, num[i].val, numval);
+ }
+
+ if (verbose) {
+ (void) fprintf(trace, "%s: %d:%d, "
+ "changed = %d, seen = %d.\n",
+ num[i].infoname, num[i].val, numval,
+ num[i].changed, num[i].seenagain);
+ }
}
if (printing != pr_none) {
@@ -791,9 +819,11 @@ check_nth_terminal(char *nterm, int n)
}
}
if (strval != NULL) {
- if (printing != pr_none)
+ if (printing != pr_none) {
pr_string(str[i].infoname, str[i].capname,
str[i].fullname, strval);
+ }
+
if (common && EQUAL(str[i].val, strval)) {
(void) printf("\t%s= '", str[i].infoname);
PR(stdout, strval);
@@ -848,48 +878,57 @@ dorelative(int firstoptind, int argc, char **argv)
pr_bheading();
/* Print out all bools that are different. */
- for (i = 0; i < numbools; i++)
- if (!ibool[i].val && ibool[i].changed)
+ for (i = 0; i < numbools; i++) {
+ if (!ibool[i].val && ibool[i].changed) {
pr_boolean(ibool[i].infoname, (char *)0,
(char *)0, -1);
- else if (ibool[i].val && (ibool[i].changed ||
- !ibool[i].seenagain))
+ } else if (ibool[i].val && (ibool[i].changed ||
+ !ibool[i].seenagain)) {
pr_boolean(ibool[i].infoname, (char *)0, (char *)0, 1);
+ }
+ }
pr_bfooting();
pr_nheading();
/* Print out all nums that are different. */
- for (i = 0; i < numnums; i++)
- if (num[i].val < 0 && num[i].changed)
+ for (i = 0; i < numnums; i++) {
+ if (num[i].val < 0 && num[i].changed) {
pr_number(num[i].infoname, (char *)0, (char *)0, -1);
- else if (num[i].val >= 0 && (num[i].changed ||
- !num[i].seenagain))
+ } else if (num[i].val >= 0 && (num[i].changed ||
+ !num[i].seenagain)) {
pr_number(num[i].infoname, (char *)0,
(char *)0, num[i].val);
+ }
+ }
pr_nfooting();
pr_sheading();
/* Print out all strs that are different. */
- for (i = 0; i < numstrs; i++)
- if (str[i].val == NULL && str[i].changed)
+ for (i = 0; i < numstrs; i++) {
+ if (str[i].val == NULL && str[i].changed) {
pr_string(str[i].infoname, (char *)0, (char *)0,
(char *)0);
- else if ((str[i].val != NULL) &&
- (str[i].changed || !str[i].seenagain))
- pr_string(str[i].infoname, (char *)0, (char *)0, str[i].val);
+ } else if ((str[i].val != NULL) &&
+ (str[i].changed || !str[i].seenagain)) {
+ pr_string(str[i].infoname,
+ (char *)0, (char *)0, str[i].val);
+ }
+ }
pr_sfooting();
/* Finish it up. */
- for (i = firstoptind; i < argc; i++)
- if (used[i - firstoptind])
+ for (i = firstoptind; i < argc; i++) {
+ if (used[i - firstoptind]) {
(void) printf("\tuse=%s,\n", argv[i]);
- else
+ } else {
(void) fprintf(stderr,
"%s: 'use=%s' did not add anything to the "
"description.\n", progname, argv[i]);
+ }
+ }
}
void
@@ -903,9 +942,11 @@ local_setenv(char *termNinfo)
register int termlen;
if (termNinfo && *termNinfo) {
- if (verbose)
+ if (verbose) {
(void) fprintf(trace, "setting TERMINFO=%s.\n",
termNinfo);
+ }
+
termlen = strlen(termNinfo);
if (termlen + 10 > termsize) {
termsize = termlen + 20;
@@ -1052,12 +1093,13 @@ main(int argc, char **argv)
optind = 0;
}
pr_init(printing = pr_terminfo);
- } else
+ } else {
diff++;
+ }
}
/* Set the default sorting order. */
- if (sortorder == none)
+ if (sortorder == none) {
switch ((int) printing) {
case (int) pr_cap:
sortorder = by_cap; break;
@@ -1067,6 +1109,7 @@ main(int argc, char **argv)
case (int) pr_none:
sortorder = by_terminfo; break;
}
+ }
firstterm = argv[optind++];
firstoptind = optind;
diff --git a/usr/src/cmd/ksh/builtins/alias.c b/usr/src/cmd/ksh/builtins/alias.c
index a17e2dabd1..88edbc1e9b 100644
--- a/usr/src/cmd/ksh/builtins/alias.c
+++ b/usr/src/cmd/ksh/builtins/alias.c
@@ -68,9 +68,7 @@ bfastpathrec fastpath_builtins[] =
/* This list must be alphabetically sorted for |strcmp()| usage */
{ "basename", b_basename },
{ "cat", b_cat },
- { "chgrp", b_chgrp },
{ "chmod", b_chmod },
- { "chown", b_chown },
#ifdef ENABLE_PERFORMANCE_PARADOXON
{ "cksum", b_cksum },
#endif /* ENABLE_PERFORMANCE_PARADOXON */
@@ -98,7 +96,7 @@ bfastpathrec fastpath_builtins[] =
{ "mkfifo", b_mkfifo },
{ "mktemp", b_mktemp },
{ "mv", b_mv },
- { "paste", b_paste },
+ { "paste", b_paste },
{ "pathchk", b_pathchk },
{ "pids", b_pids },
{ "readlink", b_readlink },
@@ -119,7 +117,7 @@ bfastpathrec fastpath_builtins[] =
{ "uniq", b_uniq },
{ "wc", b_wc },
{ "xgrep", b_xgrep },
- { NULL, (int (*)(int, char **, void *))NULL }
+ { NULL, (int (*)(int, char **, void *))NULL }
};
static inline
diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common
index b1f8835acd..79b49c8ce2 100644
--- a/usr/src/cmd/mdb/Makefile.common
+++ b/usr/src/cmd/mdb/Makefile.common
@@ -22,7 +22,7 @@
#
# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2016 Joyent, Inc.
-# Copyright 2016 Nexenta Systems, Inc.
+# Copyright 2017 Nexenta Systems, Inc.
#
#
@@ -35,6 +35,8 @@ COMMON_MODULES_PROC = \
libavl \
libc \
libcmdutils \
+ libfknsmb \
+ libfksmbfs \
libfksmbsrv \
libnvpair \
libproc \
diff --git a/usr/src/cmd/mdb/Makefile.module b/usr/src/cmd/mdb/Makefile.module
index 5bfdbf8434..7da9b0c586 100644
--- a/usr/src/cmd/mdb/Makefile.module
+++ b/usr/src/cmd/mdb/Makefile.module
@@ -24,6 +24,8 @@
#
# Copyright (c) 2013 by Delphix. All rights reserved.
# Copyright (c) 2018, Joyent, Inc.
+# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
.KEEP_STATE:
@@ -177,7 +179,7 @@ lint: $$(LINTFILES)
$(MODFILE): dmod .WAIT $(MODOBJS) $$(MAPFILE-EXT)
$(LINK.c) $(ZDEFS) $(ZIGNORE) $(MAPFILE-EXT:%=-M%) $(GSHARED) \
- $(MODOBJS) -o $@ $(LDLIBS) -lc
+ $(MODOBJS) -o $@ $(LDLIBS) -lc -lproc
$(CTFMERGE) -L VERSION -o $@ $(MODOBJS)
$(POST_PROCESS_SO)
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
index 54876b5bcf..878728251c 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c
@@ -3208,8 +3208,8 @@ const mdb_dcmd_t mdb_dcmd_builtins[] = {
*/
{ "?", "fmt-list", "format data from object file", cmd_print_object },
{ "$>", "[file]", "log session to a file", cmd_old_log },
- { "$g", "?", "get/set C++ demangling options", cmd_demflags },
- { "$G", NULL, "enable/disable C++ demangling support", cmd_demangle },
+ { "$g", "?", "get/set demangling options", cmd_demflags },
+ { "$G", NULL, "enable/disable demangling support", cmd_demangle },
{ "$i", NULL, "print signals that are ignored", cmd_notsup },
{ "$l", NULL, "print the representative thread's lwp id", cmd_notsup },
{ "$p", ":", "change debugger target context", cmd_context },
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_demangle.c b/usr/src/cmd/mdb/common/mdb/mdb_demangle.c
index a24d889009..b016297b31 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_demangle.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_demangle.c
@@ -27,7 +27,7 @@
*/
/*
- * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
*/
#include <mdb/mdb_modapi.h>
@@ -66,8 +66,7 @@ mdb_dem_load(void)
dmp->dm_len = 0;
dmp->dm_buf = NULL;
dmp->dm_flags = MDB_DM_SCOPE;
- /* stick with C++ for now to match old behavior */
- dmp->dm_lang = SYSDEM_LANG_CPP;
+ dmp->dm_lang = SYSDEM_LANG_AUTO;
return (dmp);
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
index 471d918ca5..c68f20b107 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_fmt.c
@@ -21,7 +21,7 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
* Copyright (c) 2017 by Delphix. All rights reserved.
*/
@@ -82,8 +82,9 @@ typedef mdb_tgt_addr_t mdb_fmt_func_f(mdb_tgt_t *,
#define FMT_PRINTF 0x2 /* f_ptr is a const char * format string */
#define FMT_MATCH 0x4 /* Match command (not supported here) */
#define FMT_WRITE 0x8 /* Command writes to address space */
+#define FMT_NOAUTOWRAP 0x10 /* Autowrap should not be autoenabled */
-#define FMT_TYPE(x) ((x) & 0x7) /* Excludes modifying flags (FMT_WRITE) */
+#define FMT_TYPE(x) ((x) & 0x7) /* Excludes modifying flags */
typedef struct mdb_fmt_desc {
int f_type; /* Type of format (see above) */
@@ -120,6 +121,7 @@ static const char help_match64[] = "long long";
static const char help_match16[] = "short";
static const char help_uintptr[] = "hexadecimal uintptr_t";
static const char help_ctf[] = "whose size is inferred by CTF info";
+static const char help_jazzed[] = "jazzed-up binary unsigned long long";
/*ARGSUSED*/
static mdb_tgt_addr_t
@@ -455,10 +457,12 @@ static mdb_tgt_addr_t
fmt_binary(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
{
uint64_t x;
+ const char *fmts[] = { "%-64s", "%-65s" };
+ const uint64_t mask = 0x8000000000000000ull;
while (cnt-- != 0) {
if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) == sizeof (x)) {
- mdb_iob_printf(mdb.m_out, "%-64s",
+ mdb_iob_printf(mdb.m_out, fmts[(x & mask) != 0],
numtostr(x, 2, NTOS_UNSIGNED));
mdb_nv_set_value(mdb.m_rvalue, x);
addr += sizeof (x);
@@ -471,6 +475,83 @@ fmt_binary(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
}
static mdb_tgt_addr_t
+fmt_jazzed(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
+{
+ uint64_t x;
+ char buf[256];
+
+ while (cnt-- != 0) {
+ boolean_t header = B_TRUE;
+
+ if (mdb_tgt_aread(t, as, &x, sizeof (x), addr) != sizeof (x)) {
+ warn("failed to read data from target");
+ break;
+ }
+
+ mdb_nv_set_value(mdb.m_rvalue, x);
+ addr += sizeof (x);
+
+ mdb_iob_printf(mdb.m_out, "%s\n",
+ numtostr(x, 2, NTOS_UNSIGNED));
+
+ while (x != 0) {
+ int b = 63, forearm;
+ int i = 0, highbit;
+
+ /*
+ * Find the high bit...
+ */
+ while (!(x & (1ULL << b)))
+ b--;
+
+ highbit = b;
+
+ /*
+ * ...and iterate over the remaining bits, putting
+ * the upper arm in our buffer for any set bit (and
+ * a space otherwise).
+ */
+ while (x & ((1ULL << b) - 1)) {
+ buf[i++] = x & (1ULL << b) ? '|' : ' ';
+ b--;
+ }
+
+ /*
+ * If this is the header line, print the upper arm
+ * for the lowest set bit and continue...
+ */
+ if (header) {
+ header = B_FALSE;
+ buf[i] = '\0';
+ mdb_iob_printf(mdb.m_out, "%s|\n", buf);
+ continue;
+ }
+
+ /*
+ * ...otherwise, put the elbow and forearm into our
+ * buffer, and print it.
+ */
+ buf[i++] = '+';
+
+ for (forearm = b; forearm > -2; forearm--)
+ buf[i++] = '-';
+
+ buf[i] = '\0';
+ mdb_iob_printf(mdb.m_out, "%s bit %d %smask 0x%0*llx\n",
+ buf, b, b < 10 && highbit >= 10 ? " " : "",
+ (highbit / 4) + 1, 1ULL << b);
+
+ /*
+ * Finally, clear the lowest set bit and continue.
+ */
+ x &= ~(1ULL << b);
+ }
+ }
+
+ return (addr);
+}
+
+static mdb_tgt_addr_t
fmt_hex64(mdb_tgt_t *t, mdb_tgt_as_t as, mdb_tgt_addr_t addr, size_t cnt)
{
const char *fmts[] = { "%-16llx", "%-17llx" };
@@ -560,13 +641,13 @@ static const mdb_fmt_desc_t fmttab[] = {
{ FMT_PRINTF, "%-8x", NULL, 1 }, /* 66 = B */
{ FMT_FUNC, FUNCP(fmt_escchr), help_escchr, 1 }, /* 67 = C */
{ FMT_PRINTF, "%-16d", NULL, 4 }, /* 68 = D */
- { FMT_PRINTF, "%-16llu", NULL, 8 }, /* 69 = E */
+ { FMT_PRINTF, "%-21llu", NULL, 8 }, /* 69 = E */
#ifdef _KMDB
{ FMT_NONE, NULL, NULL, 0 }, /* 70 = F */
#else
{ FMT_PRINTF, "%g", NULL, sizeof (double), B_TRUE }, /* 70 = F */
#endif
- { FMT_PRINTF, "%-16llo", NULL, 8 }, /* 71 = G */
+ { FMT_PRINTF, "%-23llo", NULL, 8 }, /* 71 = G */
{ FMT_FUNC, FUNCP(fmt_swapint), help_swapint, 4 }, /* 72 = H */
{ FMT_FUNC, FUNCP(fmt_dotinstr), help_dotinstr, 0 }, /* 73 = I */
{ FMT_FUNC, FUNCP(fmt_hex64), help_hex64, 8 }, /* 74 = J */
@@ -579,7 +660,7 @@ static const mdb_fmt_desc_t fmttab[] = {
{ FMT_MATCH, NULL, help_match64, 8 }, /* 77 = M */
{ FMT_FUNC, FUNCP(fmt_nl), help_nl, SZ_NONE }, /* 78 = N */
{ FMT_PRINTF, "%-#16o", NULL, 4 }, /* 79 = O */
- { FMT_PRINTF, "%-16a", NULL, sizeof (uintptr_t) }, /* 80 = P */
+ { FMT_PRINTF, "%-19a", NULL, sizeof (uintptr_t) }, /* 80 = P */
{ FMT_PRINTF, "%-#16q", NULL, 4 }, /* 81 = Q */
{ FMT_FUNC, FUNCP(fmt_binary), help_binary, 8 }, /* 82 = R */
{ FMT_FUNC, FUNCP(fmt_escstr), help_escstr, 0 }, /* 83 = S */
@@ -600,23 +681,24 @@ static const mdb_fmt_desc_t fmttab[] = {
{ FMT_PRINTF, "%-#8o", NULL, 1 }, /* 98 = b */
{ FMT_PRINTF, "%c", NULL, 1 }, /* 99 = c */
{ FMT_PRINTF, "%-8hd", NULL, 2 }, /* 100 = d */
- { FMT_PRINTF, "%-16lld", NULL, 8 }, /* 101 = e */
+ { FMT_PRINTF, "%-21lld", NULL, 8 }, /* 101 = e */
#ifdef _KMDB
{ FMT_NONE, NULL, NULL, 0 }, /* 102 = f */
#else
{ FMT_FUNC, FUNCP(fmt_float), help_f, sizeof (float),
B_TRUE }, /* 102 = f */
#endif
- { FMT_PRINTF, "%-16llq", NULL, 8 }, /* 103 = g */
+ { FMT_PRINTF, "%-24llq", NULL, 8 }, /* 103 = g */
{ FMT_FUNC, FUNCP(fmt_swapshort), help_swapshort, 2 }, /* 104 = h */
{ FMT_FUNC, FUNCP(fmt_instr), help_instr, 0 }, /* 105 = i */
- { FMT_NONE, NULL, NULL, 0 }, /* 106 = j */
+ { FMT_FUNC|FMT_NOAUTOWRAP,
+ FUNCP(fmt_jazzed), help_jazzed, 8 }, /* 106 = j */
{ FMT_NONE, NULL, NULL, 0 }, /* 107 = k */
{ FMT_MATCH, NULL, help_match16, 2 }, /* 108 = l */
{ FMT_NONE, NULL, NULL, 0 }, /* 109 = m */
{ FMT_FUNC, FUNCP(fmt_nl), help_nl, SZ_NONE }, /* 110 = n */
{ FMT_PRINTF, "%-#8ho", NULL, 2 }, /* 111 = o */
- { FMT_PRINTF, "%-16a", NULL, sizeof (uintptr_t) }, /* 112 = p */
+ { FMT_PRINTF, "%-19a", NULL, sizeof (uintptr_t) }, /* 112 = p */
{ FMT_PRINTF, "%-#8hq", NULL, 2 }, /* 113 = q */
{ FMT_FUNC, FUNCP(fmt_ws), help_ws, SZ_NONE }, /* 114 = r */
{ FMT_FUNC, FUNCP(fmt_rawstr), help_rawstr, 0 }, /* 115 = s */
@@ -637,6 +719,7 @@ mdb_fmt_print(mdb_tgt_t *t, mdb_tgt_as_t as,
mdb_fmt_func_f *funcp;
uintmax_t rvalue;
void *buf;
+ uint_t oflags = mdb.m_flags;
union {
uint64_t i8;
@@ -651,6 +734,14 @@ mdb_fmt_print(mdb_tgt_t *t, mdb_tgt_as_t as,
return (addr);
}
+ if (!(fp->f_type & FMT_NOAUTOWRAP)) {
+ /*
+ * Unless a format has explicitly opted out, we force autowrap
+ * for the duration of mdb_fmt_print().
+ */
+ mdb.m_flags |= MDB_FL_AUTOWRAP;
+ }
+
switch (FMT_TYPE(fp->f_type)) {
case FMT_FUNC:
funcp = (mdb_fmt_func_f *)fp->f_ptr;
@@ -725,6 +816,8 @@ mdb_fmt_print(mdb_tgt_t *t, mdb_tgt_as_t as,
warn("invalid format character -- '%c'\n", fmt);
}
+ mdb.m_flags = oflags;
+
return (addr);
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_io.c b/usr/src/cmd/mdb/common/mdb/mdb_io.c
index b8c04bcd06..f1ad8d051c 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_io.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_io.c
@@ -24,7 +24,7 @@
*/
/*
- * Copyright (c) 2017, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
@@ -162,11 +162,14 @@ typedef struct {
/*
* Define macro for determining if we should automatically wrap to the next
* line of output, based on the amount of consumed buffer space and the
- * specified size of the next thing to be inserted (n).
+ * specified size of the next thing to be inserted (n) -- being careful to
+ * not force a spurious wrap if we're autoindented and already at the margin.
*/
#define IOB_WRAPNOW(iob, n) \
(IOB_AUTOWRAP(iob) && (iob)->iob_nbytes != 0 && \
- ((n) + (iob)->iob_nbytes > (iob)->iob_cols))
+ ((n) + (iob)->iob_nbytes > (iob)->iob_cols) && \
+ !(((iob)->iob_flags & MDB_IOB_INDENT) && \
+ (iob)->iob_nbytes == (iob)->iob_margin))
/*
* Define prompt string and string to erase prompt string for iob_pager
@@ -1910,7 +1913,7 @@ mdb_iob_fill(mdb_iob_t *iob, int c, size_t nfill)
void
mdb_iob_ws(mdb_iob_t *iob, size_t n)
{
- if (iob->iob_nbytes + n < iob->iob_cols)
+ if (!IOB_AUTOWRAP(iob) || iob->iob_nbytes + n < iob->iob_cols)
mdb_iob_fill(iob, ' ', n);
else
mdb_iob_nl(iob);
diff --git a/usr/src/cmd/mdb/common/modules/genunix/ldi.c b/usr/src/cmd/mdb/common/modules/genunix/ldi.c
index 1df7fd1120..a3ceb64421 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/ldi.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/ldi.c
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/dditypes.h>
@@ -377,7 +381,8 @@ ldi_handle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
argc, argv) == -1) {
mdb_warn("can't walk ldi handles");
return (DCMD_ERR);
- } return (DCMD_OK);
+ }
+ return (DCMD_OK);
}
/* display the header line */
diff --git a/usr/src/cmd/mdb/common/modules/libc/libc.c b/usr/src/cmd/mdb/common/modules/libc/libc.c
index a075638ddd..b9de1dc936 100644
--- a/usr/src/cmd/mdb/common/modules/libc/libc.c
+++ b/usr/src/cmd/mdb/common/modules/libc/libc.c
@@ -23,6 +23,8 @@
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2019, Joyent, Inc.
+ * Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
#include <sys/mdb_modapi.h>
@@ -36,6 +38,7 @@
#include <string.h>
#include <thr_uberdata.h>
#include "findstack.h"
+#include <libproc.h>
static const char *
stack_flags(const stack_t *sp)
@@ -1200,6 +1203,223 @@ d_errno(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
mdb_printf("%d\n", errval);
+
+ return (DCMD_OK);
+}
+
+/*
+ * Print percent from 16-bit binary fraction [0 .. 1]
+ * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
+ *
+ * Note: This routine was copied from elfdump/common/corenote.c and modified.
+ *
+ */
+static uint_t
+pct_value(ushort_t pct)
+{
+ uint_t value = pct;
+
+ value = ((value * 1000) + 0x7000) >> 15; /* [0 .. 1000] */
+ if (value >= 1000)
+ value = 999;
+
+ return (value);
+}
+
+static void
+psinfo_raw(psinfo_t psinfo)
+{
+ const int minspaces = 2;
+ const int spbcols = 20;
+ char sysname[SYS2STR_MAX];
+ uint_t cpu, mem;
+ char buff[32];
+ int bufflen;
+
+ mdb_printf("[ NT_PRPSINFO ]\n");
+
+ mdb_printf("\tpr_state: %d\t\t\tpr_sname: %c\n",
+ psinfo.pr_lwp.pr_state, psinfo.pr_lwp.pr_sname);
+
+ mdb_printf("\tpr_zomb: %d\t\t\tpr_nice: %d\n",
+ psinfo.pr_nzomb, psinfo.pr_lwp.pr_nice);
+
+ mdb_printf("\tpr_uid: %u\t\t\tpr_gid: %u\n",
+ psinfo.pr_uid, psinfo.pr_gid);
+
+ mdb_snprintf(buff, sizeof (buff),
+ "%d", psinfo.pr_pid);
+
+ bufflen = strlen(buff);
+ mdb_printf("\tpr_pid: %s%*spr_ppid: %d\n",
+ buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
+ psinfo.pr_ppid);
+
+ mdb_printf("\tpr_pgid: %u\t\t\tpr_sid: %d\n",
+ psinfo.pr_gid, psinfo.pr_sid);
+
+ mdb_snprintf(buff, sizeof (buff),
+ "0x%lx", (ulong_t)psinfo.pr_addr);
+
+ bufflen = strlen(buff);
+
+ mdb_printf("\tpr_addr: %s%*spr_size: %#x\n",
+ buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
+ (ulong_t)psinfo.pr_size);
+
+ mdb_printf("\tpr_rssize: %#lx\t\tpr_wchan: %#lx\n",
+ (ulong_t)psinfo.pr_rssize, (ulong_t)psinfo.pr_lwp.pr_wchan);
+
+ mdb_printf("\tpr_start:\n\t tv_sec: %ld\t\ttv_nsec: %ld\n",
+ psinfo.pr_start.tv_sec, psinfo.pr_start.tv_nsec);
+
+ mdb_printf("\tpr_time:\n\t tv_sec: %ld\t\t\ttv_nsec: %ld\n",
+ psinfo.pr_time.tv_sec, psinfo.pr_time.tv_nsec);
+
+ mdb_printf("\tpr_pri: %d\t\t\tpr_oldpri: %d\n",
+ psinfo.pr_lwp.pr_pri, psinfo.pr_lwp.pr_oldpri);
+
+ mdb_printf("\tpr_cpu: %d\n", psinfo.pr_lwp.pr_cpu);
+
+ mdb_printf("\tpr_clname: %s\n", psinfo.pr_lwp.pr_clname);
+
+ mdb_printf("\tpr_fname: %s\n", psinfo.pr_fname);
+
+ mdb_printf("\tpr_psargs: %s\n", psinfo.pr_psargs);
+
+
+ mdb_printf("\tpr_syscall: [ %s ]\n",
+ proc_sysname(psinfo.pr_lwp.pr_syscall, sysname,
+ sizeof (sysname)));
+
+ mdb_printf("\tpr_ctime:\n\t tv_sec: %ld\t\t\ttv_nsec: %ld\n",
+ psinfo.pr_ctime.tv_sec, psinfo.pr_ctime.tv_nsec);
+
+ mdb_printf("\tpr_argc: %d\t\t\tpr_argv: 0x%lx\n",
+ psinfo.pr_argc, (ulong_t)psinfo.pr_argv);
+
+ mdb_snprintf(buff, sizeof (buff), "0x%lx", (ulong_t)psinfo.pr_envp);
+
+ bufflen = strlen(buff);
+
+ mdb_printf("\tpr_envp: %s%*spr_wstat: %d\n",
+ buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
+ psinfo.pr_wstat);
+
+ cpu = pct_value(psinfo.pr_pctcpu);
+ mem = pct_value(psinfo.pr_pctmem);
+
+ mdb_printf("\tpr_pctcpu: %u.%u%%\t\tpr_pctmem: %u.%u%%\n",
+ cpu / 10, cpu % 10, mem / 10, mem % 10);
+
+ mdb_printf("\tpr_euid: %u\t\t\tpr_egid: %u\n",
+ psinfo.pr_euid, psinfo.pr_egid);
+
+ mdb_printf("\tpr_dmodel: [%s]\n",
+ proc_dmodelname(psinfo.pr_dmodel, buff, sizeof (buff)));
+}
+
+static void
+psinfo_sum(psinfo_t psinfo)
+{
+ const int minspaces = 2;
+ const int spbcols = 23;
+ char buff[64];
+ int bufflen;
+ int ms;
+
+ mdb_printf("PID: %6d (process id)\t\t"
+ "UID: %4u (real user id)\n",
+ psinfo.pr_pid, psinfo.pr_uid);
+
+ mdb_printf("PPID: %6d (parent process id)\tEUID: %4d"
+ " (effective user id)\n", psinfo.pr_ppid, psinfo.pr_euid);
+
+ mdb_printf("PGID: %6d (process group id)\tGID: %4u"
+ " (real group id)\n", psinfo.pr_pgid, psinfo.pr_gid);
+
+ mdb_printf("SID: %6d (session id)\t\tEGID: %4u"
+ " (effective group id)\n",
+ psinfo.pr_sid, psinfo.pr_egid);
+
+ mdb_printf("ZONEID: %6d\t\t\t\tCONTRACT:%4d\n",
+ psinfo.pr_zoneid, psinfo.pr_contract);
+
+ mdb_printf("PROJECT:%6d \t\t\t\tTASK: %4d\n\n",
+ psinfo.pr_projid, psinfo.pr_taskid);
+
+ mdb_printf("START: %Y (wall timestamp when the process started)\n",
+ psinfo.pr_start);
+
+ ms = NSEC2MSEC(psinfo.pr_time.tv_nsec);
+
+ mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds",
+ psinfo.pr_time.tv_sec, ms);
+
+ bufflen = strlen(buff);
+
+ mdb_printf("TIME: %s%*s"
+ "(CPU time used by this process)\n",
+ buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
+
+ ms = NSEC2MSEC(psinfo.pr_ctime.tv_nsec);
+
+ mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds",
+ psinfo.pr_ctime.tv_sec, ms);
+
+ mdb_printf("CTIME: %s%*s"
+ "(CPU time used by child processes)\n",
+ buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
+
+ mdb_snprintf(buff, sizeof (buff), "%s", psinfo.pr_fname);
+ bufflen = strlen(buff);
+
+ mdb_printf("FNAME: %s%*s(name of the program executed)\n",
+ buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
+
+ mdb_printf("PSARGS: \"%s\"\n", psinfo.pr_psargs);
+}
+
+void
+d_psinfo_dcmd_help(void)
+{
+ mdb_printf(
+ "Prints relevant fields from psinfo_t data and\n"
+ "most fields from NT_PRPSINFO note section\n\n"
+ "Usage: ::psinfo [-v]\n"
+ "Options:\n"
+ " -v verbose output\n");
+}
+
+static int
+d_psinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ psinfo_t psinfo;
+ uint_t opt_v = FALSE;
+ ssize_t nbytes;
+
+ if (mdb_getopts(argc, argv, 'v',
+ MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
+ return (DCMD_USAGE);
+
+ nbytes = mdb_get_xdata("psinfo", NULL, 0);
+
+ if (nbytes <= 0) {
+ mdb_warn("information not available for analysis");
+ return (DCMD_ERR);
+ }
+
+ if (mdb_get_xdata("psinfo", &psinfo, nbytes) != nbytes) {
+ mdb_warn("failed to read psinfo information");
+ return (DCMD_ERR);
+ }
+
+ if (opt_v) {
+ psinfo_raw(psinfo);
+ } else {
+ psinfo_sum(psinfo);
+ }
+
return (DCMD_OK);
}
@@ -1215,6 +1435,8 @@ static const mdb_dcmd_t dcmds[] = {
{ "ulwp", ":", "print ulwp_t structure", d_ulwp, NULL },
{ "uberdata", ":", "print uberdata_t structure", d_uberdata, NULL },
{ "tsd", ":-k key", "print tsd for this thread", d_tsd, NULL },
+ { "psinfo", "[-v]", "prints relevant psinfo_t data", d_psinfo,
+ d_psinfo_dcmd_help },
{ NULL }
};
diff --git a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
index 3b350a19ba..24e690f98a 100644
--- a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
+++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c
@@ -20,9 +20,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
@@ -35,6 +36,12 @@
#include <netsmb/smb_rq.h>
#include <netsmb/smb_pass.h>
+#ifdef _KERNEL
+#define NSMB_OBJNAME "nsmb"
+#else
+#define NSMB_OBJNAME "libfknsmb.so.1"
+#endif
+
#define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */
#define OPT_RECURSE 0x0002 /* recursive display */
@@ -66,12 +73,13 @@ print_str(uintptr_t addr)
*/
typedef struct smb_co_walk_data {
uintptr_t pp;
- int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE */
+ int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE, ... */
int size; /* sizeof (union member) */
union co_u {
smb_connobj_t co; /* copy of the list element */
smb_vc_t vc;
smb_share_t ss;
+ smb_fh_t fh;
} u;
} smb_co_walk_data_t;
@@ -108,6 +116,9 @@ smb_co_walk_init(mdb_walk_state_t *wsp, int level)
case SMBL_SHARE:
smbw->size = sizeof (smbw->u.ss);
break;
+ case SMBL_FH:
+ smbw->size = sizeof (smbw->u.fh);
+ break;
default:
smbw->size = sizeof (smbw->u);
break;
@@ -146,7 +157,7 @@ smb_vc_walk_init(mdb_walk_state_t *wsp)
}
/* Locate the VC list head. */
- if (mdb_lookup_by_obj("nsmb", "smb_vclist", &sym)) {
+ if (mdb_lookup_by_obj(NSMB_OBJNAME, "smb_vclist", &sym)) {
mdb_warn("failed to lookup `smb_vclist'\n");
return (WALK_ERR);
}
@@ -174,6 +185,24 @@ smb_ss_walk_init(mdb_walk_state_t *wsp)
}
/*
+ * Walk the file hande list below some share.
+ */
+int
+smb_fh_walk_init(mdb_walk_state_t *wsp)
+{
+
+ /*
+ * Initial walk_addr is address of parent (share)
+ */
+ if (wsp->walk_addr == 0) {
+ mdb_warn("::walk smb_fh does not support global walks\n");
+ return (WALK_ERR);
+ }
+
+ return (smb_co_walk_init(wsp, SMBL_FH));
+}
+
+/*
* Common walk_step for walking structs inherited
* from smb_connobj_t (smb_vc_t, smb_share_t)
*/
@@ -215,6 +244,30 @@ typedef struct smb_co_cbdata {
} smb_co_cbdata_t;
/*
+ * Call-back function for walking a file handle list.
+ */
+/* ARGSUSED */
+int
+smb_fh_cb(uintptr_t addr, const void *data, void *arg)
+{
+ const smb_fh_t *fhp = data;
+ // smb_co_cbdata_t *cbd = arg;
+
+ mdb_inc_indent(2);
+ mdb_printf(" %-p", addr);
+ if (fhp->fh_fid2.fid_volatile != 0) {
+ mdb_printf("\t0x%llx\n",
+ (long long) fhp->fh_fid2.fid_volatile);
+ } else {
+ mdb_printf("\t0x%x\n", fhp->fh_fid1);
+ }
+
+ mdb_dec_indent(2);
+
+ return (WALK_NEXT);
+}
+
+/*
* Call-back function for walking a share list.
*/
int
@@ -222,12 +275,20 @@ smb_ss_cb(uintptr_t addr, const void *data, void *arg)
{
const smb_share_t *ssp = data;
smb_co_cbdata_t *cbd = arg;
+ uint32_t tid;
- mdb_printf(" %-p\t%s\n", addr, ssp->ss_name);
+ tid = ssp->ss2_tree_id;
+ if (tid == 0)
+ tid = ssp->ss_tid;
- if (cbd->flags & OPT_VERBOSE) {
+ mdb_printf(" %-p\t0x%x\t%s\n", addr, tid, ssp->ss_name);
+
+ if (cbd->flags & OPT_RECURSE) {
mdb_inc_indent(2);
- /* Anything wanted here? */
+ if (mdb_pwalk("nsmb_fh", smb_fh_cb, cbd, addr) < 0) {
+ mdb_warn("failed to walk 'nsmb_fh'");
+ /* Don't: return (WALK_ERR); */
+ }
mdb_dec_indent(2);
}
@@ -408,6 +469,7 @@ rqlist_walk_step(mdb_walk_state_t *wsp)
typedef struct rqlist_cbdata {
int printed_header;
+ int vcflags;
uintptr_t uid; /* optional filtering by UID */
} rqlist_cbdata_t;
@@ -423,8 +485,13 @@ rqlist_cb(uintptr_t addr, const void *data, void *arg)
}
mdb_printf(" %-p", addr); /* smb_rq_t */
- mdb_printf(" x%04x", rq->sr_mid);
- mdb_printf(" x%02x", rq->sr_cmd);
+ if ((cbd->vcflags & SMBV_SMB2) != 0) {
+ mdb_printf(" x%04llx", (long long)rq->sr2_messageid);
+ mdb_printf(" x%02x", rq->sr2_command);
+ } else {
+ mdb_printf(" x%04x", rq->sr_mid);
+ mdb_printf(" x%02x", rq->sr_cmd);
+ }
mdb_printf(" %d", rq->sr_state);
mdb_printf(" x%x", rq->sr_flags);
mdb_printf("\n");
@@ -437,9 +504,20 @@ int
rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
rqlist_cbdata_t cbd;
+ smb_vc_t *vcp;
+ size_t vcsz;
memset(&cbd, 0, sizeof (cbd));
+ /* Need the VC again to get */
+ vcsz = sizeof (*vcp);
+ vcp = mdb_alloc(vcsz, UM_SLEEP | UM_GC);
+ if (mdb_vread(vcp, vcsz, addr) != vcsz) {
+ mdb_warn("cannot read VC from %p", addr);
+ return (DCMD_ERR);
+ }
+ cbd.vcflags = vcp->vc_flags;
+
/*
* Initial walk_addr is address of parent (VC)
*/
@@ -471,7 +549,7 @@ pwtree_walk_init(mdb_walk_state_t *wsp)
return (WALK_ERR);
}
- if (mdb_lookup_by_obj("nsmb", "smb_ptd", &sym) == -1) {
+ if (mdb_lookup_by_obj(NSMB_OBJNAME, "smb_ptd", &sym) == -1) {
mdb_warn("failed to find symbol 'smb_ptd'");
return (WALK_ERR);
}
@@ -600,6 +678,8 @@ static const mdb_walker_t walkers[] = {
smb_vc_walk_init, smb_co_walk_step, NULL },
{ "nsmb_ss", "walk nsmb share list for some VC",
smb_ss_walk_init, smb_co_walk_step, NULL },
+ { "nsmb_fh", "walk nsmb share list for some VC",
+ smb_fh_walk_init, smb_co_walk_step, NULL },
{ "nsmb_rqlist", "walk request list for some VC",
rqlist_walk_init, rqlist_walk_step, NULL },
{ "nsmb_pwtree", "walk passord AVL tree",
diff --git a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
index 6be9e2a0c4..e787fd86e5 100644
--- a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
+++ b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c
@@ -20,13 +20,19 @@
*/
/*
- * 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.
*/
-#include <sys/mdb_modapi.h>
#include <sys/types.h>
+#include <sys/mdb_modapi.h>
+
+#ifdef _USER
+#include "../genunix/avl.h"
+#define _FAKE_KERNEL
+#endif
+
#include <sys/refstr_impl.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
@@ -149,7 +155,7 @@ smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
if (!(flags & DCMD_ADDRSPEC)) {
- if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd)
+ if (mdb_walk("vfs", smbfs_vfs_cb, cbd)
== -1) {
mdb_warn("can't walk smbfs vfs");
return (DCMD_ERR);
@@ -238,7 +244,7 @@ smbfs_node_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
addr += OFFSETOF(smbmntinfo_t, smi_hash_avl);
- if (mdb_pwalk("genunix`avl", smbfs_node_cb, cbd, addr) == -1) {
+ if (mdb_pwalk("avl", smbfs_node_cb, cbd, addr) == -1) {
mdb_warn("cannot walk smbfs nodes");
return (DCMD_ERR);
}
@@ -267,10 +273,59 @@ static const mdb_dcmd_t dcmds[] = {
{NULL}
};
+#ifdef _USER
+/*
+ * Sadly, can't just compile ../genunix/vfs.c with this since
+ * it has become a catch-all for FS-specific headers etc.
+ */
+int
+vfs_walk_init(mdb_walk_state_t *wsp)
+{
+ if (wsp->walk_addr == NULL &&
+ mdb_readvar(&wsp->walk_addr, "rootvfs") == -1) {
+ mdb_warn("failed to read 'rootvfs'");
+ return (WALK_ERR);
+ }
+
+ wsp->walk_data = (void *)wsp->walk_addr;
+ return (WALK_NEXT);
+}
+
+int
+vfs_walk_step(mdb_walk_state_t *wsp)
+{
+ vfs_t vfs;
+ int status;
+
+ if (mdb_vread(&vfs, sizeof (vfs), wsp->walk_addr) == -1) {
+ mdb_warn("failed to read vfs_t at %p", wsp->walk_addr);
+ return (WALK_DONE);
+ }
+
+ status = wsp->walk_callback(wsp->walk_addr, &vfs, wsp->walk_cbdata);
+
+ if (vfs.vfs_next == wsp->walk_data)
+ return (WALK_DONE);
+
+ wsp->walk_addr = (uintptr_t)vfs.vfs_next;
+
+ return (status);
+}
+#endif // _USER
+
static const mdb_walker_t walkers[] = {
+#ifdef _USER
+ /* from avl.c */
+ { AVL_WALK_NAME, AVL_WALK_DESC,
+ avl_walk_init, avl_walk_step, avl_walk_fini },
+ /* from vfs.c */
+ { "vfs", "walk file system list",
+ vfs_walk_init, vfs_walk_step },
+#endif // _USER
{NULL}
};
+
static const mdb_modinfo_t modinfo = {
MDB_API_VERSION,
dcmds,
diff --git a/usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile b/usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile
new file mode 100644
index 0000000000..e6c6109a50
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/amd64/libfknsmb/Makefile
@@ -0,0 +1,49 @@
+#
+# 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 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfknsmb.so
+MDBTGT = proc
+
+MODSRCS = nsmb.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/nsmb
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbclnt/libfknsmb/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+CPPFLAGS += -D_FAKE_KERNEL
+
+CSTD= $(CSTD_GNU99)
diff --git a/usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile b/usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile
new file mode 100644
index 0000000000..51b6d01c6d
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/amd64/libfksmbfs/Makefile
@@ -0,0 +1,56 @@
+#
+# 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 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfksmbfs.so
+MDBTGT = proc
+
+MODSRCS = smbfs.c avl.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/smbfs
+GENUNIX_DIR = ../../../common/modules/genunix
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbsrv/libfksmbsrv/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+
+CSTD= $(CSTD_GNU99)
+
+dmod/%.o: $(GENUNIX_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+dmod/%.ln: $(GENUNIX_DIR)/%.c
+ $(LINT.c) -c $<
diff --git a/usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile b/usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile
new file mode 100644
index 0000000000..c50ac1c69d
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/ia32/libfknsmb/Makefile
@@ -0,0 +1,48 @@
+#
+# 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 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfknsmb.so
+MDBTGT = proc
+
+MODSRCS = nsmb.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/nsmb
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbclnt/libfknsmb/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+CPPFLAGS += -D_FAKE_KERNEL
+
+CSTD= $(CSTD_GNU99)
diff --git a/usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile b/usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile
new file mode 100644
index 0000000000..892908da7a
--- /dev/null
+++ b/usr/src/cmd/mdb/intel/ia32/libfksmbfs/Makefile
@@ -0,0 +1,55 @@
+#
+# 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 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+#
+
+MODULE = libfksmbfs.so
+MDBTGT = proc
+
+MODSRCS = smbfs.c avl.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+MODSRCS_DIR = ../../../common/modules/smbfs
+GENUNIX_DIR = ../../../common/modules/genunix
+
+# Note: need our sys includes _before_ ENVCPPFLAGS, proto etc.
+CPPFLAGS.first += -I$(SRC)/lib/smbsrv/libfksmbsrv/common
+CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common
+
+CPPFLAGS += -I$(SRC)/uts/common/fs/smbclnt/
+CPPFLAGS += -I$(SRC)/uts/common
+
+CSTD= $(CSTD_GNU99)
+
+dmod/%.o: $(GENUNIX_DIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+dmod/%.ln: $(GENUNIX_DIR)/%.c
+ $(LINT.c) -c $<
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb b/usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb
new file mode 100644
index 0000000000..18e9053ce4
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb
@@ -0,0 +1,2 @@
+-1,10=E
+1<<0t63,10=E
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb.out
new file mode 100644
index 0000000000..2268a48be9
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-E.mdb.out
@@ -0,0 +1,12 @@
+ 18446744073709551615 18446744073709551615 18446744073709551615
+ 18446744073709551615 18446744073709551615 18446744073709551615
+ 18446744073709551615 18446744073709551615 18446744073709551615
+ 18446744073709551615 18446744073709551615 18446744073709551615
+ 18446744073709551615 18446744073709551615 18446744073709551615
+ 18446744073709551615
+ 9223372036854775808 9223372036854775808 9223372036854775808
+ 9223372036854775808 9223372036854775808 9223372036854775808
+ 9223372036854775808 9223372036854775808 9223372036854775808
+ 9223372036854775808 9223372036854775808 9223372036854775808
+ 9223372036854775808 9223372036854775808 9223372036854775808
+ 9223372036854775808
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb b/usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb
new file mode 100644
index 0000000000..f10f78336b
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb
@@ -0,0 +1,4 @@
+-1,10=G
+1<<0t63,10=G
+1<<0t60,10=G
+1<<0t57,10=G
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb.out
new file mode 100644
index 0000000000..f1dfd5193b
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-G.mdb.out
@@ -0,0 +1,32 @@
+ 1777777777777777777777 1777777777777777777777
+ 1777777777777777777777 1777777777777777777777
+ 1777777777777777777777 1777777777777777777777
+ 1777777777777777777777 1777777777777777777777
+ 1777777777777777777777 1777777777777777777777
+ 1777777777777777777777 1777777777777777777777
+ 1777777777777777777777 1777777777777777777777
+ 1777777777777777777777 1777777777777777777777
+ 1000000000000000000000 1000000000000000000000
+ 1000000000000000000000 1000000000000000000000
+ 1000000000000000000000 1000000000000000000000
+ 1000000000000000000000 1000000000000000000000
+ 1000000000000000000000 1000000000000000000000
+ 1000000000000000000000 1000000000000000000000
+ 1000000000000000000000 1000000000000000000000
+ 1000000000000000000000 1000000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb b/usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb
new file mode 100644
index 0000000000..ff9dabbce9
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb
@@ -0,0 +1,3 @@
+-1,10=J
+1<<0t63,10=J
+1<<0t59,10=J
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb.out
new file mode 100644
index 0000000000..644fee231e
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-J.mdb.out
@@ -0,0 +1,16 @@
+ ffffffffffffffff ffffffffffffffff ffffffffffffffff
+ ffffffffffffffff ffffffffffffffff ffffffffffffffff
+ ffffffffffffffff ffffffffffffffff ffffffffffffffff
+ ffffffffffffffff ffffffffffffffff ffffffffffffffff
+ ffffffffffffffff ffffffffffffffff ffffffffffffffff
+ ffffffffffffffff
+ 8000000000000000 8000000000000000 8000000000000000
+ 8000000000000000 8000000000000000 8000000000000000
+ 8000000000000000 8000000000000000 8000000000000000
+ 8000000000000000 8000000000000000 8000000000000000
+ 8000000000000000 8000000000000000 8000000000000000
+ 8000000000000000
+ 800000000000000 800000000000000 800000000000000 800000000000000
+ 800000000000000 800000000000000 800000000000000 800000000000000
+ 800000000000000 800000000000000 800000000000000 800000000000000
+ 800000000000000 800000000000000 800000000000000 800000000000000
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb b/usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb
new file mode 100644
index 0000000000..88928fda29
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb
@@ -0,0 +1 @@
+1<<0t63,10=P
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb.out
new file mode 100644
index 0000000000..65e05e7220
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-P.mdb.out
@@ -0,0 +1,6 @@
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb b/usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb
new file mode 100644
index 0000000000..9f55408276
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb
@@ -0,0 +1,4 @@
+1=RRRR
+1<<0t62=RRR
+1<<0t63=RRR
+-1=RRRR
diff --git a/usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb.out
new file mode 100644
index 0000000000..f05b0bac4d
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-cap-R.mdb.out
@@ -0,0 +1,14 @@
+ 1
+ 1
+ 1
+ 1
+ 100000000000000000000000000000000000000000000000000000000000000
+ 100000000000000000000000000000000000000000000000000000000000000
+ 100000000000000000000000000000000000000000000000000000000000000
+ 1000000000000000000000000000000000000000000000000000000000000000
+ 1000000000000000000000000000000000000000000000000000000000000000
+ 1000000000000000000000000000000000000000000000000000000000000000
+ 1111111111111111111111111111111111111111111111111111111111111111
+ 1111111111111111111111111111111111111111111111111111111111111111
+ 1111111111111111111111111111111111111111111111111111111111111111
+ 1111111111111111111111111111111111111111111111111111111111111111
diff --git a/usr/src/cmd/mdb/test/format/tst.format-e.mdb b/usr/src/cmd/mdb/test/format/tst.format-e.mdb
new file mode 100644
index 0000000000..79d4b25af4
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-e.mdb
@@ -0,0 +1,2 @@
+-1,10=e
+1<<0t63,10=e
diff --git a/usr/src/cmd/mdb/test/format/tst.format-e.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-e.mdb.out
new file mode 100644
index 0000000000..909c53cbc0
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-e.mdb.out
@@ -0,0 +1,12 @@
+ -1 -1 -1
+ -1 -1 -1
+ -1 -1 -1
+ -1 -1 -1
+ -1 -1 -1
+ -1
+ -9223372036854775808 -9223372036854775808 -9223372036854775808
+ -9223372036854775808 -9223372036854775808 -9223372036854775808
+ -9223372036854775808 -9223372036854775808 -9223372036854775808
+ -9223372036854775808 -9223372036854775808 -9223372036854775808
+ -9223372036854775808 -9223372036854775808 -9223372036854775808
+ -9223372036854775808
diff --git a/usr/src/cmd/mdb/test/format/tst.format-g.mdb b/usr/src/cmd/mdb/test/format/tst.format-g.mdb
new file mode 100644
index 0000000000..b3397d21ed
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-g.mdb
@@ -0,0 +1,5 @@
+-1,10=g
+1<<0t63,10=g
+(1<<0t63)-1,10=g
+1<<0t60,10=g
+1<<0t57,10=g
diff --git a/usr/src/cmd/mdb/test/format/tst.format-g.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-g.mdb.out
new file mode 100644
index 0000000000..c46dff3594
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-g.mdb.out
@@ -0,0 +1,40 @@
+ -1 -1
+ -1 -1
+ -1 -1
+ -1 -1
+ -1 -1
+ -1 -1
+ -1 -1
+ -1 -1
+ -1000000000000000000000 -1000000000000000000000
+ -1000000000000000000000 -1000000000000000000000
+ -1000000000000000000000 -1000000000000000000000
+ -1000000000000000000000 -1000000000000000000000
+ -1000000000000000000000 -1000000000000000000000
+ -1000000000000000000000 -1000000000000000000000
+ -1000000000000000000000 -1000000000000000000000
+ -1000000000000000000000 -1000000000000000000000
+ 777777777777777777777 777777777777777777777
+ 777777777777777777777 777777777777777777777
+ 777777777777777777777 777777777777777777777
+ 777777777777777777777 777777777777777777777
+ 777777777777777777777 777777777777777777777
+ 777777777777777777777 777777777777777777777
+ 777777777777777777777 777777777777777777777
+ 777777777777777777777 777777777777777777777
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 100000000000000000000 100000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
+ 10000000000000000000 10000000000000000000
diff --git a/usr/src/cmd/mdb/test/format/tst.format-j.mdb b/usr/src/cmd/mdb/test/format/tst.format-j.mdb
new file mode 100644
index 0000000000..875a1e178f
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-j.mdb
@@ -0,0 +1,8 @@
+-1=JRjnn
+0=JRjnn
+1=JRjnn
+feedface=JRjnn
+badfeedcafe=JRjnn
+deadba11e12a=JRjnn
+badb100d=JRjnn
+baddefec8ed=JRjnn
diff --git a/usr/src/cmd/mdb/test/format/tst.format-j.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-j.mdb.out
new file mode 100644
index 0000000000..3f5fa0afaf
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-j.mdb.out
@@ -0,0 +1,238 @@
+ ffffffffffffffff
+ 1111111111111111111111111111111111111111111111111111111111111111
+ 1111111111111111111111111111111111111111111111111111111111111111
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||+-- bit 0 mask 0x0000000000000001
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||+--- bit 1 mask 0x0000000000000002
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||+---- bit 2 mask 0x0000000000000004
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||+----- bit 3 mask 0x0000000000000008
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||+------ bit 4 mask 0x0000000000000010
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||+------- bit 5 mask 0x0000000000000020
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||+-------- bit 6 mask 0x0000000000000040
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||+--------- bit 7 mask 0x0000000000000080
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||+---------- bit 8 mask 0x0000000000000100
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||||+----------- bit 9 mask 0x0000000000000200
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||+------------ bit 10 mask 0x0000000000000400
+ ||||||||||||||||||||||||||||||||||||||||||||||||||||+------------- bit 11 mask 0x0000000000000800
+ |||||||||||||||||||||||||||||||||||||||||||||||||||+-------------- bit 12 mask 0x0000000000001000
+ ||||||||||||||||||||||||||||||||||||||||||||||||||+--------------- bit 13 mask 0x0000000000002000
+ |||||||||||||||||||||||||||||||||||||||||||||||||+---------------- bit 14 mask 0x0000000000004000
+ ||||||||||||||||||||||||||||||||||||||||||||||||+----------------- bit 15 mask 0x0000000000008000
+ |||||||||||||||||||||||||||||||||||||||||||||||+------------------ bit 16 mask 0x0000000000010000
+ ||||||||||||||||||||||||||||||||||||||||||||||+------------------- bit 17 mask 0x0000000000020000
+ |||||||||||||||||||||||||||||||||||||||||||||+-------------------- bit 18 mask 0x0000000000040000
+ ||||||||||||||||||||||||||||||||||||||||||||+--------------------- bit 19 mask 0x0000000000080000
+ |||||||||||||||||||||||||||||||||||||||||||+---------------------- bit 20 mask 0x0000000000100000
+ ||||||||||||||||||||||||||||||||||||||||||+----------------------- bit 21 mask 0x0000000000200000
+ |||||||||||||||||||||||||||||||||||||||||+------------------------ bit 22 mask 0x0000000000400000
+ ||||||||||||||||||||||||||||||||||||||||+------------------------- bit 23 mask 0x0000000000800000
+ |||||||||||||||||||||||||||||||||||||||+-------------------------- bit 24 mask 0x0000000001000000
+ ||||||||||||||||||||||||||||||||||||||+--------------------------- bit 25 mask 0x0000000002000000
+ |||||||||||||||||||||||||||||||||||||+---------------------------- bit 26 mask 0x0000000004000000
+ ||||||||||||||||||||||||||||||||||||+----------------------------- bit 27 mask 0x0000000008000000
+ |||||||||||||||||||||||||||||||||||+------------------------------ bit 28 mask 0x0000000010000000
+ ||||||||||||||||||||||||||||||||||+------------------------------- bit 29 mask 0x0000000020000000
+ |||||||||||||||||||||||||||||||||+-------------------------------- bit 30 mask 0x0000000040000000
+ ||||||||||||||||||||||||||||||||+--------------------------------- bit 31 mask 0x0000000080000000
+ |||||||||||||||||||||||||||||||+---------------------------------- bit 32 mask 0x0000000100000000
+ ||||||||||||||||||||||||||||||+----------------------------------- bit 33 mask 0x0000000200000000
+ |||||||||||||||||||||||||||||+------------------------------------ bit 34 mask 0x0000000400000000
+ ||||||||||||||||||||||||||||+------------------------------------- bit 35 mask 0x0000000800000000
+ |||||||||||||||||||||||||||+-------------------------------------- bit 36 mask 0x0000001000000000
+ ||||||||||||||||||||||||||+--------------------------------------- bit 37 mask 0x0000002000000000
+ |||||||||||||||||||||||||+---------------------------------------- bit 38 mask 0x0000004000000000
+ ||||||||||||||||||||||||+----------------------------------------- bit 39 mask 0x0000008000000000
+ |||||||||||||||||||||||+------------------------------------------ bit 40 mask 0x0000010000000000
+ ||||||||||||||||||||||+------------------------------------------- bit 41 mask 0x0000020000000000
+ |||||||||||||||||||||+-------------------------------------------- bit 42 mask 0x0000040000000000
+ ||||||||||||||||||||+--------------------------------------------- bit 43 mask 0x0000080000000000
+ |||||||||||||||||||+---------------------------------------------- bit 44 mask 0x0000100000000000
+ ||||||||||||||||||+----------------------------------------------- bit 45 mask 0x0000200000000000
+ |||||||||||||||||+------------------------------------------------ bit 46 mask 0x0000400000000000
+ ||||||||||||||||+------------------------------------------------- bit 47 mask 0x0000800000000000
+ |||||||||||||||+-------------------------------------------------- bit 48 mask 0x0001000000000000
+ ||||||||||||||+--------------------------------------------------- bit 49 mask 0x0002000000000000
+ |||||||||||||+---------------------------------------------------- bit 50 mask 0x0004000000000000
+ ||||||||||||+----------------------------------------------------- bit 51 mask 0x0008000000000000
+ |||||||||||+------------------------------------------------------ bit 52 mask 0x0010000000000000
+ ||||||||||+------------------------------------------------------- bit 53 mask 0x0020000000000000
+ |||||||||+-------------------------------------------------------- bit 54 mask 0x0040000000000000
+ ||||||||+--------------------------------------------------------- bit 55 mask 0x0080000000000000
+ |||||||+---------------------------------------------------------- bit 56 mask 0x0100000000000000
+ ||||||+----------------------------------------------------------- bit 57 mask 0x0200000000000000
+ |||||+------------------------------------------------------------ bit 58 mask 0x0400000000000000
+ ||||+------------------------------------------------------------- bit 59 mask 0x0800000000000000
+ |||+-------------------------------------------------------------- bit 60 mask 0x1000000000000000
+ ||+--------------------------------------------------------------- bit 61 mask 0x2000000000000000
+ |+---------------------------------------------------------------- bit 62 mask 0x4000000000000000
+ +----------------------------------------------------------------- bit 63 mask 0x8000000000000000
+
+
+ 0
+ 0
+ 0
+
+
+ 1
+ 1
+ 1
+ |
+ +-- bit 0 mask 0x1
+
+
+ feedface
+ 11111110111011011111101011001110
+ 11111110111011011111101011001110
+ ||||||| ||| || |||||| | || |||
+ ||||||| ||| || |||||| | || ||+--- bit 1 mask 0x00000002
+ ||||||| ||| || |||||| | || |+---- bit 2 mask 0x00000004
+ ||||||| ||| || |||||| | || +----- bit 3 mask 0x00000008
+ ||||||| ||| || |||||| | |+-------- bit 6 mask 0x00000040
+ ||||||| ||| || |||||| | +--------- bit 7 mask 0x00000080
+ ||||||| ||| || |||||| +----------- bit 9 mask 0x00000200
+ ||||||| ||| || |||||+------------- bit 11 mask 0x00000800
+ ||||||| ||| || ||||+-------------- bit 12 mask 0x00001000
+ ||||||| ||| || |||+--------------- bit 13 mask 0x00002000
+ ||||||| ||| || ||+---------------- bit 14 mask 0x00004000
+ ||||||| ||| || |+----------------- bit 15 mask 0x00008000
+ ||||||| ||| || +------------------ bit 16 mask 0x00010000
+ ||||||| ||| |+-------------------- bit 18 mask 0x00040000
+ ||||||| ||| +--------------------- bit 19 mask 0x00080000
+ ||||||| ||+----------------------- bit 21 mask 0x00200000
+ ||||||| |+------------------------ bit 22 mask 0x00400000
+ ||||||| +------------------------- bit 23 mask 0x00800000
+ ||||||+--------------------------- bit 25 mask 0x02000000
+ |||||+---------------------------- bit 26 mask 0x04000000
+ ||||+----------------------------- bit 27 mask 0x08000000
+ |||+------------------------------ bit 28 mask 0x10000000
+ ||+------------------------------- bit 29 mask 0x20000000
+ |+-------------------------------- bit 30 mask 0x40000000
+ +--------------------------------- bit 31 mask 0x80000000
+
+
+ badfeedcafe
+ 10111010110111111110111011011100101011111110
+ 10111010110111111110111011011100101011111110
+ | ||| | || |||||||| ||| || ||| | | |||||||
+ | ||| | || |||||||| ||| || ||| | | ||||||+--- bit 1 mask 0x00000000002
+ | ||| | || |||||||| ||| || ||| | | |||||+---- bit 2 mask 0x00000000004
+ | ||| | || |||||||| ||| || ||| | | ||||+----- bit 3 mask 0x00000000008
+ | ||| | || |||||||| ||| || ||| | | |||+------ bit 4 mask 0x00000000010
+ | ||| | || |||||||| ||| || ||| | | ||+------- bit 5 mask 0x00000000020
+ | ||| | || |||||||| ||| || ||| | | |+-------- bit 6 mask 0x00000000040
+ | ||| | || |||||||| ||| || ||| | | +--------- bit 7 mask 0x00000000080
+ | ||| | || |||||||| ||| || ||| | +----------- bit 9 mask 0x00000000200
+ | ||| | || |||||||| ||| || ||| +------------- bit 11 mask 0x00000000800
+ | ||| | || |||||||| ||| || ||+---------------- bit 14 mask 0x00000004000
+ | ||| | || |||||||| ||| || |+----------------- bit 15 mask 0x00000008000
+ | ||| | || |||||||| ||| || +------------------ bit 16 mask 0x00000010000
+ | ||| | || |||||||| ||| |+-------------------- bit 18 mask 0x00000040000
+ | ||| | || |||||||| ||| +--------------------- bit 19 mask 0x00000080000
+ | ||| | || |||||||| ||+----------------------- bit 21 mask 0x00000200000
+ | ||| | || |||||||| |+------------------------ bit 22 mask 0x00000400000
+ | ||| | || |||||||| +------------------------- bit 23 mask 0x00000800000
+ | ||| | || |||||||+--------------------------- bit 25 mask 0x00002000000
+ | ||| | || ||||||+---------------------------- bit 26 mask 0x00004000000
+ | ||| | || |||||+----------------------------- bit 27 mask 0x00008000000
+ | ||| | || ||||+------------------------------ bit 28 mask 0x00010000000
+ | ||| | || |||+------------------------------- bit 29 mask 0x00020000000
+ | ||| | || ||+-------------------------------- bit 30 mask 0x00040000000
+ | ||| | || |+--------------------------------- bit 31 mask 0x00080000000
+ | ||| | || +---------------------------------- bit 32 mask 0x00100000000
+ | ||| | |+------------------------------------ bit 34 mask 0x00400000000
+ | ||| | +------------------------------------- bit 35 mask 0x00800000000
+ | ||| +--------------------------------------- bit 37 mask 0x02000000000
+ | ||+----------------------------------------- bit 39 mask 0x08000000000
+ | |+------------------------------------------ bit 40 mask 0x10000000000
+ | +------------------------------------------- bit 41 mask 0x20000000000
+ +--------------------------------------------- bit 43 mask 0x80000000000
+
+
+ deadba11e12a
+ 110111101010110110111010000100011110000100101010
+ 110111101010110110111010000100011110000100101010
+ || |||| | | || || ||| | | |||| | | | |
+ || |||| | | || || ||| | | |||| | | | +--- bit 1 mask 0x000000000002
+ || |||| | | || || ||| | | |||| | | +----- bit 3 mask 0x000000000008
+ || |||| | | || || ||| | | |||| | +------- bit 5 mask 0x000000000020
+ || |||| | | || || ||| | | |||| +---------- bit 8 mask 0x000000000100
+ || |||| | | || || ||| | | |||+--------------- bit 13 mask 0x000000002000
+ || |||| | | || || ||| | | ||+---------------- bit 14 mask 0x000000004000
+ || |||| | | || || ||| | | |+----------------- bit 15 mask 0x000000008000
+ || |||| | | || || ||| | | +------------------ bit 16 mask 0x000000010000
+ || |||| | | || || ||| | +---------------------- bit 20 mask 0x000000100000
+ || |||| | | || || ||| +--------------------------- bit 25 mask 0x000002000000
+ || |||| | | || || ||+----------------------------- bit 27 mask 0x000008000000
+ || |||| | | || || |+------------------------------ bit 28 mask 0x000010000000
+ || |||| | | || || +------------------------------- bit 29 mask 0x000020000000
+ || |||| | | || |+--------------------------------- bit 31 mask 0x000080000000
+ || |||| | | || +---------------------------------- bit 32 mask 0x000100000000
+ || |||| | | |+------------------------------------ bit 34 mask 0x000400000000
+ || |||| | | +------------------------------------- bit 35 mask 0x000800000000
+ || |||| | +--------------------------------------- bit 37 mask 0x002000000000
+ || |||| +----------------------------------------- bit 39 mask 0x008000000000
+ || |||+------------------------------------------- bit 41 mask 0x020000000000
+ || ||+-------------------------------------------- bit 42 mask 0x040000000000
+ || |+--------------------------------------------- bit 43 mask 0x080000000000
+ || +---------------------------------------------- bit 44 mask 0x100000000000
+ |+------------------------------------------------ bit 46 mask 0x400000000000
+ +------------------------------------------------- bit 47 mask 0x800000000000
+
+
+ badb100d
+ 10111010110110110001000000001101
+ 10111010110110110001000000001101
+ | ||| | || || || | || |
+ | ||| | || || || | || +-- bit 0 mask 0x00000001
+ | ||| | || || || | |+---- bit 2 mask 0x00000004
+ | ||| | || || || | +----- bit 3 mask 0x00000008
+ | ||| | || || || +-------------- bit 12 mask 0x00001000
+ | ||| | || || |+------------------ bit 16 mask 0x00010000
+ | ||| | || || +------------------- bit 17 mask 0x00020000
+ | ||| | || |+--------------------- bit 19 mask 0x00080000
+ | ||| | || +---------------------- bit 20 mask 0x00100000
+ | ||| | |+------------------------ bit 22 mask 0x00400000
+ | ||| | +------------------------- bit 23 mask 0x00800000
+ | ||| +--------------------------- bit 25 mask 0x02000000
+ | ||+----------------------------- bit 27 mask 0x08000000
+ | |+------------------------------ bit 28 mask 0x10000000
+ | +------------------------------- bit 29 mask 0x20000000
+ +--------------------------------- bit 31 mask 0x80000000
+
+
+ baddefec8ed
+ 10111010110111011110111111101100100011101101
+ 10111010110111011110111111101100100011101101
+ | ||| | || ||| |||| ||||||| || | ||| || |
+ | ||| | || ||| |||| ||||||| || | ||| || +-- bit 0 mask 0x00000000001
+ | ||| | || ||| |||| ||||||| || | ||| |+---- bit 2 mask 0x00000000004
+ | ||| | || ||| |||| ||||||| || | ||| +----- bit 3 mask 0x00000000008
+ | ||| | || ||| |||| ||||||| || | ||+------- bit 5 mask 0x00000000020
+ | ||| | || ||| |||| ||||||| || | |+-------- bit 6 mask 0x00000000040
+ | ||| | || ||| |||| ||||||| || | +--------- bit 7 mask 0x00000000080
+ | ||| | || ||| |||| ||||||| || +------------- bit 11 mask 0x00000000800
+ | ||| | || ||| |||| ||||||| |+---------------- bit 14 mask 0x00000004000
+ | ||| | || ||| |||| ||||||| +----------------- bit 15 mask 0x00000008000
+ | ||| | || ||| |||| ||||||+------------------- bit 17 mask 0x00000020000
+ | ||| | || ||| |||| |||||+-------------------- bit 18 mask 0x00000040000
+ | ||| | || ||| |||| ||||+--------------------- bit 19 mask 0x00000080000
+ | ||| | || ||| |||| |||+---------------------- bit 20 mask 0x00000100000
+ | ||| | || ||| |||| ||+----------------------- bit 21 mask 0x00000200000
+ | ||| | || ||| |||| |+------------------------ bit 22 mask 0x00000400000
+ | ||| | || ||| |||| +------------------------- bit 23 mask 0x00000800000
+ | ||| | || ||| |||+--------------------------- bit 25 mask 0x00002000000
+ | ||| | || ||| ||+---------------------------- bit 26 mask 0x00004000000
+ | ||| | || ||| |+----------------------------- bit 27 mask 0x00008000000
+ | ||| | || ||| +------------------------------ bit 28 mask 0x00010000000
+ | ||| | || ||+-------------------------------- bit 30 mask 0x00040000000
+ | ||| | || |+--------------------------------- bit 31 mask 0x00080000000
+ | ||| | || +---------------------------------- bit 32 mask 0x00100000000
+ | ||| | |+------------------------------------ bit 34 mask 0x00400000000
+ | ||| | +------------------------------------- bit 35 mask 0x00800000000
+ | ||| +--------------------------------------- bit 37 mask 0x02000000000
+ | ||+----------------------------------------- bit 39 mask 0x08000000000
+ | |+------------------------------------------ bit 40 mask 0x10000000000
+ | +------------------------------------------- bit 41 mask 0x20000000000
+ +--------------------------------------------- bit 43 mask 0x80000000000
+
+
diff --git a/usr/src/cmd/mdb/test/format/tst.format-p.mdb b/usr/src/cmd/mdb/test/format/tst.format-p.mdb
new file mode 100644
index 0000000000..ee2b989d1b
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-p.mdb
@@ -0,0 +1 @@
+1<<0t63,10=p
diff --git a/usr/src/cmd/mdb/test/format/tst.format-p.mdb.out b/usr/src/cmd/mdb/test/format/tst.format-p.mdb.out
new file mode 100644
index 0000000000..65e05e7220
--- /dev/null
+++ b/usr/src/cmd/mdb/test/format/tst.format-p.mdb.out
@@ -0,0 +1,6 @@
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000 0x8000000000000000 0x8000000000000000
+ 0x8000000000000000
diff --git a/usr/src/cmd/mdb/test/options/tst.autowrap.mdb b/usr/src/cmd/mdb/test/options/tst.autowrap.mdb
index 5c62e288d3..5904cbf4c7 100644
--- a/usr/src/cmd/mdb/test/options/tst.autowrap.mdb
+++ b/usr/src/cmd/mdb/test/options/tst.autowrap.mdb
@@ -2,7 +2,14 @@
::typedef -c lp32
0::printf "Pack my box with five dozen liquor jugs. How razorback-jumping frogs can level six piqued gymnasts! Amazingly few discotheques provide jukeboxes.%d" int .
+0::printf "%-79d%d" int . .
+0::printf "%-80d%d" int . .
+0::printf "%-81d%d" int . .
+
::set -o autowrap
0::printf "Pack my box with five dozen liquor jugs. How razorback-jumping frogs can level six piqued gymnasts! Amazingly few discotheques provide jukeboxes.%d" int .
+0::printf "%-79d%d" int . .
+0::printf "%-80d%d" int . .
+0::printf "%-81d%d" int . .
diff --git a/usr/src/cmd/mdb/test/options/tst.autowrap.mdb.out b/usr/src/cmd/mdb/test/options/tst.autowrap.mdb.out
new file mode 100644
index 0000000000..81d3ef5293
--- /dev/null
+++ b/usr/src/cmd/mdb/test/options/tst.autowrap.mdb.out
@@ -0,0 +1,11 @@
+Pack my box with five dozen liquor jugs. How razorback-jumping frogs can level six piqued gymnasts! Amazingly few discotheques provide jukeboxes.0
+0 0
+0 0
+0 0
+Pack my box with five dozen liquor jugs. How razorback-jumping frogs can level s
+ix piqued gymnasts! Amazingly few discotheques provide jukeboxes.0
+0 0
+0
+0
+0
+0
diff --git a/usr/src/cmd/ndmpadm/ndmpadm_main.c b/usr/src/cmd/ndmpadm/ndmpadm_main.c
index 6cc7cbb7bc..8f6da4b052 100644
--- a/usr/src/cmd/ndmpadm/ndmpadm_main.c
+++ b/usr/src/cmd/ndmpadm/ndmpadm_main.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -333,7 +334,7 @@ ndmp_set_config_process(char *propname)
if ((propvalue = strchr(propname, '=')) == NULL) {
(void) fprintf(stderr, gettext("Missing value in "
"property=value argument for %s\n"), propname);
- return;
+ return;
}
*propvalue = '\0';
propvalue++;
@@ -341,7 +342,7 @@ ndmp_set_config_process(char *propname)
if (*propname == '\0') {
(void) fprintf(stderr, gettext("Missing property in "
"property=value argument for %s\n"), propname);
- return;
+ return;
}
for (j = 0; j < NDMPADM_NPROP; j++) {
if (strcmp(propname, prop_table[j]) == 0)
@@ -513,7 +514,7 @@ ndmp_kill_sessions(int argc, char **argv, ndmp_command_t *cur_cmd)
} else {
(void) fprintf(stderr,
gettext("Invalid argument %s\n"), argv[i]);
- continue;
+ continue;
}
if (ret == -1)
(void) fprintf(stdout,
diff --git a/usr/src/cmd/pathchk/pathchk.c b/usr/src/cmd/pathchk/pathchk.c
index 23c9ed91e8..b3ed05a4c5 100644
--- a/usr/src/cmd/pathchk/pathchk.c
+++ b/usr/src/cmd/pathchk/pathchk.c
@@ -20,8 +20,8 @@
* CDDL HEADER END
*/
/*
- *
- * Copyright (c) 1994 by Sun Microsystems, Inc.
+ * Copyright (c) 1994 by Sun Microsystems, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -31,7 +31,6 @@
* P1003.2/D11.2
*
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Original ident string for reference
* ident "$Id: pathchk.c,v 1.29 1994/05/24 15:51:19 mark Exp $"
@@ -247,7 +246,7 @@ checkpathname(char *path, int pflag)
* Find the end of the current component
* and check for valid characters in the component
*/
- while (*p != '\0' && !M_FSDELIM(*p)) {
+ while (*p != '\0' && !M_FSDELIM(*p)) {
/*
* for pflag: check for PFCS characters
* otherwise assume all characters are valid
@@ -280,13 +279,13 @@ checkpathname(char *path, int pflag)
* are required when not just
* checking for portability.
*/
- struct stat sb;
- char fsdelim;
+ struct stat sb;
+ char fsdelim;
- fsdelim = *ecomp;
- *ecomp = '\0';
+ fsdelim = *ecomp;
+ *ecomp = '\0';
- if (stat(path, &sb) == -1) {
+ if (stat(path, &sb) == -1) {
/*
* We error out if an
* intermediate component
@@ -303,7 +302,7 @@ checkpathname(char *path, int pflag)
} else if (errno == ENOENT) {
checkStat = 0;
}
- } else if (S_ISDIR(sb.st_mode)) {
+ } else if (S_ISDIR(sb.st_mode)) {
/*
* If the current prefix is a
* directory, then we need to
diff --git a/usr/src/cmd/pcitool/pcitool_ui.c b/usr/src/cmd/pcitool/pcitool_ui.c
index ddeccea4bf..20e3956222 100644
--- a/usr/src/cmd/pcitool/pcitool_ui.c
+++ b/usr/src/cmd/pcitool/pcitool_ui.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -1424,7 +1425,7 @@ parse_intr_set_opts(char *input, uint64_t *flags_arg, uint32_t *cpu_arg)
} else {
(void) fprintf(stderr,
"Unrecognized option for -i -m -w\n");
- rval = FAILURE;
+ rval = FAILURE;
}
return (rval);
diff --git a/usr/src/cmd/pg/pg.c b/usr/src/cmd/pg/pg.c
index 2218c9abf3..f4ce5ddeff 100644
--- a/usr/src/cmd/pg/pg.c
+++ b/usr/src/cmd/pg/pg.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -226,7 +227,7 @@ main(int argc, char **argv)
/* check for non-standard + option */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--") == 0)
- break;
+ break;
if (argv[i][0] == '+') {
if (argv[i][1] == '/') {
diff --git a/usr/src/cmd/savecore/savecore.c b/usr/src/cmd/savecore/savecore.c
index e1d3589acc..9b8e43e488 100644
--- a/usr/src/cmd/savecore/savecore.c
+++ b/usr/src/cmd/savecore/savecore.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
@@ -92,6 +92,7 @@ static dumpdatahdr_t datahdr; /* compression info */
static long coreblksize; /* preferred write size (st_blksize) */
static int cflag; /* run as savecore -c */
static int mflag; /* run as savecore -m */
+static int rflag; /* run as savecore -r */
/*
* Payload information for the events we raise. These are used
@@ -164,7 +165,7 @@ static void
usage(void)
{
(void) fprintf(stderr,
- "usage: %s [-Lvd] [-f dumpfile] [dirname]\n", progname);
+ "usage: %s [-L | -r] [-vd] [-f dumpfile] [dirname]\n", progname);
exit(1);
}
@@ -229,7 +230,7 @@ logprint(uint32_t flags, char *message, ...)
* raise if run as savecore -m. If something in the
* raise_event codepath calls logprint avoid recursion.
*/
- if (!mflag && logprint_raised++ == 0)
+ if (!mflag && !rflag && logprint_raised++ == 0)
raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
code = 2;
break;
@@ -240,7 +241,7 @@ logprint(uint32_t flags, char *message, ...)
case SC_EXIT_ERR:
default:
- if (!mflag && logprint_raised++ == 0 && have_dumpfile)
+ if (!mflag && !rflag && logprint_raised++ == 0 && have_dumpfile)
raise_event(SC_EVENT_SAVECORE_FAILURE, buf);
code = 1;
break;
@@ -355,7 +356,7 @@ read_number_from_file(const char *filename, long default_value)
static void
read_dumphdr(void)
{
- if (filemode)
+ if (filemode || rflag)
dumpfd = Open(dumpfile, O_RDONLY, 0644);
else
dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
@@ -408,7 +409,7 @@ read_dumphdr(void)
/*
* Clear valid bit so we don't complain on every invocation.
*/
- if (!filemode)
+ if (!filemode && !rflag)
Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
logprint(SC_SL_ERR | SC_EXIT_ERR,
"initial dump header corrupt");
@@ -660,7 +661,7 @@ copy_crashfile(const char *corefile)
* Write out the modified dump header to the dump device.
* The dump device has been processed, so DF_VALID is clear.
*/
- if (!filemode)
+ if (!filemode && !rflag)
Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
(void) close(corefd);
@@ -1422,7 +1423,7 @@ build_corefile(const char *namelist, const char *corefile)
* Write out the modified dump headers.
*/
Pwrite(corefd, &corehdr, sizeof (corehdr), 0);
- if (!filemode)
+ if (!filemode && !rflag)
Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
(void) close(corefd);
@@ -1531,7 +1532,10 @@ stack_retrieve(char *stack)
DUMP_ERPTSIZE);
dumpoff -= DUMP_SUMMARYSIZE;
- dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
+ if (rflag)
+ dumpfd = Open(dumpfile, O_RDONLY, 0644);
+ else
+ dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
dumpoff = llseek(dumpfd, dumpoff, SEEK_END) & -DUMP_OFFSET;
Pread(dumpfd, &sd, sizeof (summary_dump_t), dumpoff);
@@ -1668,7 +1672,7 @@ main(int argc, char *argv[])
if (savedir != NULL)
savedir = strdup(savedir);
- while ((c = getopt(argc, argv, "Lvcdmf:")) != EOF) {
+ while ((c = getopt(argc, argv, "Lvcdmf:r")) != EOF) {
switch (c) {
case 'L':
livedump++;
@@ -1685,6 +1689,9 @@ main(int argc, char *argv[])
case 'm':
mflag++;
break;
+ case 'r':
+ rflag++;
+ break;
case 'f':
dumpfile = optarg;
filebounds = getbounds(dumpfile);
@@ -1709,6 +1716,9 @@ main(int argc, char *argv[])
if (cflag && livedump)
usage();
+ if (rflag && (cflag || mflag || livedump))
+ usage();
+
if (dumpfile == NULL || livedump)
dumpfd = Open("/dev/dump", O_RDONLY, 0444);
@@ -1752,7 +1762,7 @@ main(int argc, char *argv[])
* We could extend it to handle this, but there doesn't seem to be
* a general need for it, so we isolate the complexity here instead.
*/
- if (dumphdr.dump_panicstring[0] != '\0') {
+ if (dumphdr.dump_panicstring[0] != '\0' && !rflag) {
int logfd = Open("/dev/conslog", O_WRONLY, 0644);
log_ctl_t lc;
struct strbuf ctl, dat;
@@ -1801,7 +1811,7 @@ main(int argc, char *argv[])
* for the same event. Also avoid raising an event for a
* livedump, or when we inflating a compressed dump.
*/
- if (!fm_panic && !livedump && !filemode)
+ if (!fm_panic && !livedump && !filemode && !rflag)
raise_event(SC_EVENT_DUMP_PENDING, NULL);
logprint(SC_SL_WARN, "System dump time: %s",
@@ -1857,7 +1867,7 @@ main(int argc, char *argv[])
* has panicked. We know a reasonable amount about the
* condition at this time, but the dump is still compressed.
*/
- if (!livedump && !fm_panic)
+ if (!livedump && !fm_panic && !rflag)
raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
if (metrics_size > 0) {
@@ -1926,7 +1936,7 @@ main(int argc, char *argv[])
build_corefile(namelist, corefile);
- if (!livedump && !filemode && !fm_panic)
+ if (!livedump && !filemode && !fm_panic && !rflag)
raise_event(SC_EVENT_DUMP_AVAILABLE, NULL);
if (access(METRICSFILE, F_OK) == 0) {
diff --git a/usr/src/cmd/sbdadm/sbdadm.c b/usr/src/cmd/sbdadm/sbdadm.c
index c2323e11b1..dfabdd7a3a 100644
--- a/usr/src/cmd/sbdadm/sbdadm.c
+++ b/usr/src/cmd/sbdadm/sbdadm.c
@@ -22,6 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
@@ -316,7 +317,7 @@ delete_lu(int operandLen, char *operands[], cmdOptions_t *options,
notValidHexNumber = B_TRUE;
break;
}
- sGuid[j] = tolower(operands[i][j]);
+ sGuid[j] = tolower(operands[i][j]);
}
if ((notValidHexNumber == B_TRUE) ||
(strlen(operands[i]) != GUID_INPUT)) {
diff --git a/usr/src/cmd/sgs/ar/common/main.c b/usr/src/cmd/sgs/ar/common/main.c
index a452d403ff..e5667aa196 100644
--- a/usr/src/cmd/sgs/ar/common/main.c
+++ b/usr/src/cmd/sgs/ar/common/main.c
@@ -25,6 +25,10 @@
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include "inc.h"
#include "conv.h"
@@ -277,7 +281,7 @@ setup(int argc, char *argv[], Cmd_info *cmd_info)
MSG_ORIG(MSG_FMT_VERSION),
(const char *)SGU_PKG,
(const char *)SGU_REL);
- Vflag++;
+ Vflag++;
}
break;
case 'C':
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.msg b/usr/src/cmd/sgs/elfdump/common/elfdump.msg
index 253ea4a788..5876b59f1f 100644
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg
@@ -37,7 +37,7 @@
[-N name] [-O osabi] [-T type] [-p | -w outfile] \
file...\n"
@ MSG_USAGE_DETAIL1 "\t[-c]\t\tdump section header information\n"
-@ MSG_USAGE_DETAIL2 "\t[-C]\t\tdemangle C++ symbol names\n"
+@ MSG_USAGE_DETAIL2 "\t[-C]\t\tdemangle symbol names\n"
@ MSG_USAGE_DETAIL3 "\t[-d]\t\tdump the contents of the .dynamic section\n"
@ MSG_USAGE_DETAIL4 "\t[-e]\t\tdump the elf header\n"
@ MSG_USAGE_DETAIL5 "\t[-g]\t\tdump the contents of the .group sections\n"
diff --git a/usr/src/cmd/sgs/libld/common/machrel.amd.c b/usr/src/cmd/sgs/libld/common/machrel.amd.c
index 694a9ad8be..ebf7cc5a8f 100644
--- a/usr/src/cmd/sgs/libld/common/machrel.amd.c
+++ b/usr/src/cmd/sgs/libld/common/machrel.amd.c
@@ -740,7 +740,6 @@ tls_fixups(Ofl_desc *ofl, Rel_desc *arsp)
DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH,
R_AMD64_TPOFF32, arsp, ld_reloc_sym_name));
arsp->rel_rtype = R_AMD64_TPOFF32;
- arsp->rel_raddend = 0;
return (FIX_RELOC);
}
@@ -764,7 +763,7 @@ ld_do_activerelocs(Ofl_desc *ofl)
*/
REL_CACHE_TRAVERSE(&ofl->ofl_actrels, idx, rcbp, arsp) {
uchar_t *addr;
- Xword value;
+ Xword value;
Sym_desc *sdp;
const char *ifl_name;
Xword refaddr;
diff --git a/usr/src/cmd/sgs/m4/common/m4.c b/usr/src/cmd/sgs/m4/common/m4.c
index e96fb17c26..8888f49eef 100644
--- a/usr/src/cmd/sgs/m4/common/m4.c
+++ b/usr/src/cmd/sgs/m4/common/m4.c
@@ -30,6 +30,10 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
@@ -576,7 +580,7 @@ expand(wchar_t **a1, int c)
pbstr(lquote);
if (i <= 0)
- break;
+ break;
pbstr(L",");
}
diff --git a/usr/src/cmd/sgs/nm/amd64/Makefile b/usr/src/cmd/sgs/nm/amd64/Makefile
index 0b9d1b6992..cb2d8a5fb5 100644
--- a/usr/src/cmd/sgs/nm/amd64/Makefile
+++ b/usr/src/cmd/sgs/nm/amd64/Makefile
@@ -22,7 +22,7 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright (c) 2019, Joyent, Inc.
# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
@@ -44,10 +44,6 @@ INCLIST= -I../../include -I../../include/i386 \
-I$(SRCBASE)/uts/$(ARCH)/sys
CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
-CERRWARN += -_gcc=-Wno-uninitialized
-
-SMOFF += precedence,indenting
-
LDLIBS += $(CONVLIBDIR64) $(CONV_LIB) $(ELFLIBDIR) -lelf
%.o: ../common/%.c
diff --git a/usr/src/cmd/sgs/nm/common/nm.c b/usr/src/cmd/sgs/nm/common/nm.c
index fc3ded721e..2e750a559b 100644
--- a/usr/src/cmd/sgs/nm/common/nm.c
+++ b/usr/src/cmd/sgs/nm/common/nm.c
@@ -26,6 +26,7 @@
*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2018 Jason King
+ * Copyright 2019, Joyent, Inc.
*/
#include <stdio.h>
@@ -76,7 +77,7 @@ typedef struct { /* structure to translate symbol table data */
#define REG_WEAK "R*"
#define REG_LOCL "r"
-#define OPTSTR ":APDoxhvnursplLCVefgRTt:" /* option string for getopt() */
+#define OPTSTR ":APDoxhvniursplLCVefgRTt:" /* option string for getopt() */
#define DATESIZE 60
@@ -116,6 +117,7 @@ static int /* flags: ?_flag corresponds to ? option */
h_flag = 0, /* suppress printing of headings */
v_flag = 0, /* sort external symbols by value */
n_flag = 0, /* sort external symbols by name */
+ i_flag = 0, /* don't sort symbols */
u_flag = 0, /* print only undefined symbols */
r_flag = 0, /* prepend object file or archive name */
/* to each symbol name */
@@ -210,141 +212,185 @@ main(int argc, char *argv[], char *envp[])
while ((optchar = getopt(argc, argv, optstr)) != -1) {
switch (optchar) {
- case 'o': if (COMPAT_FMT_FLAG(FMT_T_OCT))
- fmt_flag = FMT_T_OCT;
- else
- (void) fprintf(stderr, gettext(
- "%s: -x or -t set, -o ignored\n"),
- prog_name);
- break;
- case 'x': if (COMPAT_FMT_FLAG(FMT_T_HEX))
- fmt_flag = FMT_T_HEX;
- else
- (void) fprintf(stderr, gettext(
- "%s: -o or -t set, -x ignored\n"),
- prog_name);
- break;
- case 'h': h_flag = 1;
- break;
- case 'v': if (!n_flag)
- v_flag = 1;
- else
- (void) fprintf(stderr, gettext(
- "%s: -n set, -v ignored\n"),
- prog_name);
- break;
- case 'n': if (!v_flag)
- n_flag = 1;
- else
- (void) fprintf(stderr, gettext(
- "%s: -v set, -n ignored\n"),
- prog_name);
- break;
- case 'u': if (!e_flag && !g_flag)
- u_flag = 1;
- else
- (void) fprintf(stderr, gettext(
- "%s: -e or -g set, -u ignored\n"),
- prog_name);
- break;
- case 'e': if (!u_flag && !g_flag)
- e_flag = 1;
- else
- (void) fprintf(stderr, gettext(
- "%s: -u or -g set, -e ignored\n"),
- prog_name);
- break;
- case 'g': if (!u_flag && !e_flag)
- g_flag = 1;
- else
- (void) fprintf(stderr, gettext(
- "%s: -u or -e set, -g ignored\n"),
- prog_name);
- break;
- case 'r': if (R_flag) {
- R_flag = 0;
- (void) fprintf(stderr, gettext(
- "%s: -r set, -R ignored\n"),
- prog_name);
- }
- r_flag = 1;
- break;
- case 's': s_flag = 1;
- break;
- case 'p': if (P_flag == 1) {
- (void) fprintf(stderr, gettext(
- "nm: -P set. -p ignored\n"));
- } else
- p_flag = 1;
- break;
- case 'P': if (p_flag == 1) {
- (void) fprintf(stderr, gettext(
- "nm: -p set. -P ignored\n"));
- } else
- P_flag = 1;
- break;
- case 'l': l_flag = 1;
- break;
- case 'L': if (D_flag == 1) {
- (void) fprintf(stderr, gettext(
- "nm: -D set. -L ignored\n"));
- } else
- L_flag = 1;
- break;
- case 'D': if (L_flag == 1) {
- (void) fprintf(stderr, gettext(
- "nm: -L set. -D ignored\n"));
- } else
- D_flag = 1;
- break;
+ case 'o':
+ if (COMPAT_FMT_FLAG(FMT_T_OCT)) {
+ fmt_flag = FMT_T_OCT;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -x or -t set, -o ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'x':
+ if (COMPAT_FMT_FLAG(FMT_T_HEX)) {
+ fmt_flag = FMT_T_HEX;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -o or -t set, -x ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'h':
+ h_flag = 1;
+ break;
+ case 'v':
+ if (!n_flag && !i_flag) {
+ v_flag = 1;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -n or -i set, -v ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'n':
+ if (!v_flag && !i_flag) {
+ n_flag = 1;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -v or -i set, -n ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'i':
+ if (!n_flag && !v_flag) {
+ i_flag = 1;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -n or -v set, -i ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'u':
+ if (!e_flag && !g_flag) {
+ u_flag = 1;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -e or -g set, -u ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'e':
+ if (!u_flag && !g_flag) {
+ e_flag = 1;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -u or -g set, -e ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'g':
+ if (!u_flag && !e_flag) {
+ g_flag = 1;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -u or -e set, -g ignored\n"),
+ prog_name);
+ }
+ break;
+ case 'r':
+ if (R_flag) {
+ R_flag = 0;
+ (void) fprintf(stderr, gettext(
+ "%s: -r set, -R ignored\n"),
+ prog_name);
+ }
+ r_flag = 1;
+ break;
+ case 's':
+ s_flag = 1;
+ break;
+ case 'p':
+ if (P_flag == 1) {
+ (void) fprintf(stderr, gettext(
+ "nm: -P set. -p ignored\n"));
+ } else {
+ p_flag = 1;
+ }
+ break;
+ case 'P':
+ if (p_flag == 1) {
+ (void) fprintf(stderr, gettext(
+ "nm: -p set. -P ignored\n"));
+ } else {
+ P_flag = 1;
+ }
+ break;
+ case 'l':
+ l_flag = 1;
+ break;
+ case 'L':
+ if (D_flag == 1) {
+ (void) fprintf(stderr, gettext(
+ "nm: -D set. -L ignored\n"));
+ } else {
+ L_flag = 1;
+ }
+ break;
+ case 'D':
+ if (L_flag == 1) {
+ (void) fprintf(stderr, gettext(
+ "nm: -L set. -D ignored\n"));
+ } else {
+ D_flag = 1;
+ }
+ break;
case 'C':
- C_flag = 1;
- break;
- case 'A': A_flag = 1;
- break;
- case 'V': V_flag = 1;
- (void) fprintf(stderr, "nm: %s %s\n",
- (const char *)SGU_PKG,
- (const char *)SGU_REL);
- break;
+ C_flag = 1;
+ break;
+ case 'A':
+ A_flag = 1;
+ break;
+ case 'V':
+ V_flag = 1;
+ (void) fprintf(stderr, "nm: %s %s\n",
+ (const char *)SGU_PKG,
+ (const char *)SGU_REL);
+ break;
case 'f': /* -f is a noop, see man page */
- break;
- case 'R': if (!r_flag)
- R_flag = 1;
- else
- (void) fprintf(stderr, gettext(
- "%s: -r set, -R ignored\n"),
- prog_name);
- break;
+ break;
+ case 'R':
+ if (!r_flag) {
+ R_flag = 1;
+ } else {
+ (void) fprintf(stderr, gettext(
+ "%s: -r set, -R ignored\n"),
+ prog_name);
+ }
+ break;
case 'T':
- break;
- case 't': if (strcmp(optarg, "o") == 0) {
- new_fmt_flag = FMT_T_OCT;
- } else if (strcmp(optarg, "d") == 0) {
- new_fmt_flag = FMT_T_DEC;
- } else if (strcmp(optarg, "x") == 0) {
- new_fmt_flag = FMT_T_HEX;
- } else {
- new_fmt_flag = FMT_T_NONE;
- }
- if (new_fmt_flag == FMT_T_NONE) {
- errflag += 1;
- (void) fprintf(stderr, gettext(
-"nm: -t requires radix value (d, o, x): %s\n"), optarg);
- } else if (COMPAT_FMT_FLAG(new_fmt_flag)) {
- fmt_flag = new_fmt_flag;
- } else {
- (void) fprintf(stderr, gettext(
- "nm: -t or -o or -x set. -t ignored.\n"));
- }
- break;
- case ':': errflag += 1;
+ break;
+ case 't':
+ if (strcmp(optarg, "o") == 0) {
+ new_fmt_flag = FMT_T_OCT;
+ } else if (strcmp(optarg, "d") == 0) {
+ new_fmt_flag = FMT_T_DEC;
+ } else if (strcmp(optarg, "x") == 0) {
+ new_fmt_flag = FMT_T_HEX;
+ } else {
+ new_fmt_flag = FMT_T_NONE;
+ }
+ if (new_fmt_flag == FMT_T_NONE) {
+ errflag += 1;
+ (void) fprintf(stderr, gettext(
+ "nm: -t requires radix value (d, o, x): "
+ "%s\n"), optarg);
+ } else if (COMPAT_FMT_FLAG(new_fmt_flag)) {
+ fmt_flag = new_fmt_flag;
+ } else {
(void) fprintf(stderr, gettext(
- "nm: %c requires operand\n"), optopt);
- break;
- case '?': errflag += 1;
- break;
- default: break;
+ "nm: -t or -o or -x set. -t ignored.\n"));
+ }
+ break;
+ case ':':
+ errflag += 1;
+ (void) fprintf(stderr, gettext(
+ "nm: %c requires operand\n"), optopt);
+ break;
+ case '?':
+ errflag += 1;
+ break;
+ default:
+ break;
}
}
@@ -381,7 +427,7 @@ static void
usage()
{
(void) fprintf(stderr, gettext(
-"Usage: nm [-ACDhLlnPpRrsTVv] [-efox] [-g | -u] [-t d|o|x] file ...\n"));
+"Usage: nm [-ACDhiLlnPpRrsTVv] [-efox] [-g | -u] [-t d|o|x] file ...\n"));
}
/*
@@ -451,20 +497,20 @@ each_file(char *filename)
(void) printf(gettext(
"\n\nUndefined symbols from %s:\n\n"),
filename);
- } else if (!h_flag & !P_flag)
+ } else if ((h_flag == 0) && (P_flag == 0)) {
#else
- if (!h_flag & !P_flag)
+ if ((h_flag == 0) && (P_flag == 0)) {
#endif
- {
- if (p_flag)
+ if (p_flag) {
(void) printf("\n\n%s:\n", filename);
- else {
- if (A_flag != 0)
+ } else {
+ if (A_flag != 0) {
(void) printf("\n\n%s%s:\n",
A_header, filename);
- else
+ } else {
(void) printf("\n\n%s:\n",
filename);
+ }
}
}
archive_name = (char *)0;
@@ -616,11 +662,11 @@ print_ar_files(int fd, Elf * elf_file, char *filename)
continue;
}
- if (!h_flag & !P_flag) {
- if (p_flag)
+ if ((h_flag == 0) && (P_flag == 0)) {
+ if (p_flag) {
(void) printf("\n\n%s[%s]:\n",
filename, p_ar->ar_name);
- else {
+ } else {
if (A_flag != 0)
(void) printf("\n\n%s%s[%s]:\n",
A_header, filename, p_ar->ar_name);
@@ -715,8 +761,10 @@ print_symtab(Elf *elf_file, unsigned int shstrndx,
prog_name, filename);
return;
}
- qsort((char *)sym_data, count-1, sizeof (SYM),
- (int (*)(const void *, const void *))compare);
+ if (i_flag == 0) {
+ qsort((char *)sym_data, count-1, sizeof (SYM),
+ (int (*)(const void *, const void *))compare);
+ }
s = sym_data;
while (count > 1) {
#ifndef XPG4
@@ -725,18 +773,19 @@ print_symtab(Elf *elf_file, unsigned int shstrndx,
* U_flag specified
*/
print_with_uflag(sym_data, filename);
- } else if (p_flag)
+ } else if (p_flag) {
#else
- if (p_flag)
+ if (p_flag) {
#endif
print_with_pflag(ndigits, elf_file, shstrndx,
sym_data, filename);
- else if (P_flag)
+ } else if (P_flag) {
print_with_Pflag(ndigits, elf_file, shstrndx,
sym_data);
- else
+ } else {
print_with_otherflags(ndigits, elf_file,
shstrndx, sym_data, filename);
+ }
sym_data++;
count--;
}
@@ -803,9 +852,9 @@ readsyms(Elf_Data * data, GElf_Sxword num, Elf *elf,
buf->indx = i;
/* allow to work on machines where NULL-derefs dump core */
- if (sym.st_name == 0)
+ if (sym.st_name == 0) {
buf->name = "";
- else if (C_flag) {
+ } else if (C_flag) {
const char *dn = NULL;
char *name = (char *)elf_strptr(elf, link, sym.st_name);
@@ -817,9 +866,9 @@ readsyms(Elf_Data * data, GElf_Sxword num, Elf *elf,
name = FormatName(name, d_buf);
}
buf->name = name;
- }
- else
+ } else {
buf->name = (char *)elf_strptr(elf, link, sym.st_name);
+ }
buf->value = sym.st_value;
buf->size = sym.st_size;
@@ -1456,29 +1505,34 @@ parsename(char *s)
void
parse_fn_and_print(const char *str, char *s)
{
- char c, *p1, *p2;
+ char c = '\0', *p1, *p2;
int yes = 1;
- if ((p1 = p2 = strstr(s, "_c_")) == NULL)
- if ((p1 = p2 = strstr(s, "_C_")) == NULL)
- if ((p1 = p2 = strstr(s, "_cc_")) == NULL)
- if ((p1 = p2 = strstr(s, "_cxx_")) == NULL)
+ if ((p1 = p2 = strstr(s, "_c_")) == NULL) {
+ if ((p1 = p2 = strstr(s, "_C_")) == NULL) {
+ if ((p1 = p2 = strstr(s, "_cc_")) == NULL) {
+ if ((p1 = p2 = strstr(s, "_cxx_")) == NULL) {
if ((p1 = p2 = strstr(s, "_h_")) ==
- NULL)
- yes = 0;
- else
+ NULL) {
+ yes = 0;
+ } else {
p2 += 2;
- else
+ }
+ } else {
p2 += 4;
- else
+ }
+ } else {
p2 += 3;
- else
+ }
+ } else {
p2 += 2;
- else
+ }
+ } else {
p2 += 2;
+ }
if (yes) {
- *p1 = '.';
+ *p1 = '.';
c = *p2;
*p2 = '\0';
}
diff --git a/usr/src/cmd/sgs/nm/i386/Makefile b/usr/src/cmd/sgs/nm/i386/Makefile
index c7d5bf8b0b..a6f7735af2 100644
--- a/usr/src/cmd/sgs/nm/i386/Makefile
+++ b/usr/src/cmd/sgs/nm/i386/Makefile
@@ -21,7 +21,7 @@
#
# Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright (c) 2019, Joyent, Inc.
# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
@@ -46,10 +46,6 @@ INCLIST= -I../../include -I../../include/i386 \
DEFLIST= -DTARGET=I386 -DI386=1 -D$(ARFORMAT) -DELF
CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
-CERRWARN += -_gcc=-Wno-uninitialized
-
-SMOFF += precedence,indenting
-
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
objs.xpg4/%.o := CPPFLAGS += -DXPG4
diff --git a/usr/src/cmd/sgs/nm/sparc/Makefile b/usr/src/cmd/sgs/nm/sparc/Makefile
index 0fa774a310..a76d967545 100644
--- a/usr/src/cmd/sgs/nm/sparc/Makefile
+++ b/usr/src/cmd/sgs/nm/sparc/Makefile
@@ -45,7 +45,6 @@ INCLIST= -I../../include -I../../include/sparc \
-I$(SRCBASE)/uts/$(ARCH)/sys
DEFLIST= -DTARGET=SPARC -DSPARC=1 -D$(ARFORMAT) -DELF
CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
-CERRWARN += -_gcc=-Wno-uninitialized
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
objs.xpg4/%.o := CPPFLAGS += -DXPG4
diff --git a/usr/src/cmd/sgs/nm/sparcv9/Makefile b/usr/src/cmd/sgs/nm/sparcv9/Makefile
index 58bc8a5aff..75772f807c 100644
--- a/usr/src/cmd/sgs/nm/sparcv9/Makefile
+++ b/usr/src/cmd/sgs/nm/sparcv9/Makefile
@@ -43,7 +43,6 @@ INCLIST= -I../../include -I../../include/sparc \
-I$(SRCBASE)/uts/$(ARCH)/sys
DEFLIST= -DTARGET=SPARC -DSPARC=1 -D$(ARFORMAT) -DELF
CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
-CERRWARN += -_gcc=-Wno-uninitialized
LDLIBS += $(CONVLIBDIR64) $(CONV_LIB) $(ELFLIBDIR) -lelf
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index 44cf7146e8..7e549775e0 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1662,3 +1662,4 @@ Bugid Risk Synopsis
7594 ld -zaslr should accept Solaris-compatible values
8616 ld has trouble parsing -z options specified with -Wl
10267 ld and GCC disagree about i386 local dynamic TLS
+10471 ld(1) amd64 LD->LE TLS transition causes memory corruption
diff --git a/usr/src/cmd/sgs/pvs/common/pvs.c b/usr/src/cmd/sgs/pvs/common/pvs.c
index 4d51ce300d..4c353b887c 100644
--- a/usr/src/cmd/sgs/pvs/common/pvs.c
+++ b/usr/src/cmd/sgs/pvs/common/pvs.c
@@ -27,7 +27,7 @@
/*
* Analyze the versioning information within a file.
*
- * -C demangle C++ symbol names.
+ * -C demangle symbol names.
*
* -d dump version definitions.
*
diff --git a/usr/src/cmd/sgs/pvs/common/pvs.msg b/usr/src/cmd/sgs/pvs/common/pvs.msg
index 82a61385cd..eb888a753a 100644
--- a/usr/src/cmd/sgs/pvs/common/pvs.msg
+++ b/usr/src/cmd/sgs/pvs/common/pvs.msg
@@ -22,6 +22,7 @@
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2018, Joyent, Inc.
#
@ _START_
@@ -34,7 +35,7 @@
# Argument usage messages.
@ MSG_USAGE_BRIEF "usage: %s [-Cdlnorsv] [-I index] [-N Name] file(s)\n"
-@ MSG_USAGE_DETAIL "\t[-C]\t\tdemangle C++ symbol names\n\
+@ MSG_USAGE_DETAIL "\t[-C]\t\tdemangle symbol names\n\
\t[-d]\t\tprint version definition information\n\
\t[-I index]\tqualify version with an index\n\
\t[-l]\t\tprint reduced symbols\n\
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/README b/usr/src/cmd/sgs/test/ld/x64/tls/ie/README
deleted file mode 100644
index 835b3a80ea..0000000000
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/README
+++ /dev/null
@@ -1,9 +0,0 @@
-This tests the x64 link-editor's handling of Initial Executable TLS sequences.
-
-The original C source files are in orig/ but unused, since we need to avoid
-any changes to the compiler influencing our tests.
-
- % ksh x64-ie-test.sh /path/to/proto/root
- pass: addq-->leaq 1
- ...
- pass: bad insn sequence
diff --git a/usr/src/cmd/svc/common/notify_params.c b/usr/src/cmd/svc/common/notify_params.c
index e947b0fa76..16104d899e 100644
--- a/usr/src/cmd/svc/common/notify_params.c
+++ b/usr/src/cmd/svc/common/notify_params.c
@@ -87,7 +87,7 @@ static char *fma_classes[] = {
const char *
get_fma_tag(uint32_t index)
{
- if (index > (sizeof (fma_tags) / sizeof (struct fma_tags)))
+ if (index >= (sizeof (fma_tags) / sizeof (struct fma_tags)))
return (NULL);
return (fma_tags[index].t);
@@ -101,7 +101,7 @@ get_fma_tag(uint32_t index)
const char *
get_fma_class(uint32_t index)
{
- if (index > (sizeof (fma_tags) / sizeof (struct fma_tags)))
+ if (index >= (sizeof (fma_tags) / sizeof (struct fma_tags)))
return (NULL);
return (fma_tags[index].s);
diff --git a/usr/src/cmd/syseventd/daemons/syseventd/sysevent_client.c b/usr/src/cmd/syseventd/daemons/syseventd/sysevent_client.c
index 04a410991b..155b59eab1 100644
--- a/usr/src/cmd/syseventd/daemons/syseventd/sysevent_client.c
+++ b/usr/src/cmd/syseventd/daemons/syseventd/sysevent_client.c
@@ -24,7 +24,9 @@
* All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
/*
* syseventd client interfaces
@@ -121,7 +123,7 @@ insert_client(void *client_data, int client_type, int retry_limit)
NULL);
(void) mutex_unlock(&scp->client_lock);
(void) mutex_unlock(&client_tbl_lock);
- return (i);
+ return (i);
}
}
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index 1e384f2f10..ff2389ea55 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -23,7 +23,7 @@
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2019, Joyent, Inc.
* Copyright (c) 2014, OmniTI Computer Consulting, Inc. All rights reserved.
*/
@@ -1290,6 +1290,8 @@ const struct ioc {
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_POOL_INITIALIZE, "ZFS_IOC_POOL_INITIALIZE",
"zfs_cmd_t" },
+ { (uint_t)ZFS_IOC_POOL_SYNC, "ZFS_IOC_POOL_SYNC",
+ "zfs_cmd_t" },
/* kssl ioctls */
{ (uint_t)KSSL_ADD_ENTRY, "KSSL_ADD_ENTRY",
diff --git a/usr/src/cmd/ucodeadm/ucodeadm.c b/usr/src/cmd/ucodeadm/ucodeadm.c
index 1ff85bcf0d..67a7bae882 100644
--- a/usr/src/cmd/ucodeadm/ucodeadm.c
+++ b/usr/src/cmd/ucodeadm/ucodeadm.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <sys/types.h>
#include <sys/processor.h>
#include <sys/ucode.h>
@@ -668,9 +672,9 @@ main(int argc, char *argv[])
uint32_t *revp = NULL;
int i;
#if defined(_SYSCALL32_IMPL)
- struct ucode_get_rev_struct32 inf32;
+ struct ucode_get_rev_struct32 inf32;
#else
- struct ucode_get_rev_struct info;
+ struct ucode_get_rev_struct info;
#endif
cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX);
@@ -721,9 +725,9 @@ main(int argc, char *argv[])
if (action & UCODE_OPT_UPDATE) {
int tmprc;
#if defined(_SYSCALL32_IMPL)
- struct ucode_write_struct32 uw_struct32;
+ struct ucode_write_struct32 uw_struct32;
#else
- struct ucode_write_struct uw_struct;
+ struct ucode_write_struct uw_struct;
#endif
#if defined(_SYSCALL32_IMPL)
diff --git a/usr/src/cmd/ul/ul.c b/usr/src/cmd/ul/ul.c
index d4cfa6ea5f..272df43eb7 100644
--- a/usr/src/cmd/ul/ul.c
+++ b/usr/src/cmd/ul/ul.c
@@ -12,7 +12,9 @@
* specifies the terms and conditions for redistribution.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
#include <stdio.h>
#include <locale.h>
@@ -460,7 +462,7 @@ iattr(void)
tszbf += n * MEMFCT;
}
tszbf -= n;
- *cp++ = cx;
+ *cp++ = cx;
while (--n > 0) {
*cp++ = cx;
i++;
diff --git a/usr/src/cmd/valtools/ckitem.c b/usr/src/cmd/valtools/ckitem.c
index c56794f50d..61f9f85655 100644
--- a/usr/src/cmd/valtools/ckitem.c
+++ b/usr/src/cmd/valtools/ckitem.c
@@ -28,7 +28,9 @@
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
#include <stdio.h>
#include <ctype.h>
@@ -146,7 +148,7 @@ main(int argc, char **argv)
if (!invis) {
(void) fprintf(stderr,
gettext("Not enough memory\n"));
- exit(1);
+ exit(1);
}
while ((c = getopt(argc, argv, "m:oni:l:f:ud:p:e:h:k:s:QW:?")) != EOF) {
/* check for invalid option */
@@ -197,7 +199,7 @@ main(int argc, char **argv)
if (!invis) {
(void) fprintf(stderr,
gettext("Not enough memory\n"));
- exit(1);
+ exit(1);
}
(void) memset(invis + ninvis, 0,
(invismaxsize - ninvis) *
diff --git a/usr/src/cmd/write/write.c b/usr/src/cmd/write/write.c
index 7518cf85ab..6683af7f85 100644
--- a/usr/src/cmd/write/write.c
+++ b/usr/src/cmd/write/write.c
@@ -27,6 +27,7 @@
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -274,9 +275,9 @@ main(int argc, char **argv)
(void) fprintf(stderr,
gettext("Cannot determine who you are.\n"));
exit(1);
- }
- (void) strlcpy(&ownname[0], &passptr->pw_name[0],
- sizeof (ownname));
+ }
+ (void) strlcpy(&ownname[0], &passptr->pw_name[0],
+ sizeof (ownname));
} else {
(void) strlcpy(&ownname[0], self.ut_user,
sizeof (self.ut_user));
diff --git a/usr/src/cmd/zdump/zdump.c b/usr/src/cmd/zdump/zdump.c
index eae12f775f..8c3a32bc8f 100644
--- a/usr/src/cmd/zdump/zdump.c
+++ b/usr/src/cmd/zdump/zdump.c
@@ -4,6 +4,10 @@
*/
/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
+/*
* zdump 7.24
* Taken from elsie.nci.nih.gov to replace the existing Solaris zdump,
* which was based on an earlier version of the elsie code.
@@ -231,8 +235,9 @@ char *argv[];
cutloyear = lo;
cuthiyear = hi;
} else {
-(void) fprintf(stderr, gettext("%s: wild -c argument %s\n"),
- progname, cutarg);
+ (void) fprintf(stderr,
+ gettext("%s: wild -c argument %s\n"),
+ progname, cutarg);
exit(EXIT_FAILURE);
}
}
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
index e82d8a089e..d83d3854d0 100644
--- a/usr/src/cmd/zpool/zpool_main.c
+++ b/usr/src/cmd/zpool/zpool_main.c
@@ -98,6 +98,8 @@ static int zpool_do_history(int, char **);
static int zpool_do_get(int, char **);
static int zpool_do_set(int, char **);
+static int zpool_do_sync(int, char **);
+
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
@@ -142,6 +144,7 @@ typedef enum {
HELP_GET,
HELP_SET,
HELP_SPLIT,
+ HELP_SYNC,
HELP_REGUID,
HELP_REOPEN
} zpool_help_t;
@@ -198,6 +201,7 @@ static zpool_command_t command_table[] = {
{ "history", zpool_do_history, HELP_HISTORY },
{ "get", zpool_do_get, HELP_GET },
{ "set", zpool_do_set, HELP_SET },
+ { "sync", zpool_do_sync, HELP_SYNC },
};
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -284,6 +288,8 @@ get_usage(zpool_help_t idx)
"[<device> ...]\n"));
case HELP_REGUID:
return (gettext("\treguid <pool>\n"));
+ case HELP_SYNC:
+ return (gettext("\tsync [pool] ...\n"));
}
abort();
@@ -2619,6 +2625,45 @@ error:
return (err ? 1 : 0);
}
+/*
+ * zpool sync [-f] [pool] ...
+ *
+ * -f (undocumented) force uberblock (and config including zpool cache file)
+ * update.
+ *
+ * Sync the specified pool(s).
+ * Without arguments "zpool sync" will sync all pools.
+ * This command initiates TXG sync(s) and will return after the TXG(s) commit.
+ *
+ */
+static int
+zpool_do_sync(int argc, char **argv)
+{
+ int ret;
+ boolean_t force = B_FALSE;
+
+ /* check options */
+ while ((ret = getopt(argc, argv, "f")) != -1) {
+ switch (ret) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* if argc == 0 we will execute zpool_sync_one on all pools */
+ ret = for_each_pool(argc, argv, B_FALSE, NULL, zpool_sync_one, &force);
+
+ return (ret);
+}
+
typedef struct iostat_cbdata {
boolean_t cb_verbose;
int cb_namewidth;
diff --git a/usr/src/common/ctf/ctf_create.c b/usr/src/common/ctf/ctf_create.c
index 355165eb12..d88283e8f5 100644
--- a/usr/src/common/ctf/ctf_create.c
+++ b/usr/src/common/ctf/ctf_create.c
@@ -25,7 +25,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <sys/sysmacros.h>
@@ -2126,6 +2126,7 @@ ctf_add_label(ctf_file_t *fp, const char *name, ctf_id_t type, uint_t position)
return (ctf_set_errno(fp, EAGAIN));
}
+ ctf_dprintf("adding label %s, %ld\n", name, type);
dld->dld_type = type;
fp->ctf_dtstrlen += strlen(name) + 1;
ctf_dld_insert(fp, dld, position);
diff --git a/usr/src/common/pnglite/pnglite.c b/usr/src/common/pnglite/pnglite.c
index 7ea32c002d..5d8b41f9e9 100644
--- a/usr/src/common/pnglite/pnglite.c
+++ b/usr/src/common/pnglite/pnglite.c
@@ -100,12 +100,13 @@ png_get_bpp(png_t *png)
static int
png_read_ihdr(png_t *png)
{
- unsigned length;
+ unsigned length = 0;
unsigned orig_crc;
unsigned calc_crc;
uint8_t ihdr[13+4]; /* length should be 13, make room for type (IHDR) */
- file_read_ul(png, &length);
+ if (file_read_ul(png, &length) != PNG_NO_ERROR)
+ return (PNG_FILE_ERROR);
if (length != 13)
return (PNG_CRC_ERROR);
@@ -113,7 +114,8 @@ png_read_ihdr(png_t *png)
if (file_read(png, ihdr, 1, 13+4) != 13+4)
return (PNG_EOF_ERROR);
- file_read_ul(png, &orig_crc);
+ if (file_read_ul(png, &orig_crc) != PNG_NO_ERROR)
+ return (PNG_FILE_ERROR);
calc_crc = crc32(0L, Z_NULL, 0);
calc_crc = crc32(calc_crc, ihdr, 13+4);
@@ -220,7 +222,7 @@ done:
if (result != PNG_NO_ERROR) {
free(png->image);
- close(png->fd);
+ (void) close(png->fd);
png->fd = -1;
return (result);
}
@@ -231,7 +233,7 @@ done:
int
png_close(png_t *png)
{
- close(png->fd);
+ (void) close(png->fd);
png->fd = -1;
free(png->image);
png->image = NULL;
@@ -329,7 +331,8 @@ png_read_idat(png_t *png, unsigned length)
calc_crc = crc32(calc_crc, (uint8_t *)"IDAT", 4);
calc_crc = crc32(calc_crc, (uint8_t *)png->readbuf, length);
- file_read_ul(png, &orig_crc);
+ if (file_read_ul(png, &orig_crc) != PNG_NO_ERROR)
+ return (PNG_FILE_ERROR);
if (orig_crc != calc_crc)
return (PNG_CRC_ERROR);
@@ -344,9 +347,10 @@ png_process_chunk(png_t *png)
unsigned type;
unsigned length;
- file_read_ul(png, &length);
+ if (file_read_ul(png, &length) != PNG_NO_ERROR)
+ return (PNG_FILE_ERROR);
- if (file_read_ul(png, &type))
+ if (file_read_ul(png, &type) != PNG_NO_ERROR)
return (PNG_FILE_ERROR);
/*
@@ -373,7 +377,7 @@ png_process_chunk(png_t *png)
} else if (type == png_IEND)
return (PNG_DONE);
else
- file_read(png, 0, 1, length + 4); /* unknown chunk */
+ (void) file_read(png, 0, 1, length + 4); /* unknown chunk */
return (result);
}
@@ -571,7 +575,7 @@ png_get_data(png_t *png, uint8_t *data)
png->readbuflen = 0;
}
if (png->zs)
- png_end_inflate(png);
+ (void) png_end_inflate(png);
if (result != PNG_DONE) {
free(png->png_data);
diff --git a/usr/src/common/smbclnt/smbfs_ntacl.c b/usr/src/common/smbclnt/smbfs_ntacl.c
index dcc0d55e79..3ff10aba82 100644
--- a/usr/src/common/smbclnt/smbfs_ntacl.c
+++ b/usr/src/common/smbclnt/smbfs_ntacl.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -33,7 +34,7 @@
#include <sys/acl.h>
#include <sys/byteorder.h>
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/cred.h>
#include <sys/cmn_err.h>
@@ -42,16 +43,18 @@
#include <sys/vnode.h>
#include <sys/vfs.h>
-#include <sys/kidmap.h>
-
-#else /* _KERNEL */
+#else /* _KERNEL || _FAKE_KERNEL */
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
-#include <idmap.h>
+#endif /* _KERNEL || _FAKE_KERNEL */
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#else /* _KERNEL */
+#include <idmap.h>
#endif /* _KERNEL */
#include <netsmb/mchain.h>
@@ -61,7 +64,7 @@
#define NT_SD_REVISION 1
#define NT_ACL_REVISION 2
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#define MALLOC(size) kmem_alloc(size, KM_SLEEP)
#define FREESZ(p, sz) kmem_free(p, sz)
#else /* _KERNEL */
@@ -887,7 +890,7 @@ ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo2uid *mip)
int
smbfs_acl_sd2zfs(
i_ntsd_t *sd,
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
vsecattr_t *acl_info,
#else /* _KERNEL */
acl_t *acl_info,
@@ -908,12 +911,12 @@ smbfs_acl_sd2zfs(
* sanity checks
*/
if (acl_info) {
-#ifndef _KERNEL
+#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
if (acl_info->acl_type != ACE_T ||
acl_info->acl_aclp != NULL ||
acl_info->acl_entry_size != sizeof (ace_t))
return (EINVAL);
-#endif /* _KERNEL */
+#endif /* !_KERNEL */
if ((sd->sd_flags & SD_DACL_PRESENT) == 0)
return (EINVAL);
}
@@ -1117,7 +1120,7 @@ smbfs_acl_sd2zfs(
zacep->a_type = ACCESS_ALLOWED_ACE_TYPE;
}
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
acl_info->vsa_aclcnt = zacecnt;
acl_info->vsa_aclentp = zacep0;
acl_info->vsa_aclentsz = zacl_size;
@@ -1226,7 +1229,7 @@ smbfs_str2sid(const char *sid_prefix, uint32_t *ridp, i_ntsid_t **osidp)
goto out;
}
p++;
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
err = ddi_strtoul(p, &np, 10, &sa);
if (err != 0)
goto out;
@@ -1409,7 +1412,7 @@ zace2ntace(i_ntace_t **ntacep, ace_t *zacep, struct mapinfo2sid *mip)
*/
int
smbfs_acl_zfs2sd(
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
vsecattr_t *acl_info,
#else /* _KERNEL */
acl_t *acl_info,
@@ -1455,7 +1458,7 @@ smbfs_acl_zfs2sd(
return (EINVAL);
if (own_gid == (gid_t)-1)
return (EINVAL);
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
if ((acl_info->vsa_mask & VSA_ACE) == 0)
return (EINVAL);
zacecnt = acl_info->vsa_aclcnt;
diff --git a/usr/src/common/smbclnt/smbfs_ntacl.h b/usr/src/common/smbclnt/smbfs_ntacl.h
index d3ef999f58..830282cf44 100644
--- a/usr/src/common/smbclnt/smbfs_ntacl.h
+++ b/usr/src/common/smbclnt/smbfs_ntacl.h
@@ -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.
*/
#ifndef _SMBFS_NTACL_H
@@ -122,7 +124,7 @@ int mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd);
* Convert an internal SD to a ZFS-style ACL.
* Get uid/gid too if pointers != NULL.
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
int smbfs_acl_sd2zfs(i_ntsd_t *, vsecattr_t *, uid_t *, gid_t *);
#else /* _KERNEL */
/* See also: lib/libsmbfs/netsmb/smbfs_acl.h */
@@ -136,7 +138,7 @@ int smbfs_acl_sd2zfs(struct i_ntsd *, acl_t *, uid_t *, gid_t *);
* (when setting them) or existing, so that any
* owner@ or group@ ACEs can be translated.
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
int smbfs_acl_zfs2sd(vsecattr_t *, uid_t, gid_t, uint32_t, i_ntsd_t **);
#else /* _KERNEL */
/* See also: lib/libsmbfs/netsmb/smbfs_acl.h */
diff --git a/usr/src/common/smbios/smb_info.c b/usr/src/common/smbios/smb_info.c
index 71d5dd897d..2c67f2964a 100644
--- a/usr/src/common/smbios/smb_info.c
+++ b/usr/src/common/smbios/smb_info.c
@@ -1072,13 +1072,15 @@ id_t
smbios_info_boot(smbios_hdl_t *shp, smbios_boot_t *bp)
{
const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_BOOT);
- const smb_boot_t *b = (smb_boot_t *)(uintptr_t)stp->smbst_hdr;
+ const smb_boot_t *b;
if (stp == NULL)
return (-1); /* errno is set for us */
bzero(bp, sizeof (smbios_boot_t));
+ b = (smb_boot_t *)(uintptr_t)stp->smbst_hdr;
+
bp->smbt_status = b->smbbo_status[0];
bp->smbt_size = stp->smbst_hdr->smbh_len - sizeof (smb_boot_t);
bp->smbt_data = bp->smbt_size ? &b->smbbo_status[1] : NULL;
diff --git a/usr/src/compat/freebsd/amd64/machine/atomic.h b/usr/src/compat/freebsd/amd64/machine/atomic.h
index 6d8235d37c..d8e8131840 100644
--- a/usr/src/compat/freebsd/amd64/machine/atomic.h
+++ b/usr/src/compat/freebsd/amd64/machine/atomic.h
@@ -11,7 +11,7 @@
/*
* Copyright 2014 Pluribus Networks Inc.
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _COMPAT_FREEBSD_AMD64_MACHINE_ATOMIC_H_
@@ -238,6 +238,11 @@ atomic_swap_long(volatile u_long *p, u_long v)
/* Operations on pointers. */
#define atomic_cmpset_ptr atomic_cmpset_long
-#define mb() __asm __volatile("mfence;" : : : "memory")
+/* Needed for the membar functions */
+#include_next <sys/atomic.h>
+
+#define mb() membar_enter()
+#define rmb() membar_consumer()
+#define wmb() membar_producer()
#endif /* _COMPAT_FREEBSD_AMD64_MACHINE_ATOMIC_H_ */
diff --git a/usr/src/contrib/mDNSResponder/Clients/dns-sd.c b/usr/src/contrib/mDNSResponder/Clients/dns-sd.c
index 5ae5c48380..f99482be04 100644
--- a/usr/src/contrib/mDNSResponder/Clients/dns-sd.c
+++ b/usr/src/contrib/mDNSResponder/Clients/dns-sd.c
@@ -2288,7 +2288,7 @@ Fail:
// NOT static -- otherwise the compiler may optimize it out
// The "@(#) " pattern is a special prefix the "what" command looks for
-const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion);
#if _BUILDING_XCODE_PROJECT_
// If the process crashes, then this string will be magically included in the automatically-generated crash log
diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c b/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c
index 26477da593..c1cc6a4e65 100644
--- a/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c
+++ b/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c
@@ -273,8 +273,14 @@ asm (".desc ___crashreporter_info__, 0x10");
#endif
// For convenience when using the "strings" command, this is the last thing in the file
-#if mDNSResponderVersion > 1
-mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+#if defined(mDNSResponderVersion)
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion);
#elif MDNS_VERSIONSTR_NODTS
mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
#else
diff --git a/usr/src/data/hwdata/pci.ids b/usr/src/data/hwdata/pci.ids
index 311c6b0b29..118463573c 100644
--- a/usr/src/data/hwdata/pci.ids
+++ b/usr/src/data/hwdata/pci.ids
@@ -1,8 +1,8 @@
#
# List of PCI ID's
#
-# Version: 2018.10.25
-# Date: 2018-10-25 03:15:02
+# Version: 2019.03.12
+# Date: 2019-03-12 03:15:02
#
# Maintained by Albert Pool, Martin Mares, and other volunteers from
# the PCI ID Project at https://pci-ids.ucw.cz/.
@@ -57,8 +57,7 @@
0680 Ultra ATA/133 IDE RAID CONTROLLER CARD
# Wrong ID used in subsystem ID of the TELES.S0/PCI 2.x ISDN adapter
00a7 Teles AG (Wrong ID)
-# nee nCipher
-0100 Thales e-Security
+0100 nCipher Security
0123 General Dynamics
0128 Dell (wrong ID)
# 018a is not LevelOne but there is a board misprogrammed
@@ -220,8 +219,7 @@
0eac SHF Communication Technologies AG
0008 Ethernet Powerlink Managing Node 01
0f62 Acrox Technologies Co., Ltd.
-# Formerly NCR
-1000 LSI Logic / Symbios Logic
+1000 Broadcom / LSI
0001 53c810
1000 1000 LSI53C810AE PCI to SCSI I/O Processor
0002 53c820
@@ -267,6 +265,7 @@
1000 1000 LSI53C875A PCI to Ultra SCSI Controller
0014 MegaRAID Tri-Mode SAS3516
1028 1fd4 PERC H745P MX
+ 1137 020e UCSC-RAID-M5 12G Modular RAID Controller
1d49 0602 ThinkSystem RAID 930-16i 4GB Flash PCIe 12Gb Adapter
1d49 0604 ThinkSystem RAID 930-8e 4GB Flash PCIe 12Gb Adapter
1d49 0607 ThinkSystem RAID 930-16i 8GB Flash PCIe 12Gb Adapter
@@ -274,6 +273,7 @@
8086 9460 RAID Controller RSP3TD160F
8086 9480 RAID Controller RSP3MD088F
0015 MegaRAID Tri-Mode SAS3416
+ 1d49 0503 ThinkSystem RAID 530-16i PCIe 12Gb Adapter
0016 MegaRAID Tri-Mode SAS3508
1028 1fc9 PERC H840 Adapter
1028 1fcb PERC H740P Adapter
@@ -281,7 +281,6 @@
1028 1fcf PERC H740P Mini
1d49 0601 ThinkSystem RAID 930-8i 2GB Flash PCIe 12Gb Adapter
1d49 0603 ThinkSystem RAID 930-24i 4GB Flash PCIe 12Gb Adapter
- 1d49 0604 ThinkSystem RAID 930-8e 4GB Flash PCIe 12Gb Adapter
8086 352e Integrated RAID Module RMSP3CD080F
8086 352f Integrated RAID Module RMSP3HD080E
8086 9461 RAID Controller RSP3DD080F
@@ -401,7 +400,7 @@
8086 3510 RMS25PB080 RAID Controller
8086 3511 RMS25PB040 RAID Controller
8086 3512 RMT3PB080 RAID Controller
- 8086 3513 RMS25CB080 RAID Controller
+ 8086 3513 Integrated RAID Module RMS25CB080
8086 3514 RMS25CB040 RAID Controller
8086 351c RMS25PB080N RAID Controller
8086 351d RMS25CB080N RAID Controller
@@ -445,6 +444,7 @@
1028 1f4d PERC H330 Embedded (for monolithic)
1054 306a SAS 3004 iMR ROMB
1d49 04db ServeRAID M1210 SAS/SATA Controller
+ 1d49 0504 ThinkSystem RAID 520-8i PCIe 12Gb Adapter
0060 MegaRAID SAS 1078
1000 1006 MegaRAID SAS 8888ELP
1000 100a MegaRAID SAS 8708ELP
@@ -479,19 +479,24 @@
0062 SAS1078 PCI-Express Fusion-MPT SAS
1000 0062 SAS1078 PCI-Express Fusion-MPT SAS
0064 SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]
+ 1000 3030 9200-16e 6Gb/s SAS/SATA PCIe x8 External HBA
1000 30c0 SAS 9201-16i
+ 1000 30d0 9201-16e 6Gb/s SAS/SATA PCIe x8 External HBA
0065 SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]
006e SAS2308 PCI-Express Fusion-MPT SAS-2
0070 SAS2004 PCI-Express Fusion-MPT SAS-2 [Spitfire]
+ 1000 3010 SAS9211-4i
0071 MR SAS HBA 2004
0072 SAS2008 PCI-Express Fusion-MPT SAS-2 [Falcon]
+ 1000 3040 9210-8i
+ 1000 3080 9200-8e [LSI SAS 6Gb/s SAS/SATA PCIe x8 External HBA]
1000 30b0 9200-8e [LSI SAS 6Gb/s SAS/SATA PCIe x8 External HBA]
1028 1f1c 6Gbps SAS HBA Adapter
1028 1f1d PERC H200 Adapter
1028 1f1e PERC H200 Integrated
1028 1f1f PERC H200 Modular
1028 1f20 PERC H200 Embedded
- 1028 1f22 Internal Tape Adapter
+ 1028 1f22 PERC H200 Internal Tape Adapter
8086 350f RMS2LL040 RAID Controller
8086 3700 SSD 910 Series
0073 MegaRAID SAS 2008 [Falcon]
@@ -499,6 +504,7 @@
1000 9241 MegaRAID SAS 9240-4i
1000 92a0 MegaRAID SAS 9220-8i
1014 03b1 ServeRAID M1015 SAS/SATA Controller
+ 1014 040d ServeRAID M1115 SAS/SATA Controller
1028 1f4e PERC H310 Adapter
1028 1f4f PERC H310 Integrated
1028 1f50 PERC H310 Mini Blades
@@ -506,6 +512,7 @@
1028 1f52 PERC H310 Embedded1
1028 1f53 PERC H310 Embedded2
1028 1f54 PERC H310 Reserved
+ 1028 1f78 PERC H310
1054 3035 LSI MegaRAID SAS 9240-8i
1137 0072 2004 iMR ROMB
1137 0073 2008 ROMB
@@ -586,10 +593,14 @@
0084 SAS2208 PCI-Express Fusion-MPT SAS-2
0085 SAS2208 PCI-Express Fusion-MPT SAS-2
0086 SAS2308 PCI-Express Fusion-MPT SAS-2
+ 15d9 0690 Onboard MegaRAID SAS2208 [Thunderbolt]
+ 15d9 0691 Onboard SAS2308 PCI-Express Fusion-MPT SAS-2
0087 SAS2308 PCI-Express Fusion-MPT SAS-2
1000 3020 9207-8i SAS2.1 HBA
+ 1000 3030 SAS9207-4i4e
1000 3040 9207-8e SAS2.1 HBA
1000 3050 SAS9217-8i
+ 1014 0472 N2125 External Host Bus Adapter
1590 0044 H220i
8086 3000 RS25GB008 RAID Controller
8086 3060 RS25FB044 RAID Controller
@@ -617,6 +628,8 @@
1028 1f53 HBA330 Mini
1028 1fd2 HBA330 MX
1028 1fd3 HBA330 MMZ
+# Supermicro AOC-S3008L-L8e uses 0808 for their SAS3008 SAS controller
+ 15d9 0808 AOC-S3008L-L8e
1bd4 0011 Inspur 12Gb 8i-3008 IT SAS HBA
00ab SAS3516 Fusion-MPT Tri-Mode RAID On Chip (ROC)
8086 3530 Integrated RAID Module RMSP3JD160J
@@ -627,6 +640,7 @@
8086 3020 RAID Controller RSP3GD016J
00ae SAS3508 Fusion-MPT Tri-Mode RAID On Chip (ROC)
00af SAS3408 Fusion-MPT Tri-Mode I/O Controller Chip (IOC)
+ 1000 3010 HBA 9400-8i
1d49 0200 ThinkSystem 430-8i SAS/SATA 12Gb HBA
1d49 0202 ThinkSystem 430-8e SAS/SATA 12Gb HBA
1d49 0204 ThinkSystem 430-8i SAS/SATA 12Gb Dense HBA
@@ -650,6 +664,14 @@
00d0 SAS3716 Fusion-MPT Tri-Mode RAID Controller Chip (ROC)
00d1 SAS3616 Fusion-MPT Tri-Mode I/O Controller Chip (IOC)
00d3 MegaRAID Tri-Mode SAS3716W
+ 00e0 Fusion-MPT 12GSAS/PCIe Unsupported SAS39xx
+ 00e1 Fusion-MPT 12GSAS/PCIe SAS39xx
+ 00e2 Fusion-MPT 12GSAS/PCIe Secure SAS39xx
+ 00e3 Fusion-MPT 12GSAS/PCIe Unsupported SAS39xx
+ 00e4 Fusion-MPT 12GSAS/PCIe Unsupported SAS38xx
+ 00e5 Fusion-MPT 12GSAS/PCIe SAS38xx
+ 00e6 Fusion-MPT 12GSAS/PCIe Secure SAS38xx
+ 00e7 Fusion-MPT 12GSAS/PCIe Unsupported SAS38xx
02b0 Virtual Endpoint on PCIe Switch
1d49 0001 ThinkSystem 1610-4P NVMe Switch Adapter
1d49 0002 ThinkSystem 810-4P NVMe Switch Adapter
@@ -725,6 +747,14 @@
0807 SA2020ZC
0901 61C102
1000 63C815
+ 10e0 MegaRAID 12GSAS/PCIe Unsupported SAS39xx
+ 10e1 MegaRAID 12GSAS/PCIe SAS39xx
+ 10e2 MegaRAID 12GSAS/PCIe Secure SAS39xx
+ 10e3 MegaRAID 12GSAS/PCIe Unsupported SAS39xx
+ 10e4 MegaRAID 12GSAS/PCIe Unsupported SAS38xx
+ 10e5 MegaRAID 12GSAS/PCIe SAS38xx
+ 10e6 MegaRAID 12GSAS/PCIe Secure SAS38xx
+ 10e7 MegaRAID 12GSAS/PCIe Unsupported SAS38xx
1960 MegaRAID
1000 0518 MegaRAID 518 SCSI 320-2 Controller
1000 0520 MegaRAID 520 SCSI 320-1 Controller
@@ -777,11 +807,21 @@
131b Kaveri [Radeon R4 Graphics]
131c Kaveri [Radeon R7 Graphics]
131d Kaveri [Radeon R6 Graphics]
+ 13e9 Ariel
+ 154c Kryptos
+ 154e Garfield
+ 1551 Arlene
+ 1552 Pooky
+ 1561 Anubis
15d8 Picasso
15dd Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series]
103c 83c6 Radeon Vega 8 Mobile
1458 d000 Radeon RX Vega 11
- 15ff Vega 11 [Radeon Vega 28 Mobile]
+ 15de Raven/Raven2/Fenghuang HDMI/DP Audio Controller
+ 15df Raven/Raven2/Fenghuang/Renoir Cryptographic Coprocessor
+ 15ff Fenghuang [Zhongshan Subor Z+]
+ 1607 Arden
+ 1636 Renoir
1714 BeaverCreek HDMI Audio [Radeon HD 6500D and 6400G-6600G series]
103c 168b ProBook 4535s
3150 RV380/M24 [Mobility Radeon X600]
@@ -863,19 +903,28 @@
4337 RS200M [Radeon IGP 330M/340M/345M/350M]
1014 053a ThinkPad R40e
103c 0850 Radeon IGP 345M
- 4341 IXP150 AC'97 Audio Controller
- 4342 IXP200 3COM 3C920B Ethernet Controller
- 4345 EHCI USB Controller
- 4347 OHCI USB Controller #1
- 4348 OHCI USB Controller #2
- 4349 Dual Channel Bus Master PCI IDE Controller
- 434d IXP AC'97 Modem
- 4353 SMBus
+ 4341 SB200 AC97 Audio Controller
+ 4342 SB200 PCI to PCI Bridge
+ 4345 SB200 EHCI USB Controller
+ 4346 Crayola 6 [XENOS Parent Die (XBOX 360)]
+ 4347 SB200 OHCI USB Controller #1
+ 4348 SB200 OHCI USB Controller #2
+ 4349 SB200 IDE Controller
+ 434c SB200 PCI to LPC Bridge
+ 434d SB200 AC97 Modem Controller
+ 4353 SB200 SMBus Controller
4354 215CT [Mach64 CT PCI]
4358 Mach64 CX [Graphics Xpression]
- 4361 IXP SB300 AC'97 Audio Controller
- 4363 SMBus
- 436e 436E Serial ATA Controller
+ 4361 SB300 AC'97 Audio Controller
+ 4362 SB300 PCI to PCI Bridge
+ 4363 SB300 SMBus Controller
+ 4365 SB300 USB Controller (EHCI)
+ 4367 SB300 USB Controller (EHCI)
+ 4368 SB300 USB Controller (EHCI)
+ 4369 SB300 IDE Controller
+ 436c SB300 PCI to LPC Bridge
+ 436d SB300 AC97 Modem Controller
+ 436e SB300 Serial ATA Controller
4370 IXP SB400 AC'97 Audio Controller
1025 0079 Aspire 5024WLMMi
1025 0091 Aspire 5032WXMi
@@ -1021,6 +1070,7 @@
103c 1611 Pavilion DM1Z-3000
1043 82ef M3A78-EH Motherboard
1043 8443 M5A88-V EVO
+ 1043 84dd M5A99X EVO (R1.0) SB950
105b 0e13 N15235/A74MX mainboard / AMD SB700
174b 1001 PURE Fusion Mini
4392 SB7x0/SB8x0/SB9x0 SATA Controller [Non-RAID5 mode]
@@ -1056,6 +1106,7 @@
105b 0e13 N15235/A74MX mainboard / AMD SB700
174b 1001 PURE Fusion Mini
439c SB7x0/SB8x0/SB9x0 IDE Controller
+ 1002 4392 MSI MS-7713 motherboard
1019 2120 A785GM-M
1043 82ef M3A78-EH Motherboard
105b 0e13 N15235/A74MX mainboard / AMD SB700
@@ -1072,6 +1123,8 @@
43a3 SB900 PCI to PCI bridge (PCIE port 3)
4437 RS250 [Mobility Radeon 7000 IGP]
4554 210888ET [Mach64 ET]
+ 4630 XENOS Parent Die (XBOX 360)
+ 4631 XENOS Daughter Die (XBOX 360)
4654 Mach64 VT
4742 Rage 3 [3D Rage PRO AGP 2X]
1002 0040 Rage Pro Turbo AGP 2X
@@ -1152,6 +1205,60 @@
1002 0084 Rage 3D Pro AGP 2x XPERT 98
1002 0087 Rage 3D IIC
1002 475a Rage IIC AGP
+ 4845 Xilleon 220 HBIU for HDTV2
+ 4846 Xilleon 220 IDE for HDTV2
+ 4847 Xilleon 220 USB for HDTV2
+ 4848 Xilleon 220 DAIO-0 for HDTV2
+ 4849 Xilleon 220 DAIO-1 for HDTV2
+ 484a Xilleon 220 LPC for HDTV2
+ 4850 Xilleon 215 HBIU for X215
+ 4851 Xilleon 215 IDE for X215
+ 4852 Xilleon 215 USB for X215
+ 4853 Xilleon 215 DAIO-0 for X215
+ 4854 Xilleon 215 DAIO-1 for X215
+ 4855 Xilleon 225 HBIU for X225
+ 4856 Xilleon 225 IDE for X225
+ 4857 Xilleon 225 USB for X225
+ 4858 Xilleon 225 DAIO-0 for X225
+ 4859 Xilleon 225 DAIO-1 for X225
+ 4860 Xilleon 210 HBIU for X210
+ 4861 Xilleon 210 IDE for X210
+ 4862 Xilleon 210 USB for X210
+ 4863 Xilleon 210 DAIO-0 for X210
+ 4864 Xilleon 210 DAIO-1 for X210
+ 4865 Xilleon 226 HBIU for X226
+ 4866 Xilleon 226 IDE for X226
+ 4867 Xilleon 226 USB for X226
+ 4868 Xilleon 226 DAIO-0 for X226
+ 4869 Xilleon 226 DAIO-1 for X226
+ 486a Xilleon 240S HBIU for X240S
+ 486b Xilleon 240H HBIU for X240H
+ 486c Xilleon 240S USB for X240S
+ 486d Xilleon 240H USB for X240H
+ 486e Xilleon 250 USB 1.1 for X250
+ 486f Xilleon 260 USB 1.1 for X260
+ 4870 Xilleon 250 HBIU for X250
+ 4871 Xilleon 250 IDE for X250
+ 4872 Xilleon 234/235 HBIU for X234/X235
+ 4873 Xilleon 244/245 HBIU for X244/X245
+ 4874 Xilleon 234/235 USB 1.1 for X234/X235
+ 4875 Xilleon 260 HBIU for X260
+ 4876 Xilleon 260 IDE for X260
+ 4877 Xilleon 244/245 USB 1.1 for X244/X245
+ 4878 Xilleon 270 HBIU for X270
+ 487b Xilleon 242 HBIU for X242
+ 487d Xilleon 242 USB 1.1 for X242
+ 4880 Xilleon 254 HBIU for X254
+ 4881 Xilleon 254 USB 1.1 for X254
+ 4882 Xilleon 255 HBIU for X255
+ 4883 Xilleon 255 USB 1.1 for X255
+ 4884 Xilleon 243 HBIU for X243
+ 4885 Xilleon 243 USB 1.1 for X243
+ 4886 Xilleon 233 HBIU for X233
+ 4887 Xilleon 233 USB 1.1 for X233
+ 4888 Xilleon 143 HBIU for X143
+ 4889 Xilleon 143 HBIU for X143L
+ 488a Xilleon 143 HBIU for X143S
4966 RV250 [Radeon 9000 Series]
10f1 0002 RV250 If [Tachyon G9000 PRO]
148c 2039 RV250 If [Radeon 9000 Pro "Evil Commando"]
@@ -1626,8 +1733,6 @@
103c 1952 ProBook 455 G1
6601 Mars [Radeon HD 8730M]
103c 2100 FirePro M4100
- 6602 Mars
- 6603 Mars
6604 Opal XT [Radeon R7 M265/M365X/M465]
1025 0776 Aspire V5 Radeon R7 M265
103c 8006 FirePro M4170
@@ -1660,9 +1765,6 @@
6613 Oland PRO [Radeon R7 240/340]
148c 7340 Radeon R7 340
1682 7240 R7 240 2048 MB
- 6620 Mars
- 6621 Mars PRO
- 6623 Mars
6631 Oland
6640 Saturn XT [FirePro M6100]
106b 014b Tropo XT [Radeon R9 M380 Mac Edition]
@@ -1704,7 +1806,7 @@
1462 2938 Radeon R9 360 OEM
1462 3271 Radeon R9 360 OEM
1682 7360 Radeon R7 360
- 6660 Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330 / M430 / R7 M520]
+ 6660 Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330 / M430 / Radeon 520 Mobile]
1028 05ea Radeon HD 8670M
1028 06bf Radeon R5 M335
103c 1970 Radeon HD 8670M
@@ -1720,7 +1822,8 @@
1025 0846 Radeon HD 8570A
17aa 3805 Radeon HD 8570M
6664 Jet XT [Radeon R5 M240]
- 6665 Jet PRO [Radeon R5 M230]
+ 6665 Jet PRO [Radeon R5 M230 / R7 M260DX / Radeon 520 Mobile]
+ 17aa 1309 Radeon R7 M260DX
17aa 368f Radeon R5 A230
6667 Jet ULT [Radeon R5 M230]
666f Sun LE [Radeon HD 8550M / R5 M230]
@@ -1729,7 +1832,7 @@
66a2 Vega 20
66a3 Vega 20
66a7 Vega 20 [Radeon Pro Vega 20]
- 66af Vega 20
+ 66af Vega 20 [Radeon VII]
6704 Cayman PRO GL [FirePro V7900]
6707 Cayman LE GL [FirePro V5900]
6718 Cayman XT [Radeon HD 6970]
@@ -2184,6 +2287,7 @@
1028 2120 Radeon HD 6450
103c 2128 Radeon HD 6450
103c 2aee Radeon HD 7450A
+ 1092 6450 Radeon HD 6450
1462 2125 Radeon HD 6450
1462 2346 Radeon HD 7450
1462 2490 Radeon HD 6450
@@ -2330,7 +2434,7 @@
67cc Ellesmere [Polaris10]
67cf Ellesmere [Polaris10]
67d0 Ellesmere [Radeon Pro V7300X / V7350x2]
- 67df Ellesmere [Radeon RX 470/480/570/570X/580/580X]
+ 67df Ellesmere [Radeon RX 470/480/570/570X/580/580X/590]
1002 0b37 Radeon RX 480
1028 1722 Radeon RX 570X
1028 1723 Radeon RX 580X
@@ -2338,6 +2442,7 @@
1043 04b0 Radeon RX 470
1043 04fb Radeon RX 480
1043 04fd Radeon RX 480 8GB
+ 1043 056a Radeon RX 590
106b 0161 Radeon Pro 580
106b 0162 Radeon Pro 575
106b 0163 Radeon Pro 570
@@ -2347,18 +2452,20 @@
1462 3413 Radeon RX 480 Gaming X 8GB
1462 3416 Radeon RX 570
1462 3418 Radeon RX 580 Armor 4G OC
+ 1462 8a92 Radeon RX 580
148c 2372 Radeon RX 480
148c 2373 Radeon RX 470
1682 9470 Radeon RX 470
1682 9480 Radeon RX 480
1682 9588 Radeon RX 580 XTR
+ 1682 c570 Radeon RX 570
174b e347 Radeon RX 470/480
174b e349 Radeon RX 470
1787 a470 Radeon RX 470
1787 a480 Radeon RX 480
1849 5001 Phantom Gaming X RX 580 OC
1da2 e353 Radeon RX 570 Pulse 4GB
- 1da2 e366 Nitro+ Radeon RX 580 4GB
+ 1da2 e366 Nitro+ Radeon RX 570/580
67e0 Baffin [Radeon Pro WX 4170]
103c 8270 Radeon Pro WX 4170
103c 8272 Radeon Pro WX 4170
@@ -2376,6 +2483,7 @@
67e9 Baffin [Polaris11]
67eb Baffin [Radeon Pro V5300X]
67ef Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X]
+ 103c 3421 Radeon RX 460
106b 0160 Radeon Pro 460
106b 0166 Radeon Pro 455
106b 0167 Radeon Pro 450
@@ -2611,9 +2719,11 @@
6863 Vega 10 XTX [Radeon Vega Frontier Edition]
6864 Vega
6867 Vega 10 XL [Radeon Pro Vega 56]
- 6868 Vega 10 [Radeon PRO WX 8100]
+ 6868 Vega 10 [Radeon PRO WX 8100/8200]
686c Vega 10 [Radeon Instinct MI25 MxGPU]
687f Vega 10 XL/XT [Radeon RX Vega 56/64]
+ 1002 0b36 RX Vega64
+ 1002 6b76 RX Vega56
6880 Lexington [Radeon HD 6550M]
103c 163c Pavilion dv6 Radeon HD 6550M
6888 Cypress XT [FirePro V8800]
@@ -3129,8 +3239,9 @@
148c 9380 Radeon R9 380
# Make naming scheme consistent
174b e308 Radeon R9 380 Nitro 4G D5
- 694c Polaris 22 [Radeon RX Vega M GH]
+ 694c Polaris 22 XT [Radeon RX Vega M GH]
694e Polaris 22 XL [Radeon RX Vega M GL]
+ 694f Polaris 22 MGL XL [Radeon Pro WX Vega M GL]
6980 Polaris12
6981 Polaris12
6985 Lexa XT [Radeon PRO WX 3100]
@@ -3145,7 +3256,7 @@
69a1 Vega 12
69a2 Vega 12
69a3 Vega 12
- 69af Vega 12
+ 69af Vega 12 [Radeon Pro Vega 20]
6fdf Polaris 20 XL [Radeon RX 580 2048SP]
700f RS100 AGP Bridge
7010 RS200/RS250 AGP Bridge
@@ -3289,6 +3400,8 @@
1043 049e Radeon R9 FURY
1043 04a0 Radeon R9 FURY X
174b e329 Radeon R9 FURY
+ 7310 Navi 10
+ 731f Navi 10
7833 RS350 Host Bridge
7834 RS350 [Radeon 9100 PRO/XT IGP]
7835 RS350M [Mobility Radeon 9000 IGP]
@@ -3502,16 +3615,16 @@
9613 RS780MC [Mobility Radeon HD 3100]
9614 RS780D [Radeon HD 3300]
9616 RS780L [Radeon 3000]
- 9640 BeaverCreek [Radeon HD 6550D]
- 9641 BeaverCreek [Radeon HD 6620G]
- 9642 Sumo [Radeon HD 6370D]
- 9643 Sumo [Radeon HD 6380G]
- 9644 Sumo [Radeon HD 6410D]
- 9645 Sumo [Radeon HD 6410D]
- 9647 BeaverCreek [Radeon HD 6520G]
+ 9640 Sumo [Radeon HD 6550D]
+ 9641 Sumo [Radeon HD 6620G]
+ 9642 SuperSumo [Radeon HD 6370D]
+ 9643 SuperSumo [Radeon HD 6380G]
+ 9644 SuperSumo [Radeon HD 6410D]
+ 9645 SuperSumo [Radeon HD 6410D]
+ 9647 Sumo [Radeon HD 6520G]
9648 Sumo [Radeon HD 6480G]
- 9649 Sumo [Radeon HD 6480G]
- 964a BeaverCreek [Radeon HD 6530D]
+ 9649 SuperSumo [Radeon HD 6480G]
+ 964a Sumo [Radeon HD 6530D]
964b Sumo
964c Sumo
964e Sumo
@@ -3581,6 +3694,8 @@
17aa 5113 Radeon R6 Graphics
17aa 5116 Radeon R6 Graphics
17aa 5118 Radeon R5 Graphics
+ 9890 Amur
+ 98c0 Nolan
98e4 Stoney [Radeon R2/R3/R4/R5 Graphics]
9900 Trinity [Radeon HD 7660G]
103c 1985 Pavilion 17-e163sg Notebook PC
@@ -3609,13 +3724,19 @@
9917 Trinity [Radeon HD 7620G]
9918 Trinity [Radeon HD 7600G]
9919 Trinity [Radeon HD 7500G]
+ 991e Bishop
9920 Liverpool [Playstation 4 APU]
9921 Liverpool HDMI/DP Audio Controller
- 9990 Trinity [Radeon HD 7520G]
- 9991 Trinity [Radeon HD 7540D]
- 9992 Trinity [Radeon HD 7420G]
- 9993 Trinity [Radeon HD 7480D]
- 9994 Trinity [Radeon HD 7400G]
+ 9922 Starshp
+ 9923 Starsha2 [Kingston/Clayton]
+ 9924 Gladius
+ 9925 Kingston/Clayton/Jupiter/Gladius/Montego HDMI Controller
+ 9926 Jupiter
+ 9990 Trinity 2 [Radeon HD 7520G]
+ 9991 Trinity 2 [Radeon HD 7540D]
+ 9992 Trinity 2 [Radeon HD 7420G]
+ 9993 Trinity 2 [Radeon HD 7480D]
+ 9994 Trinity 2 [Radeon HD 7400G]
9995 Richland [Radeon HD 8450G]
9996 Richland [Radeon HD 8470D]
9997 Richland [Radeon HD 8350G]
@@ -3626,9 +3747,9 @@
999c Richland
# AMD Quad-Core A8-Series APU A8-6500T with Radeon HD 8550D
999d Richland [Radeon HD 8550D]
- 99a0 Trinity [Radeon HD 7520G]
- 99a2 Trinity [Radeon HD 7420G]
- 99a4 Trinity [Radeon HD 7400G]
+ 99a0 Trinity 2 [Radeon HD 7520G]
+ 99a2 Trinity 2 [Radeon HD 7420G]
+ 99a4 Trinity 2 [Radeon HD 7400G]
aa00 R600 HDMI Audio [Radeon HD 2900 GT/PRO/XT]
aa01 RV635 HDMI Audio [Radeon HD 3650/3730/3750]
aa08 RV630 HDMI Audio [Radeon HD 2600 PRO/XT / HD 3610]
@@ -3657,17 +3778,38 @@
aa98 Caicos HDMI Audio [Radeon HD 6450 / 7450/8450/8490 OEM / R5 230/235/235X OEM]
174b aa98 Radeon HD 6450 1GB DDR3
aaa0 Tahiti HDMI Audio [Radeon HD 7870 XT / 7950/7970]
- aab0 Cape Verde/Pitcairn HDMI Audio [Radeon HD 7700/7800 Series]
+ aab0 Oland/Hainan/Cape Verde/Pitcairn HDMI Audio [Radeon HD 7000 Series]
+ aab8 Tiran HDMI Audio
aac0 Tobago HDMI Audio [Radeon R7 360 / R9 360 OEM]
aac8 Hawaii HDMI Audio [Radeon R9 290/290X / 390/390X]
-# I have a Tonga card and this is the HDMI Audio part
aad8 Tonga HDMI Audio [Radeon R9 285/380]
174b aad8 Radeon R9 285/380 HDMI Audio
aae0 Baffin HDMI/DP Audio [Radeon RX 550 640SP / RX 560/560X]
aae8 Fiji HDMI/DP Audio [Radeon R9 Nano / FURY/FURY X]
- aaf0 Ellesmere [Radeon RX 580]
- ac00 Theater 600 Pro
+ aaf0 Ellesmere HDMI Audio [Radeon RX 470/480 / 570/580/590]
+ aaf8 Vega 10 HDMI Audio [Radeon Vega 56/64]
+ ab00 Baffin HDMI/DP Audio [Radeon RX 550 640SP / RX 560/560X]
+ ab08 Polaris 22 HDMI Audio
+ ab10 Lexa HDMI Audio
+ ab18 Vega 12 HDMI Audio
+ ab20 Vega 20 HDMI Audio [Radeon VII]
+ ab38 Navi 10 HDMI Audio
+ ac00 Theater 506 World-Wide Analog Decoder
+ ac01 Theater 506 World-Wide Analog Decoder
ac02 TV Wonder HD 600 PCIe
+ ac03 Theater 506 PCIe
+ ac04 Theater 506 USB
+ ac05 Theater 506 USB
+ ac06 Theater 506 External USB
+ ac07 Theater 506 External USB
+ ac08 Theater 506A World-Wide Analog Decoder + Demodulator
+ ac09 Theater 506A World-Wide Analog Decoder + Demodulator
+ ac0a Theater 506A PCIe
+ ac0b Theater 506A PCIe
+ ac0c Theater 506A USB
+ ac0d Theater 506A USB
+ ac0e Theater 506A External USB
+ ac0f Theater 506A External USB
ac12 Theater HD T507 (DVB-T) TV tuner/capture device
cab0 RS100 Host Bridge
cab2 RS200 Host Bridge
@@ -4179,6 +4321,35 @@
1302 Family 11h Processor DRAM Controller
1303 Family 11h Processor Miscellaneous Control
1304 Family 11h Processor Link Control
+ 1305 Griffin Function 5
+ 1306 Griffin Function 6
+ 1307 Griffin Function 7
+ 1308 Kaveri Audio Controller
+ 1314 Wrestler/Bheem/Ontario/Krishna Audio Controller
+ 13e0 Ariel Root Complex
+ 13e1 Ariel IOMMU
+ 13e2 Ariel PCIe Dummy Host Bridge
+ 13e3 Ariel PCIe GPP Bridge
+ 13e4 Ariel PCIe Dummy Host Bridge
+ 13e5 Ariel Internal PCIe GPP Bridge 0 to Bus A
+ 13e6 Ariel Internal PCIe GPP Bridge 0 to Bus B
+ 13e7 Ariel SMBus Controller
+ 13e8 Ariel LPC Bridge
+ 13e9 Ariel Internal GPU
+ 13ea Ariel HD Audio Controller
+ 13eb Ariel HD Audio Coprocessor
+ 13ec Ariel Cryptographic Coprocessor
+ 13ed Ariel USB 3.1 Type C: Gen2 x 1port + DP Alt Mode
+ 13ee Ariel USB 3.1 Type A: Gen2 x 2 ports
+ 13ef Ariel ZCN/MP4
+ 13f0 Ariel Device 24: Function 0
+ 13f1 Ariel Device 24: Function 1
+ 13f2 Ariel Device 24: Function 2
+ 13f3 Ariel Device 24: Function 3
+ 13f4 Ariel Device 24: Function 4
+ 13f5 Ariel Device 24: Function 5
+ 13f6 Ariel Device 24: Function 6
+ 13f7 Ariel Device 24: Function 7
1400 Family 15h (Models 10h-1fh) Processor Function 0
1401 Family 15h (Models 10h-1fh) Processor Function 1
1402 Family 15h (Models 10h-1fh) Processor Function 2
@@ -4206,26 +4377,51 @@
1422 Family 15h (Models 30h-3fh) Processor Root Complex
1423 Family 15h (Models 30h-3fh) I/O Memory Management Unit
1424 Family 15h (Models 30h-3fh) Processor Root Port
+ 1425 Kaveri P2P Bridge for GFX PCIe Port [1:0]
1426 Family 15h (Models 30h-3fh) Processor Root Port
- 142e Liverpool Processor Function 0
- 142f Liverpool Processor Function 1
- 1430 Liverpool Processor Function 2
- 1431 Liverpool Processor Function 3
- 1432 Liverpool Processor Function 4
+ 142e Liverpool Processor HT configuration
+ 142f Liverpool Processor Address Maps
+ 1430 Liverpool Processor DRAM configuration
+ 1431 Liverpool Processor Misc configuration
+ 1432 Liverpool Processor PM configuration
+ 1433 Liverpool Processor NB Performance Monitor
+ 1434 Liverpool Processor SPLL Configuration
1436 Liverpool Processor Root Complex
1437 Liverpool I/O Memory Management Unit
- 1438 Liverpool Processor Root Port
+ 1438 Liverpool UMI PCIe Dummy Host Bridge
1439 Family 16h Processor Functions 5:1
+ 143a Kingston/Clayton/Gladius/Montego Root Complex
+ 143b Kingston/Clayton/Gladius/Montego P2P Bridge for UMI Link
+ 1440 Matisse Device 24: Function 0
+ 1441 Matisse Device 24: Function 1
+ 1442 Matisse Device 24: Function 2
+ 1443 Matisse Device 24: Function 3
+ 1444 Matisse Device 24: Function 4
+ 1445 Matisse Device 24: Function 5
+ 1446 Matisse Device 24: Function 6
+ 1447 Matisse Device 24: Function 7
+ 1448 Renoir Device 24: Function 0
+ 1449 Renoir Device 24: Function 1
+ 144a Renoir Device 24: Function 2
+ 144b Renoir Device 24: Function 3
+ 144c Renoir Device 24: Function 4
+ 144d Renoir Device 24: Function 5
+ 144e Renoir Device 24: Function 6
+ 144f Renoir Device 24: Function 7
1450 Family 17h (Models 00h-0fh) Root Complex
1451 Family 17h (Models 00h-0fh) I/O Memory Management Unit
- 1452 Family 17h (Models 00h-0fh) PCIe Dummy Host Bridge
+ 1452 Family 17h (Models 00h-1fh) PCIe Dummy Host Bridge
1453 Family 17h (Models 00h-0fh) PCIe GPP Bridge
1454 Family 17h (Models 00h-0fh) Internal PCIe GPP Bridge 0 to Bus B
+ 1455 Zeppelin/Renoir PCIe Dummy Function
1456 Family 17h (Models 00h-0fh) Platform Security Processor
1457 Family 17h (Models 00h-0fh) HD Audio Controller
+ 145a Zeppelin/Raven/Raven2 PCIe Dummy Function
145b Zeppelin Non-Transparent Bridge
145c Family 17h (Models 00h-0fh) USB 3.0 Host Controller
- 145f USB 3.0 Host controller
+ 145d Zeppelin Switch Upstream (PCIE SW.US)
+ 145e Zeppelin Switch Downstream (PCIE SW.DS)
+ 145f Zeppelin USB 3.0 Host controller
1460 Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 0
1461 Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 1
1462 Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 2
@@ -4234,6 +4430,36 @@
1465 Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 5
1466 Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 6
1467 Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 7
+ 1468 Zeppelin Cryptographic Coprocessor NTBCCP
+ 1480 Starship/Matisse Root Complex
+ 1481 Starship/Matisse IOMMU
+ 1482 Starship/Matisse PCIe Dummy Host Bridge
+ 1483 Starship/Matisse GPP Bridge
+ 1484 Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B]
+ 1485 Starship/Matisse Reserved SPP
+ 1486 Starship/Matisse Cryptographic Coprocessor PSPCPP
+ 1487 Starship/Matisse HD Audio Controller
+ 1488 Starship Reserved SSP
+ 1489 Starship Reserved SSP
+ 148a Starship/Matisse PCIe Dummy Function
+ 148b Starship/Matisse Non-Transparent Bridge
+ 148c Starship USB 3.0 Host Controller
+ 148d Starship/Matisse Switch Upstream (PCIE SW.US)
+ 148e Starship/Matisse Switch Downstream (PCIE SW.DS)
+ 148f Starship Reserved SSP
+ 1490 Starship Device 24; Function 0
+ 1491 Starship Device 24; Function 1
+ 1492 Starship Device 24; Function 2
+ 1493 Starship Device 24; Function 3
+ 1494 Starship Device 24; Function 4
+ 1495 Starship Device 24; Function 5
+ 1496 Starship Device 24; Function 6
+ 1497 Starship Device 24; Function 7
+ 1498 Starship/Matisse PTDMA
+ 1499 Starship/Matisse NVMe
+ 149a Starship PCIe GPP Bridge [1:0]
+ 149b Starship Reserved SSP
+ 149c Matisse USB 3.0 Host Controller
1510 Family 14h Processor Root Complex
174b 1001 PURE Fusion Mini
1512 Family 14h Processor Root Port
@@ -4248,7 +4474,33 @@
1534 Family 16h Processor Function 4
1535 Family 16h Processor Function 5
1536 Family 16h Processor Root Complex
+ 1537 Kabini/Mullins PSP-Platform Security Processor
1538 Family 16h Processor Function 0
+ 1539 Kabini P2P Bridge for PCIe Ports[4:0]
+ 1540 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky HT Configuration
+ 1541 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Address Maps
+ 1542 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky DRAM Configuration
+ 1543 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Miscellaneous Configuration
+ 1544 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky PM Configuration
+ 1545 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky NB Performance Monitor
+ 1546 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Root Complex
+ 1547 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky IOMMU
+ 1548 Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky UMI PCIe Dummy Host Bridge
+ 1549 Kryptos/Cato/Garfield/Garfield+ P2P Bridge for PCIe Port [3:0]
+ 154a Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Audio Processor
+ 154b Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky Security Processor
+ 154d Kryptos/Cato/Garfield/Garfield+/Arlene/Pooky/Anubis HDMI Controller
+ 154f Anubis Audio Processor
+ 1550 Garfield+/Arlene/Pooky/Anubis SPLL Configuration
+ 1553 Arlene/Pooky P2P Bridge for PCIE (3:0)
+ 155b Anubis Root Complex
+ 155c Anubis IOMMU
+ 155d Anubis UMI PCIe Dummy Bridge
+ 155e Anubis P2P Bridge for PCIe Ports [4:0]
+ 1560 Anubis Security Processor
+ 1566 Family 16h (Models 30h-3fh) Processor Root Complex
+ 1567 Mullins IOMMU
+ 156b Family 16h (Models 30h-3fh) Host Bridge
1570 Family 15h (Models 60h-6fh) Processor Function 0
1571 Family 15h (Models 60h-6fh) Processor Function 1
1572 Family 15h (Models 60h-6fh) Processor Function 2
@@ -4257,21 +4509,126 @@
1575 Family 15h (Models 60h-6fh) Processor Function 5
1576 Family 15h (Models 60h-6fh) Processor Root Complex
1577 Family 15h (Models 60h-6fh) I/O Memory Management Unit
+ 1578 Carrizo Platform Security Processor
+ 1579 Carrizo Audio Processor
157a Family 15h (Models 60h-6fh) Audio Controller
157b Family 15h (Models 60h-6fh) Host Bridge
157c Family 15h (Models 60h-6fh) Processor Root Port
+ 157d Carrizo Audio Dummy Host Bridge
+ 157e Carrizo Audio Controller
+ 1580 Family 16h (Models 30h-3fh) Processor Function 0
+ 1581 Family 16h (Models 30h-3fh) Processor Function 1
+ 1582 Family 16h (Models 30h-3fh) Processor Function 2
+ 1583 Family 16h (Models 30h-3fh) Processor Function 3
+ 1584 Family 16h (Models 30h-3fh) Processor Function 4
+ 1585 Family 16h (Models 30h-3fh) Processor Function 5
+ 1590 Amur/Nolan HT Configuration
+ 1591 Amur/Nolan Address Maps
+ 1592 Amur/Nolan DRAM Configuration
+ 1593 Amur/Nolan Miscellaneous Configuration
+ 1594 Amur/Nolan PM Configuration
+ 1595 Amur/Nolan NB Performance Monitor
+ 1596 Amur/Nolan Root Complex
+ 1597 Amur/Nolan IOMMU
+ 1598 Amur/Nolan Platform Security Processor
+ 1599 Amur/Nolan PCIe Dummy Host Bridge
+ 159d Amur Function 6: Gasket
+ 15b0 Stoney HT Configuration
+ 15b1 Stoney Address Maps
+ 15b2 Stoney DRAM Configuration
+ 15b3 Stoney Miscellaneous Configuration
+ 15b4 Stoney PM Configuration
+ 15b5 Stoney NB Performance Monitor
+ 15bc Stoney PCIe [GFX,GPP] Bridge [4:0]
+ 15be Stoney Audio Processor
+ 15d0 Raven/Raven2 Root Complex
+ 15d1 Raven/Raven2 IOMMU
+ 15d2 Raven/Raven2 PCIe Dummy Host Bridge
+ 15d3 Raven/Raven2 PCIe GPP Bridge [6:0]
+ 15d4 FireFlight USB 3.1
+ 15d5 FireFlight USB 3.1
+ 15da Raven/Raven2 PCIe Dummy Host Bridge
+ 15db Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus A
+ 15dc Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus B
+ 15de Raven/Raven2/FireFlight HD Audio Controller
+ 15df Family 17h (Models 10h-1fh) Platform Security Processor
+ 15e0 Raven USB 3.1
+ 15e1 Raven USB 3.1
+ 15e2 Raven/Raven2/FireFlight/Renoir Audio Processor
+ 15e3 Family 17h (Models 10h-1fh) HD Audio Controller
+ 15e4 Raven/Raven2/Renoir Sensor Fusion Hub
+ 15e5 Raven2 USB 3.1
+ 15e6 Raven/Raven2/Renoir Non-Sensor Fusion Hub KMDF driver
+ 15e8 Raven/Raven2 Device 24: Function 0
+ 15e9 Raven/Raven2 Device 24: Function 1
+ 15ea Raven/Raven2 Device 24: Function 2
+ 15eb Raven/Raven2 Device 24: Function 3
+ 15ec Raven/Raven2 Device 24: Function 4
+ 15ed Raven/Raven2 Device 24: Function 5
+ 15ee Raven/Raven2 Device 24: Function 6
+ 15ef Raven/Raven2 Device 24: Function 7
+ 15f0 FireFlight Device 24: Function 0
+ 15f1 FireFlight Device 24: Function 1
+ 15f2 FireFlight Device 24: Function 2
+ 15f3 FireFlight Device 24: Function 3
+ 15f4 FireFlight Device 24: Function 4
+ 15f5 FireFlight Device 24: Function 5
+ 15f6 FireFlight Device 24: Function 6
+ 15f7 FireFlight Device 24: Function 7
+ 15f8 FireFlight Root Complex
+ 15f9 FireFlight IOMMU
+ 15fa FireFlight PCIe Dummy Host Bridge
+ 15fb FireFlight PCIe GPP Bride 3:0
+ 15fc FireFlight PCIe Dummy Host Bridge
+ 15fd FireFlight Internal PCIe GPP Bridge 0 to Bus A
+ 15fe FireFlight Internal PCIe GPP Bridge 0 to Bus B
+ 15ff FireFlight Bus A; Device 0: Function 0: Internal GPU
1600 Family 15h Processor Function 0
1601 Family 15h Processor Function 1
1602 Family 15h Processor Function 2
1603 Family 15h Processor Function 3
1604 Family 15h Processor Function 4
1605 Family 15h Processor Function 5
+ 1606 Arden Security Processor
+ 1608 Arden Device 18h: Function 0
+ 1609 Arden Device 18h: Function 1
+ 160a Arden Device 18h: Function 2
+ 160b Arden Device 18h: Function 3
+ 160c Arden Device 18h: Function 4
+ 160d Arden Device 18h: Function 5
+ 160e Arden Device 18h: Function 6
+ 160f Arden Device 18h: Function 7
+ 1620 Anubis HT Configuration
+ 1621 Anubis Address Maps
+ 1622 Anubis DRAM Configuration
+ 1623 Anubis Miscellaneous Configuration
+ 1624 Anubis PM Configuration
+ 1625 Anubis NB Performance Monitor
+ 1626 Arden Root Complex
+ 1627 Arden IOMMU
+ 1628 Arden PCIe Dummy Host Bridge
+ 1629 Arden PCIe GPP Bridge
+ 162a Arden Internal PCIe GPP Bridge 0 to bus X
+ 162b Arden PCIe Non-Transparent Bridge
+ 1630 Renoir Root Complex
+ 1631 Renoir IOMMU
+ 1632 Renoir PCIe Dummy Host Bridge
+ 1633 Renoir PCIe GPP Bridge
+ 1634 Renoir PCIe GPP Bridge
+ 1635 Renoir Internal PCIe GPP Bridge to Bus
+ 1637 Renoir HD Audio Controller
+ 1639 Renoir USB 3.1
+ 1641 Renoir 10GbE Controller Port 0 (XGBE0/1)
+ 1642 Renoir WLAN
+ 1643 Renoir BT
+ 1644 Renoir I2S
1700 Family 12h/14h Processor Function 0
1701 Family 12h/14h Processor Function 1
1702 Family 12h/14h Processor Function 2
1703 Family 12h/14h Processor Function 3
1704 Family 12h/14h Processor Function 4
1705 Family 12h Processor Root Complex
+ 1706 Llano P2P Bridge to external GPU
1707 Family 12h Processor Root Port
1708 Family 12h Processor Root Port
1709 Family 12h Processor Root Port
@@ -4341,6 +4698,10 @@
1849 43d0 Fatal1ty X370 Professional Gaming
43ba X399 Series Chipset USB 3.1 xHCI Controller
43bb 300 Series Chipset USB 3.1 xHCI Controller
+ 43c6 400 Series Chipset PCIe Bridge
+ 43c7 400 Series Chipset PCIe Port
+ 43c8 400 Series Chipset SATA Controller
+ 43d5 400 Series Chipset USB 3.1 XHCI Controller
7006 AMD-751 [Irongate] System Controller
7007 AMD-751 [Irongate] AGP Bridge
700a AMD-IGR4 AGP Host to PCI Bridge
@@ -4413,6 +4774,7 @@
103c 1985 Pavilion 17-e163sg Notebook PC
7809 FCH USB OHCI Controller
103c 194e ProBook 455 G1 Notebook
+ 780a Kabini/Mullins SATA Raid/AHCI Mode (DotHill driver)
780b FCH SMBus Controller
103c 194e ProBook 455 G1 Notebook
103c 1985 Pavilion 17-e163sg Notebook PC
@@ -4790,7 +5152,9 @@
1028 028d PowerEdge T410 MGA G200eW WPCM450
1028 029c PowerEdge M710 MGA G200eW WPCM450
1028 02a4 PowerEdge T310 MGA G200eW WPCM450
+ 15d9 0605 X8SIL
15d9 0624 X9SCM-F Motherboard
+ 15d9 066b X9SRL-F
15d9 a811 H8DGU
0533 MGA G200EH
103c 3381 iLO4
@@ -5303,6 +5667,7 @@
122e PCI-X Local Bus Adapter
127b sx1000 System Bus Adapter
127c sx1000 I/O Controller
+ 128d Diva [GSP] Management Board
1290 Auxiliary Diva Serial Port
103c 1291 Diva SP2
1291 Auxiliary Diva Serial Port
@@ -5832,10 +6197,19 @@
104d Sony Corporation
8004 DTL-H2500 [Playstation development board]
8009 CXD1947Q i.LINK Controller
+ 800c DTL-H800 [PS1 sound development board]
8039 CXD3222 i.LINK Controller
+ 8047 PS2 TOOL MRP
8056 Rockwell HCF 56K modem
808a Memory Stick Controller
+ 80ff PS2 Performance Analyzer
+ 814a PS2 Performance Analyzer
+ 8183 ATHENS [PS3 prototype developer interface card]
+ 81b0 BM-1 [PSP TOOL Board Management Device]
+ 81c3 VO-4 [PSP TOOL Video Output Device]
81ce SxS Pro memory card
+ 81ff PS3 TOOL MRP
+ 820e CXD9208GP [PS3 PS2 emulation subsystem adapter]
# 2nd ID
905c SxS Pro memory card
# 2nd ID
@@ -8853,6 +9227,7 @@
0111 NV11 [GeForce2 MX200]
0112 NV11M [GeForce2 Go]
0113 NV11GL [Quadro2 MXR/EX/Go]
+ 1028 00e5 Quadro2 Go
0140 NV43 [GeForce 6600 GT]
1458 3125 GV-NX66T128D
1458 3126 GV-NX66T256DE
@@ -8954,7 +9329,6 @@
018b NV18GL [Quadro4 380 XGL]
018c NV18GL [Quadro NVS 50 PCI]
018d NV18M [GeForce4 448 Go]
- 018f NV18
0190 G80 [GeForce 8800 GTS / 8800 GTX]
0191 G80 [GeForce 8800 GTX]
0192 G80 [GeForce 8800 GTS]
@@ -9727,45 +10101,45 @@
0638 G94GL [Quadro FX 1800]
063a G94GLM [Quadro FX 2700M]
063f G94 [GeForce 9600 GE]
- 0640 G96 [GeForce 9500 GT]
- 0641 G96 [GeForce 9400 GT]
+ 0640 G96C [GeForce 9500 GT]
+ 0641 G96C [GeForce 9400 GT]
1682 4009 PV-T94G-ZAFG
0642 G96 [D9M-10]
0643 G96 [GeForce 9500 GT]
0644 G96 [GeForce 9500 GS]
174b 9600 Geforce 9500GS 512M DDR2 V/D/HDMI
- 0645 G96 [GeForce 9500 GS]
- 0646 G96 [GeForce GT 120]
- 0647 G96M [GeForce 9600M GT]
- 0648 G96M [GeForce 9600M GS]
- 0649 G96M [GeForce 9600M GT]
+ 0645 G96C [GeForce 9500 GS]
+ 0646 G96C [GeForce GT 120]
+ 0647 G96CM [GeForce 9600M GT]
+ 0648 G96CM [GeForce 9600M GS]
+ 0649 G96CM [GeForce 9600M GT]
1043 202d GeForce GT 220M
064a G96M [GeForce 9700M GT]
064b G96M [GeForce 9500M G]
- 064c G96M [GeForce 9650M GT]
- 064d G96 [GeForce 9600 GT]
- 064e G96 [GeForce 9600 GT / 9800 GT]
- 0651 G96M [GeForce G 110M]
- 0652 G96M [GeForce GT 130M]
+ 064c G96CM [GeForce 9650M GT]
+ 064e G96C [GeForce 9600 GSO / 9800 GT]
+ 0651 G96CM [GeForce G 110M]
+ 0652 G96CM [GeForce GT 130M]
152d 0850 GeForce GT 240M LE
- 0653 G96M [GeForce GT 120M]
- 0654 G96M [GeForce GT 220M]
+ 0653 G96CM [GeForce GT 120M]
+ 0654 G96CM [GeForce GT 220M]
1043 14a2 GeForce GT 320M
1043 14d2 GeForce GT 320M
- 0655 G96 [GeForce GT 120]
- 0656 G96 [GeForce 9650 S]
+ 0655 G96 [GeForce GT 120 Mac Edition]
+ 0656 G96 [GeForce GT 120 Mac Edition]
0658 G96GL [Quadro FX 380]
- 0659 G96GL [Quadro FX 580]
+ 0659 G96CGL [Quadro FX 580]
065a G96GLM [Quadro FX 1700M]
- 065b G96 [GeForce 9400 GT]
+ 065b G96C [GeForce 9400 GT]
065c G96GLM [Quadro FX 770M]
065d G96 [GeForce 9500 GA / 9600 GT / GTS 250]
- 065f G96 [GeForce G210]
+ 065f G96C [GeForce G210]
06c0 GF100 [GeForce GTX 480]
06c4 GF100 [GeForce GTX 465]
06ca GF100M [GeForce GTX 480M]
06cb GF100 [GeForce GTX 480]
06cd GF100 [GeForce GTX 470]
+ 06d0 GF100GL
06d1 GF100GL [Tesla C2050 / C2070]
10de 0771 Tesla C2050
10de 0772 Tesla C2070
@@ -10546,6 +10920,8 @@
10f0 GP104 High Definition Audio Controller
10f1 GP106 High Definition Audio Controller
10f7 TU102 High Definition Audio Controller
+ 10f9 TU106 High Definition Audio Controller
+ 1043 8673 TURBO-RTX2070-8G
1140 GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M]
1019 0799 GeForce 820M
1019 999f GeForce GT 720M
@@ -11166,8 +11542,13 @@
17f1 GM200GL [Quadro M6000 24GB]
17fd GM200GL [Tesla M40]
1ad6 TU102 USB 3.1 Controller
+ 1ad7 TU102 UCSI Controller
+ 1ada TU106 USB 3.1 Host Controller
+ 1043 8673 TURBO-RTX2070-8G
+ 1adb TU106 USB Type-C Port Policy Controller
+ 1043 8673 TURBO-RTX2070-8G
1b00 GP102 [TITAN X]
- 1b01 GP102
+ 1b01 GP102 [GeForce GTX 1080 Ti 10GB]
1b02 GP102 [TITAN Xp]
1b04 GP102
1b06 GP102 [GeForce GTX 1080 Ti]
@@ -11189,6 +11570,8 @@
1462 11e9 GeForce GTX 1070 Max-Q
1558 9501 GeForce GTX 1070 Max-Q
1ba2 GP104M [GeForce GTX 1070 Mobile]
+ 1ba9 GP104M
+ 1baa GP104M
1bad GP104 [GeForce GTX 1070 Engineering Sample]
1bb0 GP104GL [Quadro P5000]
1bb1 GP104GL [Quadro P4000]
@@ -11221,6 +11604,9 @@
17aa 39b9 GeForce GTX 1060 Max-Q 3GB
1c21 GP106M [GeForce GTX 1050 Ti Mobile]
1c22 GP106M [GeForce GTX 1050 Mobile]
+ 1c23 GP106M [GeForce GTX 1060 Mobile Rev. 2]
+ 1414 0020 GTX 1060 Mobile
+ 1c2d GP106M
1c30 GP106GL [Quadro P2000]
1c35 GP106
1c60 GP106BM [GeForce GTX 1060 Mobile 6GB]
@@ -11256,11 +11642,16 @@
1ccd GP107BM [GeForce GTX 1050 Mobile]
1d01 GP108 [GeForce GT 1030]
1d10 GP108M [GeForce MX150]
+ 17aa 225e ThinkPad T480
+ 1d11 GP108M [GeForce MX230]
1d12 GP108M [GeForce MX150]
1d72 1701 Mi Notebook Pro [GeForce MX150]
+ 1d13 GP108M [GeForce MX250]
1d33 GP108GLM [Quadro P500 Mobile]
+ 1d52 GP108BM [GeForce MX250]
1d81 GV100 [TITAN V]
1db1 GV100GL [Tesla V100 SXM2 16GB]
+ 1db2 GV100GL [Tesla V100-DGXS-16GB]
1db3 GV100GL [Tesla V100 FHHL 16GB]
1db4 GV100GL [Tesla V100 PCIe 16GB]
1db5 GV100GL [Tesla V100 SXM2 32GB]
@@ -11268,21 +11659,48 @@
1db7 GV100GL [Tesla V100 DGXS 32GB]
1dba GV100GL [Quadro GV100]
10de 12eb TITAN V CEO Edition
- 1e02 TU102
+ 1e02 TU102 [TITAN RTX]
1e04 TU102 [GeForce RTX 2080 Ti]
1e07 TU102 [GeForce RTX 2080 Ti Rev. A]
1462 3715 RTX 2080 Ti GAMING X TRIO
- 1e30 TU102GL [Quadro RTX 6000]
- 1e3c TU102GL [Quadro RTX 6000]
+ 1e2d TU102B
+ 1e2e TU102B
+ 1e30 TU102GL [Quadro RTX 6000/8000]
+ 10de 129e Quadro RTX 8000
+ 10de 12ba Quadro RTX 6000
+ 1e38 TU102GL
+ 1e3c TU102GL
1e3d TU102GL
+ 1e3e TU102GL
1e82 TU104 [GeForce RTX 2080]
1e87 TU104 [GeForce RTX 2080 Rev. A]
- 1eab TU104M [GeForce RTX 2080 Mobile]
+ 1e90 TU104M [GeForce RTX 2080 Mobile]
+ 1eab TU104M
1eae TU104M
1eb0 TU104GL [Quadro RTX 5000]
+ 1eb1 TU104GL [Quadro RTX 4000]
1eb8 TU104GL [Tesla T4]
+ 1ed0 TU104M [GeForce RTX 2080 Mobile]
1f02 TU106 [GeForce RTX 2070]
+ 1043 8673 TURBO RTX 2070
+ 1f04 TU106
1f07 TU106 [GeForce RTX 2070 Rev. A]
+ 1f08 TU106 [GeForce RTX 2060 Rev. A]
+ 1f10 TU106M [GeForce RTX 2070 Mobile]
+ 1f11 TU106M [GeForce RTX 2060 Mobile]
+ 1f2e TU106M
+ 1f50 TU106M [GeForce RTX 2070 Mobile]
+ 1f51 TU106M [GeForce RTX 2060 Mobile]
+ 1f82 TU107
+ 1f92 TU107M [GeForce GTX 1650 Mobile]
+ 1fbf TU107GL
+ 2182 TU116 [GeForce GTX 1660 Ti]
+ 2183 TU116
+ 2184 TU116 [GeForce GTX 1660]
+ 2191 TU116M [GeForce GTX 1660 Mobile]
+ 21ae TU116GL
+ 21bf TU116GL
+ 21d1 TU116M [GeForce GTX 1660 Mobile]
10df Emulex Corporation
0720 OneConnect NIC (Skyhawk)
103c 1934 FlexFabric 20Gb 2-port 650M Adapter
@@ -11465,11 +11883,13 @@
103c 1985 Pavilion 17-e163sg Notebook PC
17aa 3832 Yoga 520
522a RTS522A PCI Express Card Reader
+ 103c 8079 EliteBook 840 G3
5249 RTS5249 PCI Express Card Reader
103c 1909 ZBook 15
524a RTS524A PCI Express Card Reader
5250 RTS5250 PCI Express Card Reader
525a RTS525A PCI Express Card Reader
+ 1028 06dc Latitude E7470
1028 06e4 XPS 15 9550
17aa 224f ThinkPad X1 Carbon 5th Gen
5286 RTS5286 PCI Express Card Reader
@@ -11660,6 +12080,7 @@
ebf0 SED Systems Modulator/Demodulator
ebf1 SED Systems Audio Interface Card
ebf2 SED Systems Common PCI Interface
+ ebf3 SED Systems PCIe-AXI Bridge
10ef Racore Computer Products, Inc.
8154 M815x Token Ring Adapter
10f0 Peritek Corporation
@@ -12770,6 +13191,7 @@
112f Dalsa Inc.
0000 MVC IC-PCI
0001 MVC IM-PCI Video frame grabber/processor
+ 0004 PCDig Digital Image Capture
0008 PC-CamLink PCI framegrabber
1130 Computervision
1131 Philips Semiconductors
@@ -13150,6 +13572,15 @@
1137 012e VIC 1227 PCIe Ethernet NIC
1137 0137 VIC 1380 Mezzanine Ethernet NIC
1137 014d VIC 1385 PCIe Ethernet NIC
+ 1137 015d VIC 1387 MLOM Ethernet NIC
+ 1137 0215 VIC 1440 Mezzanine Ethernet NIC
+ 1137 0216 VIC 1480 MLOM Ethernet NIC
+ 1137 0217 VIC 1455 PCIe Ethernet NIC
+ 1137 0218 VIC 1457 MLOM Ethernet NIC
+ 1137 0219 VIC 1485 PCIe Ethernet NIC
+ 1137 021a VIC 1487 MLOM Ethernet NIC
+ 1137 024a VIC 1495 PCIe Ethernet NIC
+ 1137 024b VIC 1497 MLOM Ethernet NIC
0044 VIC Ethernet NIC Dynamic
1137 0047 VIC P81E PCIe Ethernet NIC Dynamic
1137 0048 VIC M81KR Mezzanine Ethernet NIC Dynamic
@@ -13571,6 +14002,13 @@
0102 Extended IDE Controller
0103 EX-IDE Type-B
010f NVMe Controller
+ 0110 NVMe SSD Controller Cx5
+ 1028 1ffb Express Flash NVMe 960G (RI) U.2 (CD5)
+ 1028 1ffc Express Flash NVMe 1.92T (RI) U.2 (CD5)
+ 1028 1ffd Express Flash NVMe 3.84T (RI) U.2 (CD5)
+ 1028 1ffe Express Flash NVMe 7.68T (RI) U.2 (CD5)
+ 1d49 4039 Thinksystem U.2 CM5 NVMe SSD
+ 1d49 403a Thinksystem AIC CM5 NVMe SSD
0115 XG4 NVMe SSD Controller
0404 DVD Decoder card
0406 Tecra Video Capture device
@@ -13673,7 +14111,7 @@
14ef 0220 PCD-RP-220S
17aa 201c ThinkPad X60/X60s
17aa 20c4 ThinkPad T61/R61
- 17aa 20c6 ThinkPad R61
+ 17aa 20c6 ThinkPad R61/T400
0477 RL5c477
0478 RL5c478
1014 0184 ThinkPad A30p
@@ -13708,7 +14146,7 @@
1043 1237 A6J-Q008
1043 1967 V6800V
144d c018 X20 IV
- 17aa 20ca ThinkPad T61
+ 17aa 20ca ThinkPad T61/T400
0811 R5C811
0822 R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter
1014 0556 ThinkPad X40 / X41 / X60s / Z60t
@@ -13730,7 +14168,7 @@
144d c018 X20 IV
17aa 201d ThinkPad X60/X60s
17aa 20c7 ThinkPad T61
- 17aa 20c8 ThinkPad W500
+ 17aa 20c8 ThinkPad T400/W500
0832 R5C832 IEEE 1394 Controller
1025 0121 Aspire 5920G
1028 01d7 XPS M1210
@@ -13767,6 +14205,7 @@
1043 1967 V6800V
1180 0852 Pavilion 2410us
1324 10cf P7120
+ 17aa 20cb ThinkPad T400
e230 R5U2xx (R5U230 / R5U231 / R5U241) [Memory Stick Host Controller]
e476 CardBus bridge
1028 040a Latitude E6410
@@ -13774,6 +14213,7 @@
e822 MMC/SD Host Controller
1028 040a Latitude E6410
1028 040b Latitude E6510
+ 17aa 21cf ThinkPad T520
e823 PCIe SDXC/MMC Host Controller
17aa 21cf ThinkPad T520
e832 R5C832 PCIe IEEE 1394 Controller
@@ -14133,6 +14573,7 @@
7820 MV78200 [Discovery Innovation] ARM SoC
7823 MV78230 [Armada XP] ARM SoC
7846 88F6820 [Armada 385] ARM SoC
+ d40f Bobcat3 Ethernet Switch
f003 GT-64010 Primary Image Piranha Image Generator
11ac Canon Information Systems Research Aust.
11ad Lite-On Communications Inc
@@ -15426,8 +15867,10 @@
1000 BSP15
12d6 Analogic Corp
12d7 Biotronic SRL
+# acquired by Diodes Inc.
12d8 Pericom Semiconductor
01a7 7C21P100 2-port PCI-X to PCI-X Bridge
+ 2304 PI7C9X2G304 EL/SL PCIe2 3-Port/4-Lane Packet Switch
2608 PI7C9X2G608GP PCIe2 6-Port/8-Lane Packet Switch
400a PI7C9X442SL PCI Express Bridge Port
400e PI7C9X442SL USB OHCI Controller
@@ -16257,6 +16700,7 @@
1043 8428 Virtuoso 100 (Xonar Xense)
1043 8467 CMI8786 (Xonar DG)
1043 8521 CMI8786 (Xonar DGX)
+ 1043 8522 Xonar DSX
1043 85f4 Virtuoso 100 (Xonar Essence STX II)
13f6 8782 PCI 2.0 HD Audio
13f6 ffff CMI8787-HG2PCI
@@ -16288,16 +16732,19 @@
1612 0004 PCI-1612 4-port RS-232/422/485
1603 PCI-1603 2-port isolated RS-232/current loop
1604 PCI-1604 2-port RS-232
+ 1680 PCI-1680 Rev.A1 2-port CAN-bus with isolation protection
16ff PCI-16xx series PCI multiport serial board (function 1: RX/TX steering CPLD)
1601 0000 PCI-1601 2-port unisolated RS-422/485 PCI communications card
1602 0000 PCI-1602 2-port isolated RS-422/485
1612 0000 PCI-1612 4-port RS-232/422/485
1711 PCI-1711 16-channel data acquisition card 12-bit, 100kS/s
+ 1713 PCI-1713 32-channel isolated analog input card
1733 PCI-1733 32-channel isolated digital input card
1734 PCI-1734 32-channel isolated digital output card
1752 PCI-1752 64-channel Isolated Digital Output Card
1754 PCI-1754 64-channel Isolated Digital Input Card
1756 PCI-1756 64-ch Isolated Digital I/O PCI Card
+ a004 PCI-1612 4-port RS-232/422/485
# FPGA bridge to two SJA1000
c302 MIOe-3680 2-Port CAN-Bus MIOe Module with Isolation Protection
13ff Silicon Spice Inc
@@ -17105,6 +17552,7 @@
6087 T6225-6087 Unified Wire Ethernet Controller
6088 T62100-6088 Unified Wire Ethernet Controller
6089 T62100-6089 Unified Wire Ethernet Controller
+ 608a T62100-608a Unified Wire Ethernet Controller
6401 T6225-CR Unified Wire Ethernet Controller
6402 T6225-SO-CR Unified Wire Ethernet Controller
6403 T6425-CR Unified Wire Ethernet Controller
@@ -17128,6 +17576,7 @@
6487 T6225-6087 Unified Wire Ethernet Controller
6488 T62100-6088 Unified Wire Ethernet Controller
6489 T62100-6089 Unified Wire Ethernet Controller
+ 648a T62100-608a Unified Wire Ethernet Controller
6501 T6225-CR Unified Wire Storage Controller
6502 T6225-SO-CR Unified Wire Storage Controller
6503 T6425-CR Unified Wire Storage Controller
@@ -17151,6 +17600,7 @@
6587 T6225-6087 Unified Wire Storage Controller
6588 T62100-6088 Unified Wire Storage Controller
6589 T62100-6089 Unified Wire Storage Controller
+ 658a T62100-608a Unified Wire Storage Controller
6601 T6225-CR Unified Wire Storage Controller
6602 T6225-SO-CR Unified Wire Storage Controller
6603 T6425-CR Unified Wire Storage Controller
@@ -17174,6 +17624,7 @@
6687 T6225-6087 Unified Wire Storage Controller
6688 T62100-6088 Unified Wire Storage Controller
6689 T62100-6089 Unified Wire Storage Controller
+ 668a T62100-608a Unified Wire Storage Controller
6801 T6225-CR Unified Wire Ethernet Controller [VF]
6802 T6225-SO-CR Unified Wire Ethernet Controller [VF]
6803 T6425-CR Unified Wire Ethernet Controller [VF]
@@ -17197,6 +17648,7 @@
6887 T6225-6087 Unified Wire Ethernet Controller [VF]
6888 T62100-6088 Unified Wire Ethernet Controller [VF]
6889 T62100-6089 Unified Wire Ethernet Controller [VF]
+ 688a T62100-608a Unified Wire Ethernet Controller [VF]
a000 PE10K Unified Wire Ethernet Controller
1426 Storage Technology Corp.
1427 Better On-Line Solutions
@@ -17271,6 +17723,7 @@
a802 NVMe SSD Controller SM951/PM951
a804 NVMe SSD Controller SM961/PM961
a808 NVMe SSD Controller SM981/PM981
+ 1d49 403b Thinksystem U.2 PM983 NVMe SSD
a820 NVMe SSD Controller 171X
1028 1f95 Express Flash NVMe XS1715 SSD 400GB
1028 1f96 Express Flash NVMe XS1715 SSD 800GB
@@ -17530,6 +17983,9 @@
e010 VScom 100HV2 1 port serial adaptor
e020 VScom 200HV2 2 port serial adaptor
14d3 CIRTECH (UK) Ltd
+ 0002 DTL-T14000 Rev. 1 [PS2 TOOL CD/DVD Emulator]
+ 0003 DTL-T14000 Rev. 2 [PS2 TOOL CD/DVD Emulator]
+ 0004 DTL-T14000 Rev. 3 [PS2 TOOL CD/DVD Emulator]
14d4 Panacom Technology Corp
14d5 Nitsuko Corporation
14d6 Accusys Inc
@@ -17987,6 +18443,7 @@
1590 0211 Ethernet 25Gb 2-port 631FLR-SFP28 Adapter
16d8 BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller
1028 1feb NetXtreme-E 10Gb SFP+ Adapter
+ 14e4 4163 BCM957416M4163C OCP 2x10GBT Type1 wRoCE
1590 020c Ethernet 10Gb 2-port 535T Adapter
1590 0212 Ethernet 10Gb 2-port 535FLR-T Adapter
16d9 BCM57417 NetXtreme-E 10GBASE-T RDMA Ethernet Controller
@@ -18298,10 +18755,12 @@
b842 BCM56842 Trident 10GE Switch Controller
# Trident2
b850 Broadcom BCM56850 Switch ASIC
+ b880 BCM56880 Switch ASIC
# Tomahawk
b960 Broadcom BCM56960 Switch ASIC
d802 BCM58802 Stingray 50Gb Ethernet SoC
14e4 8021 Stingray Dual-Port 25Gb Ethernet PCIe SmartNIC w16GB DRAM (Part No BCM958802A8046C)
+ 14e4 8023 PS410T-H04 NetXtreme-S 4x10G 10GBaseT PCIe SmartNIC
14e4 8024 Stingray Dual-Port 25Gb Ethernet PCIe SmartNIC w4GB DRAM (Part No BCM958802A8044C)
14e4 8028 Stingray Dual-Port 25Gb Ethernet PCIe SmartNIC w8GB DRAM (Part No BCM958802A8048C)
d804 BCM58804 Stingray 100Gb Ethernet SoC
@@ -18962,6 +19421,8 @@
020f MT28908A0 Family [ConnectX-6 Flash Recovery]
0210 MT28908A0 Family [ConnectX-6 Secure Flash Recovery]
0211 MT416842 Family [BlueField SoC Flash Recovery]
+ 0212 MT2892 Family [ConnectX-6 Dx Flash Recovery]
+ 0213 MT2892 Family [ConnectX-6 Dx Secure Flash Recovery]
024e MT53100 [Spectrum-2, Flash recovery mode]
024f MT53100 [Spectrum-2, Secure Flash recovery mode]
0262 MT27710 [ConnectX-4 Lx Programmable] EN
@@ -19043,8 +19504,8 @@
101a MT28800 Family [ConnectX-5 Ex Virtual Function]
101b MT28908 Family [ConnectX-6]
101c MT28908 Family [ConnectX-6 Virtual Function]
- 101d MT28841
- 101e MT28850
+ 101d MT2892 Family [ConnectX-6 Dx]
+ 101e ConnectX Family mlx5Gen Virtual Function
101f MT28851
1020 MT28860
1021 MT28861
@@ -19059,6 +19520,7 @@
5a46 MT23108 PCI Bridge
5e8c MT24204 [InfiniHost III Lx HCA]
5e8d MT25204 [InfiniHost III Lx HCA Flash Recovery]
+ 6001 NVMe SNAP Controller
6274 MT25204 [InfiniHost III Lx HCA]
6278 MT25208 InfiniHost III Ex (Tavor compatibility mode)
6279 MT25208 [InfiniHost III Ex HCA Flash Recovery]
@@ -19132,6 +19594,8 @@
15b7 Sandisk Corp
2001 Skyhawk Series NVME SSD
5001 WD Black NVMe SSD
+ 5002 WD Black 2018/PC SN720 NVMe SSD
+ 5003 WD Black 2018/PC SN520 NVMe SSD
15b8 ADDI-DATA GmbH
1001 APCI1516 SP controller (16 digi outputs)
1003 APCI1032 SP controller (32 digi inputs w/ opto coupler)
@@ -19701,6 +20165,9 @@
16b8 Sonnet Technologies, Inc.
16be Creatix Polymedia GmbH
16c3 Synopsys, Inc.
+ abcd DWC_usb3
+ abce DWC_usb3
+ abcf DWC_usb31
edda EPMockUp
16c6 Micrel-Kendin
8695 Centaur KS8695 ARM processor
@@ -19815,6 +20282,10 @@
7042 AP482 Counter Timer Module with TTL Level Input/Output
7043 AP483 Counter Timer Module with TTL Level and RS422 Input/Output
7044 AP484 Counter Timer Module with RS422 Input/Output
+ 7051 APA7-501 Reconfigurable Artix-7 52,160 Cell FPGA module 48 TTL channels
+ 7052 APA7-502 Reconfigurable Artix-7 52,160 Cell FPGA module 24 RS485 channels
+ 7053 APA7-503 Reconfigurable Artix-7 52,160 Cell FPGA module 24 TTL & 12 RS485 channels
+ 7054 APA7-504 Reconfigurable Artix-7 52,160 Cell FPGA module 24 LVDS channels
16da Advantech Co., Ltd.
0011 INES GPIB-PCI
16df PIKA Technologies Inc.
@@ -19891,10 +20362,10 @@
0216 PCT-7424E (F0) PC card with standard counters
0217 PCT-7424E (F1) PC card with standard counters
0303 PCD-7006C Digital Input & Output PCI Card
+ ff00 CTU CAN FD PCIe Card
1761 Pickering Interfaces Ltd
1771 InnoVISION Multimedia Ltd.
-# nee SBS Technologies
-1775 GE Intelligent Platforms
+1775 General Electric
177d Cavium, Inc.
0001 Nitrox XL N1
0003 Nitrox XL N1 Lite
@@ -20004,13 +20475,28 @@
0004 CAMAC Controller
0005 PROFIBUS
0006 AMCC HOTlink
+ 0007 LVD Cable Bus
+ 0008 100MHz, 64bit Sequence Generator based on VirtexII
+ 0009 double 14bit-ADC
+ 000a SIS1100 with N110 TDC
+ 000b double 14bit-ADC with memory
000d Synchronisation Slave
000e SIS1100-eCMC
000f TDC (GPX)
0010 PCIe Counter Timer
0011 SIS1100-e single link
0012 SIS1100-e quad link
+ 0013 4x2.5GHz SFP to 4 lane PCIe bridge
+ 0014 SIS1100 with GPX piggy back
0015 SIS8100 [Gigabit link, MicroTCA]
+ 0016 SIS1100e with 4 lanes
+ 0017 Quad 14bit, 50MHz ADC with 2.5GHz SFP
+ 0018 SIS8300 4-lane PCI Express, Micro TCA for Physics ADC
+ 0019 SIS SIS8300-Lx MTCA.4 Digitizer
+ 001a 100MHz, 64bit Sequence Generator based on VirtexII
+ 001c Quad 16bit, 150MHz ADC with 2.5GHz SFP
+ 0030 100MHz, 64bit Sequence Generator based on Spartan6
+ 0031 200MHz 64bit Sequence Generator based on Spartan7
# nee Techwell, Inc.
1797 Intersil Techwell
5864 TW5864 multimedia video controller
@@ -20183,6 +20669,8 @@
1915 Arria10 PCIe MainRef Design [DNPCIe_80G_A10_LL]
1916 VirtexUS PCIe Accelerator Board [DNVUF2_HPC_PCIe]
1917 UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VU_LL]
+ 1918 VirtexUS+ ASIC Emulation Board [DNVUPF4A]
+ 1919 UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VUP_HBM_LL]
1a00 Virtex6 PCIe DMA Netlist Design
1a01 Virtex6 PCIe Darklite Design [DNPCIe_HXT_10G_LL]
1a02 Virtex7 PCIe DMA Netlist Design
@@ -20195,6 +20683,8 @@
1a0a VirtexUS PCIe Darklite Design [DNVUF2_HPC_PCIe]
1a0b UltrascalePlus PCIe Darklite Design [DNPCIe_400G_VU_LL]
1a0c KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL]
+ 1a0d KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL_2QSFP]
+ 1a0e UltrascalePlus PCIe Darklite Design [DNPCIe_400G_VUP_HBM_LL]
17e4 Sectra AB
0001 KK671 Cardbus encryption board
0002 KK672 Cardbus encryption board
@@ -20211,6 +20701,9 @@
17f2 Albatron Corp.
17f3 RDC Semiconductor, Inc.
1010 R1010 IDE Controller
+ 1011 R1011 IDE Controller
+ 1012 R1012 IDE Controller
+ 1031 PCI/PCI-X to PCI-E Bridge
2012 M2012/R3308 VGA-compatible graphics adapter
6020 R6020 North Bridge
6021 R6021 Host Bridge
@@ -20517,6 +21010,7 @@
0175 NT20E3-2-PTP Network Adapter 2x10Gb
0185 NT40A01 Network Adapter
01a5 NT200A01 Network Adapter
+ 01c5 NT200A02 Network Adapter
18f6 NextIO
1000 [Nexsis] Switch Virtual P2P PCIe Bridge
1001 [Texsis] Switch Virtual P2P PCIe Bridge
@@ -20688,7 +21182,13 @@
1924 801d x2522-R1 2000 Series 10/25G Adapter
1924 801e x2542-R1 2000 Series 40/100G Adapter
1924 8022 XtremeScale X2522 10G Network Adapter
+ 1924 8024 XtremeScale X2562 OCP 3.0 Dual Port SFP28
+ 1924 8027 XtremeScale X2541 PCIe Single Port QSFP28
1924 8028 XtremeScale X2522-25G Network Adapter
+ 1924 802a XtremeScale X2542 PCIe Dual Port QSFP28
+ 1924 802b XtremeScale X2552 OCP 2.0 Dual Port SFP28
+ 1924 802c XtremeScale X2522-25G PCIe Dual Port SFP28
+ 1924 802d XtremeScale X2562 OCP 3.0 Dual Port SFP28
1803 SFC9020 10G Ethernet Controller (Virtual Function)
1813 SFL9021 10GBASE-T Ethernet Controller (Virtual Function)
1903 SFC9120 10G Ethernet Controller (Virtual Function)
@@ -20874,6 +21374,7 @@
2048 Attansic L2 Fast Ethernet
2060 AR8152 v1.1 Fast Ethernet
2062 AR8152 v2.0 Fast Ethernet
+ 1043 8468 Eee PC 1015PX
# E2200, E2201, E2205
e091 Killer E220x Gigabit Ethernet Controller
e0a1 Killer E2400 Gigabit Ethernet Controller
@@ -20928,6 +21429,8 @@
1600 OX16C954 HOST-A
16ff OX16C954 HOST-B
1987 Phison Electronics Corporation
+ 5007 E7 NVMe Controller
+ 5012 E12 NVMe Controller
1989 Montilio Inc.
0001 RapidFile Bridge
8001 RapidFile
@@ -21009,8 +21512,12 @@
19e5 3033 NVMe SSD ES3600C V3 1200GB HHHL AIC
19e5 3034 NVMe SSD ES3600C V3 1600GB HHHL AIC
19e5 3036 NVMe SSD ES3600C V3 3200GB HHHL AIC
- 0200 Hi1822 Family (2*25GE)
- 0201 Hi1822 Family (2*100GE)
+ 0200 Hi1822 Family (2*100GE)
+ 0202 Hi1822 Family (2*32G FC)
+ 0203 Hi1822 Family (2*16G FC)
+ 0205 Hi1822 Family (2*100GE)
+ 0210 Hi1822 Family (4*25GE)
+ 0212 Hi1822 Family (2*8G FC)
1710 iBMA Virtual Network Adapter
1711 Hi1710 [iBMC Intelligent Management system chip w/VGA support]
1822 Hi1822 Family (4*25GE)
@@ -21057,6 +21564,8 @@
1a03 ASPEED Technology, Inc.
1150 AST1150 PCI-to-PCI Bridge
2000 ASPEED Graphics Family
+ 15d9 0832 X10SRL-F
+1a05 deltaww
1a07 Kvaser AB
0006 CAN interface PC104+ HS/HS
0007 CAN interface PCIcanx II HS or HS/HS
@@ -21315,6 +21824,7 @@
001f DSU
0020 ADQ14
0023 ADQ7
+ 0026 ADQ8
2014 TX320
2019 S6000
# now owned by HGST (a Western Digital subsidiary)
@@ -21352,6 +21862,7 @@
1028 1fd6 BOSS-S1 Adapter
1028 1fdf BOSS-S1 Modular
1028 1fe2 BOSS-S1 Adapter
+ 1028 2010 BOSS-S2 Adapter
1d49 0300 ThinkSystem M.2 with Mirroring Enablement Kit
9235 88SE9235 PCIe 2.0 x2 4-port SATA 6 Gb/s Controller
9445 88SE9445 PCIe 2.0 x4 4-Port SAS/SATA 6 Gbps RAID Controller
@@ -21475,7 +21986,8 @@
0001 82C101
1c28 Lite-On IT Corp. / Plextor
0122 M6e PCI Express SSD [Marvell 88SS9183]
-1c2c Fiberblaze
+# previously Fiberblaze
+1c2c Silicom Denmark
000a Capture
000f SmartNIC
00a0 FBC4G Capture 4x1Gb
@@ -21486,9 +21998,15 @@
00a5 FBC2XLG Capture 2x40Gb
00a6 FBC1CG Capture 1x100Gb
00a9 FBC2XGHH Capture 2x10Gb
- 00ad FBC2CGG3HL Capture 2x200Gb
+ 00ad FBC2CGG3HL Capture 2x100Gb [Padua]
00af Capture slave device
- a001 FBC2CGG3 Capture 2x200Gb
+ 00e0 PacketMover 2x100Gb [Savona]
+ 00e1 PacketMover 2x100Gb [Tivoli]
+ a001 FBC2CGG3 Capture 2x100Gb [Mango]
+ a00e FB2CG Capture 2x100Gb [Savona]
+ a00f FB2CG Capture 2x40Gb [Savona]
+ a011 FB2CG Capture 2x25Gb [Savona]
+ a012 FB2CG Capture 8x10Gb [Savona]
# Used on V120 VME Crate Controller
1c32 Highland Technology, Inc.
1c33 Daktronics, Inc
@@ -21510,6 +22028,7 @@
1c58 8823 Ultrastar Memory (ME200)
1c5c SK hynix
1283 PC300 NVMe Solid State Drive
+ 1504 SC300 512GB M.2 2280 SATA Solid State Drive
1c5f Beijing Memblaze Technology Co. Ltd.
0540 PBlaze4 NVMe SSD
# http://www.nicevt.ru/ (in Russian)
@@ -21524,6 +22043,8 @@
0001 Hunter PCI Express
1c8c Mobiveil, Inc.
1cb1 Collion UG & Co.KG
+1cb5 Focusrite Audio Engineering Ltd
+ 0002 Clarett
1cb8 Dawning Information Industry Co., Ltd.
1cc5 Embedded Intelligence, Inc.
0100 CAN-PCIe-02
@@ -21561,6 +22082,7 @@
1d0f Amazon.com, Inc.
cd01 NVMe SSD Controller
ec20 Elastic Network Adapter (ENA)
+ efa0 Elastic Fabric Adapter (EFA)
1d17 Zhaoxin
070f ZX-100 PCI Express Root Port
0710 ZX-100/ZX-200 PCI Express Root Port
@@ -21673,8 +22195,10 @@
1d7c Aerotech, Inc.
1d82 NETINT Technologies Inc.
1d87 Fuzhou Rockchip Electronics Co., Ltd
+ 0100 RK3399 PCI Express Root Port
+ 1808 RK1808 Neural Network Processor Card
1d8f Enyx
-1d94 Chengdu Higon IC Design Co.Ltd
+1d94 Chengdu Haiguang IC Design Co., Ltd.
1450 Root Complex
1451 I/O Memory Management Unit
1452 PCIe Dummy Host Bridge
@@ -21707,6 +22231,9 @@
1d95 Graphcore Ltd
0001 Colossus GC2 [C2]
0002 Colossus GC1 [S1]
+1d9b Facebook, Inc.
+ 0010 Networking DOM Engine
+ 0011 IO Bridge
1da1 Teko Telecom S.r.l.
1da2 Sapphire Technology Limited
1dbb NGD Systems, Inc.
@@ -21721,20 +22248,42 @@
1000 IO Memory Controller
2000 NoLoad Hardware Development Kit
1def Ampere Computing, LLC
- e005 Skylark PCI Express Root Port 0 [eMAG]
- e006 Skylark PCI Express Root Port 1 [eMAG]
- e007 Skylark PCI Express Root Port 2 [eMAG]
- e008 Skylark PCI Express Root Port 3 [eMAG]
- e009 Skylark PCI Express Root Port 4 [eMAG]
- e00a Skylark PCI Express Root Port 5 [eMAG]
- e00b Skylark PCI Express Root Port 6 [eMAG]
- e00c Skylark PCI Express Root Port 7 [eMAG]
+ e005 eMAG PCI Express Root Port 0
+ e006 eMAG PCI Express Root Port 1
+ e007 eMAG PCI Express Root Port 2
+ e008 eMAG PCI Express Root Port 3
+ e009 eMAG PCI Express Root Port 4
+ e00a eMAG PCI Express Root Port 5
+ e00b eMAG PCI Express Root Port 6
+ e00c eMAG PCI Express Root Port 7
+1df3 Ethernity Networks
+ 0201 ACE-NIC40 Programmable Network Accelerator
+ 1df3 0001 ENA1040
+ 1df3 0002 ENA1044
+ 1df3 0003 ENA1044S
+ 0202 ACE-NIC50 Programmable Network Accelerator
+ 1df3 0001 ENA2050F
+ 1df3 0002 ENA2050FS
+ 0203 ACE-NIC100 Programmable Network Accelerator
+ 1df3 0001 ENA2080F
+ 1df3 0002 ENA2080FS
+ 1df3 0003 ENA2100F
+ 0204 ACE-NIC-NID Programmable Network Accelerator
+ 1df3 0001 ENA1020Z
+ 1df3 0002 ENA1020ZS
1df7 opencpi.org
0001 ml605
0002 alst4
0003 alst4x
1dfc JSC NT-COM
1181 TDM 8 Port E1/T1/J1 Adapter
+1e24 Squirrels Research Labs
+ 0101 Acorn CLE-101
+ 0215 Acorn CLE-215
+ 021f Acorn CLE-215+
+ 1525 Xilinx BCU-1525
+1e38 Thinci, Inc
+1e3d Burlywood, Inc
# nee Tumsan Oy
1fc0 Ascom (Finland) Oy
0300 E2200 Dual E1/Rawpipe Card
@@ -22613,7 +23162,7 @@
1043 108d VivoBook X202EV
0158 Xeon E3-1200 v2/Ivy Bridge DRAM Controller
1043 844d P8 series motherboard
- 8086 2010 Server Board S1200BTS
+ 8086 2010 Server Board S1200BT Family
0159 Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port
015a Xeon E3-1200 v2/Ivy Bridge Graphics Controller
015c Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller
@@ -22659,6 +23208,7 @@
0406 Haswell Integrated Graphics Controller
040a Xeon E3-1200 v3 Processor Integrated Graphics Controller
0412 Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller
+ 17aa 309f ThinkCentre M83
0416 4th Gen Core Processor Integrated Graphics Controller
17aa 220e ThinkPad T440p
041a Xeon E3-1200 v3 Processor Integrated Graphics Controller
@@ -23140,6 +23690,8 @@
1590 0264 NVMe Datacenter SSD [3DNAND] 3.2TB 2.5" U.2 (P4600)
1590 0265 NVMe Datacenter SSD [3DNAND] 6.4TB 2.5" U.2 (P4600)
1590 026c NVMe Datacenter SSD [3DNAND] 4.0TB AIC (P4500)
+ 1d49 4802 Thinksystem U.2 P4510 NVMe SSD
+ 1d49 4812 Thinksystem U.2 P4610 NVMe SSD
8086 4308 Intel SSD D5-P4320 and D5-P4326
8086 4702 NVMe Datacenter SSD [3DNAND] SE 2.5" U.2 (P4500)
8086 4704 NVMe Datacenter SSD [3DNAND] SE AIC (P4500)
@@ -23183,6 +23735,7 @@
0bf6 Atom Processor D2xxx/N2xxx DRAM Controller
0bf7 Atom Processor D2xxx/N2xxx DRAM Controller
0c00 4th Gen Core Processor DRAM Controller
+ 17aa 309f ThinkCentre M83
0c01 Xeon E3-1200 v3/4th Gen Core Processor PCI Express x16 Controller
0c04 Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller
103c 1909 ZBook 15
@@ -23192,6 +23745,7 @@
0c09 Xeon E3-1200 v3/4th Gen Core Processor PCI Express x4 Controller
0c0c Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller
17aa 220e ThinkPad T440p
+ 17aa 309f ThinkCentre M83
0c46 Atom Processor S1200 PCI Express Root Port 1
0c47 Atom Processor S1200 PCI Express Root Port 2
0c48 Atom Processor S1200 PCI Express Root Port 3
@@ -23228,6 +23782,9 @@
0c7d Atom Processor S1200 Internal
0c7e Atom Processor S1200 Internal
0c7f Atom Processor S1200 Internal
+ 0cf8 Ethernet Controller X710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
+ 8086 0000 Ethernet Controller X710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
+ 8086 0001 Ethernet Controller X710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
0d00 Crystal Well DRAM Controller
0d01 Crystal Well PCI Express x16 Controller
0d04 Crystal Well DRAM Controller
@@ -23237,8 +23794,14 @@
0d16 Crystal Well Integrated Graphics Controller
0d26 Crystal Well Integrated Graphics Controller
0d36 Crystal Well Integrated Graphics Controller
+ 0d4e Ethernet Connection (10) I219-LM
+ 0d4f Ethernet Connection (10) I219-V
+ 0d58 Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
+ 8086 0000 Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
+ 8086 0001 Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
0e00 Xeon E7 v2/Xeon E5 v2/Core i7 DMI2
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e01 Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port in DMI2 Mode
0e02 Xeon E7 v2/Xeon E5 v2/Core i7 PCI Express Root Port 1a
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
@@ -23262,26 +23825,37 @@
0e1f Xeon E7 v2/Xeon E5 v2/Core i7 UBOX Registers
0e20 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 0
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e21 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 1
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e22 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 2
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e23 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 3
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e24 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 4
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e25 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 5
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e26 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 6
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e27 Xeon E7 v2/Xeon E5 v2/Core i7 Crystal Beach DMA Channel 7
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e28 Xeon E7 v2/Xeon E5 v2/Core i7 VTd/Memory Map/Misc
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e29 Xeon E7 v2/Xeon E5 v2/Core i7 Memory Hotplug
0e2a Xeon E7 v2/Xeon E5 v2/Core i7 IIO RAS
1028 04f7 Xeon E5 v2 on PowerEdge R320 server
+ 15d9 066b X9SRL-F
0e2c Xeon E7 v2/Xeon E5 v2/Core i7 IOAPIC
+ 15d9 066b X9SRL-F
0e2e Xeon E7 v2/Xeon E5 v2/Core i7 CBDMA
0e2f Xeon E7 v2/Xeon E5 v2/Core i7 CBDMA
0e30 Xeon E7 v2/Xeon E5 v2/Core i7 Home Agent 0
@@ -23606,6 +24180,8 @@
104b 82566DC Gigabit Network Connection
104c 82562V 10/100 Network Connection
104d 82566MC Gigabit Network Connection
+ 104e Ethernet Controller X710 for 10 Gigabit SFP+
+ 104f Ethernet Controller X710 for 10 Gigabit backplane
1050 82562EZ 10/100 Ethernet Controller
1028 019d Dimension 3000
1462 728c 865PE Neo2 (MS-6728)
@@ -23821,9 +24397,11 @@
1043 8369 Motherboard
1093 76e9 PCIe-8233 Ethernet Adapter
10a9 8029 Prism XL Single Port Gigabit Ethernet
+ 15d9 0605 X8SIL
15d9 060a X7SPA-H/X7SPA-HF Motherboard
15d9 060d C7SIM-Q Motherboard
8086 0001 Gigabit CT2 Desktop Adapter
+ 8086 3578 Server Board S1200BTLR
8086 357a Server Board S1200BTS
8086 a01f Gigabit CT Desktop Adapter
e4bf 50c1 PC1-GROOVE
@@ -23876,6 +24454,7 @@
8086 106f 10-Gigabit XF LR Server Adapter
8086 a06f 10-Gigabit XF LR Server Adapter
10f5 82567LM Gigabit Network Connection
+ 17aa 20ee ThinkPad T400
10f6 82574L Gigabit Network Connection
10f7 10 Gigabit BR KX4 Dual Port Network Connection
108e 7b12 Sun Dual 10GbE PCIe 2.0 FEM
@@ -23898,6 +24477,7 @@
103c 2159 Ethernet 10Gb 2-port 562i Adapter
108e 7b11 Ethernet Server Adapter X520-2
1170 004c 82599 DP 10G Mezzanine Adapter
+ 15d9 0611 AOC-STGN-I2S [REV 1.01]
1734 11a9 10 Gigabit Dual Port Network Connection
17aa 1071 ThinkServer X520-2 AnyFabric
17aa 4007 82599ES 10-Gigabit SFI/SFP+ Network Connection
@@ -24158,6 +24738,7 @@
1502 82579LM Gigabit Network Connection (Lewisville)
1028 04a3 Precision M4600
17aa 21ce ThinkPad T520
+ 8086 3578 Server Board S1200BTLR
8086 357a Server Board S1200BTS
1503 82579V Gigabit Network Connection
1043 849c P8P67 Deluxe Motherboard
@@ -24234,6 +24815,7 @@
8086 00a2 Ethernet Server Adapter I350-T2
8086 5001 Ethernet Server Adapter I350-T4
8086 5002 Ethernet Server Adapter I350-T2
+ 8086 5003 Ethernet 1G 4P I350-t OCP
1522 I350 Gigabit Fiber Network Connection
108e 7b17 Quad Port GbE PCIe 2.0 ExpressModule, MMF
108e 7b19 Dual Port GbE PCIe 2.0 Low Profile Adapter, MMF
@@ -24287,6 +24869,7 @@
152e 82599 Virtual Function
152f I350 Virtual Function
1530 X540 Virtual Function
+ 1531 I210 Gigabit Unprogrammed
1533 I210 Gigabit Network Connection
103c 0003 Ethernet I210-T1 GbE NIC
1093 7706 Compact Vision System Ethernet Adapter
@@ -24309,6 +24892,7 @@
153a Ethernet Connection I217-LM
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
+ 17aa 309f ThinkCentre M83
153b Ethernet Connection I217-V
1547 DSL3510 Thunderbolt Controller [Cactus Ridge 4C 2012]
1548 DSL3310 Thunderbolt Controller [Cactus Ridge 2C 2012]
@@ -24364,6 +24948,8 @@
156c DSL5520 Thunderbolt 2 NHI [Falcon Ridge 4C 2013]
156d DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
156f Ethernet Connection I219-LM
+ 1028 06dc Latitude E7470
+ 103c 8079 EliteBook 840 G3
1570 Ethernet Connection I219-V
1571 Ethernet Virtual Function 700 Series
1572 Ethernet Controller X710 for 10GbE SFP+
@@ -24398,6 +24984,9 @@
8086 000e Ethernet Server Adapter OCP X710-2
8086 000f Ethernet Server Adapter OCP X710-2
8086 0010 Ethernet Converged Network Adapter X710
+ 8086 0013 Ethernet 10G 2P X710 OCP
+ 8086 0014 Ethernet 10G 4P X710 OCP
+ 8086 0015 Ethernet Server Adapter X710-DA2 for OCP
8086 4005 Ethernet Controller X710 for 10GbE SFP+
8086 4006 Ethernet Controller X710 for 10GbE SFP+
8086 4007 Ethernet Controller X710 for 10GbE SFP+
@@ -24462,6 +25051,8 @@
1590 0286 Synergy 4610C 10/25Gb Ethernet Adapter
8086 000a Ethernet 25G 2P XXV710 Mezz
158b Ethernet Controller XXV710 for 25GbE SFP28
+ 1137 0000 Ethernet Network Adapter XXV710
+ 1137 0225 Ethernet Network Adapter XXV710
8086 0000 Ethernet Network Adapter XXV710
8086 0001 Ethernet Network Adapter XXV710-2
8086 0002 Ethernet Network Adapter XXV710-2
@@ -24532,8 +25123,10 @@
15d8 Ethernet Connection (4) I219-V
17aa 2247 ThinkPad T570
17aa 224f ThinkPad X1 Carbon 5th Gen
+ 17aa 225d ThinkPad T480
15d9 JHL6340 Thunderbolt 3 NHI (C step) [Alpine Ridge 2C 2016]
15da JHL6340 Thunderbolt 3 Bridge (C step) [Alpine Ridge 2C 2016]
+ 15db JHL6340 Thunderbolt 3 USB 3.1 Controller (C step) [Alpine Ridge 2C 2016]
15df Ethernet Connection (8) I219-LM
15e0 Ethernet Connection (8) I219-V
15e1 Ethernet Connection (9) I219-LM
@@ -24549,6 +25142,16 @@
15ec JHL7540 Thunderbolt 3 USB Controller [Titan Ridge 4C 2018]
15ef JHL7540 Thunderbolt 3 Bridge [Titan Ridge DD 2018]
15f0 JHL7540 Thunderbolt 3 USB Controller [Titan Ridge DD 2018]
+ 15f6 I210 Gigabit Ethernet Connection
+ 15ff Ethernet Controller X710 for 10GBASE-T
+ 8086 0001 Ethernet Network Adapter X710-T4L
+ 8086 0002 Ethernet Network Adapter X710-T4L
+ 8086 0003 Ethernet Network Adapter X710-T2L
+ 8086 0004 Ethernet Network Adapter X710-T2L
+ 8086 0005 Ethernet 10G 2P X710-T2L-t Adapter
+ 8086 0006 Ethernet 10G 4P X710-T4L-t Adapter
+ 8086 0007 Ethernet 10G 2P X710-T2L-t OCP
+ 8086 0008 Ethernet 10G 4P X710-T4L-t OCP
1600 Broadwell-U Host Bridge -OPI
1601 Broadwell-U PCI Express x16 Controller
1602 Broadwell-U Integrated Graphics
@@ -24592,9 +25195,13 @@
1901 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x16)
1902 HD Graphics 510
1903 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem
+ 1028 06dc Latitude E7470
1028 06e4 XPS 15 9550
+ 17aa 225d ThinkPad T480
1904 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
17aa 382a B51-80 Laptop
1905 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x8)
1906 HD Graphics 510
@@ -24608,9 +25215,12 @@
1911 Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th Gen Core Processor Gaussian Mixture Model
17aa 2247 ThinkPad T570
17aa 224f ThinkPad X1 Carbon 5th Gen
+ 17aa 225d ThinkPad T480
1912 HD Graphics 530
1916 Skylake GT2 [HD Graphics 520]
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
1918 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers
1919 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Imaging Unit
191b HD Graphics 530
@@ -24703,7 +25313,7 @@
1c02 6 Series/C200 Series Chipset Family 6 port Desktop SATA AHCI Controller
1028 04aa XPS 8300
1043 844d P8 series motherboard
- 8086 7270 Server Board S1200BTS
+ 8086 7270 Server Board S1200BT Family
1c03 6 Series/C200 Series Chipset Family 6 port Mobile SATA AHCI Controller
1028 04a3 Precision M4600
1028 04b2 Vostro 3350
@@ -24761,7 +25371,7 @@
1028 04da Vostro 3750
1043 844d P8 series motherboard
17aa 21cf ThinkPad T520
- 8086 7270 Server Board S1200BTS / Apple MacBook Pro 8,1/8,2
+ 8086 7270 Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2
1c24 6 Series/C200 Series Chipset Family Thermal Management Controller
1c25 6 Series/C200 Series Chipset Family DMI to PCI Bridge
1c26 6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1
@@ -24771,7 +25381,7 @@
1028 04da Vostro 3750
1043 844d P8 series motherboard
17aa 21cf ThinkPad T520
- 8086 7270 Server Board S1200BTS / Apple MacBook Pro 8,1/8,2
+ 8086 7270 Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2
1c27 6 Series/C200 Series Chipset Family USB Universal Host Controller #1
8086 7270 Apple MacBookPro8,2 [Core i7, 15", 2011]
1c2c 6 Series/C200 Series Chipset Family USB Universal Host Controller #5
@@ -24783,7 +25393,7 @@
1028 04da Vostro 3750
1043 844d P8 series motherboard
17aa 21cf ThinkPad T520
- 8086 7270 Server Board S1200BTS / Apple MacBook Pro 8,1/8,2
+ 8086 7270 Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2
1c33 6 Series/C200 Series Chipset Family LAN Controller
1c35 6 Series/C200 Series Chipset Family VECI Controller
1c3a 6 Series/C200 Series Chipset Family MEI Controller #1
@@ -24866,18 +25476,24 @@
1d1f C600/X79 series chipset PCI Express Root Port 8
1d20 C600/X79 series chipset High Definition Audio Controller
1d22 C600/X79 series chipset SMBus Host Controller
+ 15d9 066b X9SRL-F
1d24 C600/X79 series chipset Thermal Management Controller
+ 15d9 066b X9SRL-F
1d25 C600/X79 series chipset DMI to PCI Bridge
1d26 C600/X79 series chipset USB2 Enhanced Host Controller #1
1028 04f7 C602J on PowerEdge R320 server
+ 15d9 066b X9SRL-F
1d2d C600/X79 series chipset USB2 Enhanced Host Controller #2
1028 04f7 C602J on PowerEdge R320 server
+ 15d9 066b X9SRL-F
1d33 C600/X79 series chipset LAN Controller
1d35 C600/X79 series chipset VECI Controller
1d3a C600/X79 series chipset MEI Controller #1
1028 04f7 C602J on PowerEdge R320 server
+ 15d9 066b X9SRL-F
1d3b C600/X79 series chipset MEI Controller #2
1028 04f7 C602J on PowerEdge R320 server
+ 15d9 066b X9SRL-F
1d3c C600/X79 series chipset IDE-r Controller
1d3d C600/X79 series chipset KT Controller
1d3e C600/X79 series chipset PCI Express Virtual Root Port
@@ -24886,6 +25502,7 @@
1d40 C600/X79 series chipset LPC Controller
1d41 C600/X79 series chipset LPC Controller
1028 04f7 C602J on PowerEdge R320 server
+ 15d9 066b X9SRL-F
1d50 C608 chipset Dual 4-Port SATA/SAS Storage Control Unit
1d54 C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit
1d55 C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit
@@ -24998,6 +25615,7 @@
1043 1477 N56VZ
1043 1517 Zenbook Prime UX31A
1043 84ca P8 series motherboard
+ 17aa 21f3 ThinkPad T430
1849 1e31 Motherboard
1e33 7 Series/C210 Series Chipset Family LAN Controller
1e3a 7 Series/C216 Chipset Family MEI Controller #1
@@ -25113,13 +25731,30 @@
201a Sky Lake-E Non-Transparent Bridge Registers
201c Sky Lake-E Non-Transparent Bridge Registers
2020 Sky Lake-E DMI3 Registers
+ 15d9 095d X11SPM-TF
2021 Sky Lake-E CBDMA Registers
2024 Sky Lake-E MM/Vt-d Configuration Registers
+ 2025 Sky Lake-E RAS
+ 2026 Sky Lake-E IOAPIC
2030 Sky Lake-E PCI Express Root Port A
2031 Sky Lake-E PCI Express Root Port B
2032 Sky Lake-E PCI Express Root Port C
2033 Sky Lake-E PCI Express Root Port D
+ 2034 Sky Lake-E VT-d
2035 Sky Lake-E RAS Configuration Registers
+ 2036 Sky Lake-E IOxAPIC Configuration Registers
+ 2040 Sky Lake-E Integrated Memory Controller
+ 2041 Sky Lake-E Integrated Memory Controller
+ 2042 Sky Lake-E Integrated Memory Controller
+ 2043 Sky Lake-E Integrated Memory Controller
+ 2044 Sky Lake-E Integrated Memory Controller
+ 2045 Sky Lake-E LM Channel 1
+ 2046 Sky Lake-E LMS Channel 1
+ 2047 Sky Lake-E LMDP Channel 1
+ 2048 Sky Lake-E DECS Channel 2
+ 2049 Sky Lake-E LM Channel 2
+ 204a Sky Lake-E LMS Channel 2
+ 204b Sky Lake-E LMDP Channel 2
204c Sky Lake-E M3KTI Registers
204d Sky Lake-E M3KTI Registers
204e Sky Lake-E M3KTI Registers
@@ -25127,6 +25762,9 @@
2055 Sky Lake-E CHA Registers
2056 Sky Lake-E CHA Registers
2057 Sky Lake-E CHA Registers
+ 2058 Sky Lake-E KTI 0
+ 2059 Sky Lake-E UPI Registers
+ 2066 Sky Lake-E Integrated Memory Controller
2068 Sky Lake-E DDRIO Registers
2069 Sky Lake-E DDRIO Registers
206a Sky Lake-E IOxAPIC Configuration Registers
@@ -25143,6 +25781,7 @@
2086 Sky Lake-E PCU Registers
208d Sky Lake-E CHA Registers
208e Sky Lake-E CHA Registers
+ 2241 Larrabee
2250 Xeon Phi coprocessor 5100 series
225c Xeon Phi coprocessor SE10/7120 series
225d Xeon Phi coprocessor 3120 series
@@ -26398,11 +27037,13 @@
1043 817a P5LD2-VM Mainboard
107b 5048 E4500
1462 7418 Wind PC MS-7418
+ 1849 2770 ConRoe1333-D667
8086 544e DeskTop Board D945GTP
2771 82945G/GZ/P/PL PCI Express Root Port
2772 82945G/GZ Integrated Graphics Controller
103c 2a3b Pavilion A1512X
1462 7418 Wind PC MS-7418
+ 1849 2772 ConRoe1333-D667
8086 544e DeskTop Board D945GTP
8086 d605 Desktop Board D945GCCR
2774 82955X Memory Controller Hub
@@ -26478,6 +27119,7 @@
10f7 8338 Panasonic CF-Y5 laptop
17aa 2009 ThinkPad R60/T60/X60 series
27bc NM10 Family LPC Controller
+ 1043 83ad Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
144d c072 Notebook N150P
1458 5001 GA-D525TUD
@@ -26501,6 +27143,7 @@
27c1 NM10/ICH7 Family SATA Controller [AHCI mode]
1028 01df PowerEdge SC440
103c 2a3b Pavilion A1512X
+ 1043 83ad Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
144d c072 Notebook N150P
1458 b005 GA-D525TUD
@@ -26535,6 +27178,7 @@
103c 30d5 530 Laptop
1043 1237 A6J-Q008
1043 8179 P5KPL-VM,P5LD2-VM Mainboard
+ 1043 83ad Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
1071 8209 Medion MIM 2240 Notebook PC [MD98100]
107b 5048 E4500
@@ -26559,6 +27203,7 @@
103c 30a3 Compaq nw8440
1043 1237 A6J-Q008
1043 8179 P5KPL-VM,P5LD2-VM Mainboard
+ 1043 83ad Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
1071 8209 Medion MIM 2240 Notebook PC [MD98100]
107b 5048 E4500
@@ -26583,6 +27228,7 @@
103c 30a3 Compaq nw8440
1043 1237 A6J-Q008
1043 8179 P5KPL-VM,P5LD2-VM Mainboard
+ 1043 83ad Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
1071 8209 Medion MIM 2240 Notebook PC [MD98100]
107b 5048 E4500
@@ -26605,6 +27251,7 @@
103c 30a3 Compaq nw8440
1043 1237 A6J-Q008
1043 8179 P5KPL-VM,P5LD2-VM Mainboard
+ 1043 83ad Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
1071 8209 Medion MIM 2240 Notebook PC [MD98100]
107b 5048 E4500
@@ -26629,6 +27276,7 @@
103c 30d5 530 Laptop
1043 1237 A6J-Q008
1043 8179 P5KPL-VM,P5LD2-VM Mainboard
+ 1043 83ad Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
1071 8209 Medion MIM 2240 Notebook PC [MD98100]
144d c072 Notebook N150P
@@ -26687,6 +27335,7 @@
1043 817f P5LD2-VM Mainboard (Realtek ALC 882 codec)
1043 8290 P5KPL-VM Motherboard
1043 82ea P5KPL-CM Motherboard
+ 1043 8437 Eee PC 1015PX
105b 0d7c D270S/D250S Motherboard
1071 8207 Medion MIM 2240 Notebook PC [MD98100]
107b 5048 E4500
@@ -26756,6 +27405,7 @@
1775 11cc CC11/CL11
27e2 82801GR/GH/GHM (ICH7 Family) PCI Express Port 6
1775 11cc CC11/CL11
+ 280b Intel(R) Display Audio
2810 82801HB/HR (ICH8/R) LPC Interface Controller
1043 81ec P5B
2811 82801HEM (ICH8M-E) LPC Interface Controller
@@ -27013,6 +27663,7 @@
1462 7345 MS-7345 Motherboard
8086 5044 Desktop Board DP35DP
2917 ICH9M-E LPC Interface Controller
+ 17aa 20f5 ThinkPad T400
e4bf cc4d CCM-BOOGIE
2918 82801IB (ICH9) LPC Interface Controller
1028 0236 PowerEdge R610 82801IB (ICH9) LPC Interface Controller
@@ -27052,6 +27703,7 @@
2928 82801IBM/IEM (ICH9M/ICH9M-E) 2 port SATA Controller [IDE mode]
2929 82801IBM/IEM (ICH9M/ICH9M-E) 4 port SATA Controller [AHCI mode]
103c 3628 dv6-1190en
+ 17aa 20f8 ThinkPad T400
e4bf cc4d CCM-BOOGIE
292c 82801IEM (ICH9M-E) SATA Controller [RAID mode]
292d 82801IBM/IEM (ICH9M/ICH9M-E) 2 port SATA Controller [IDE mode]
@@ -27064,6 +27716,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f9 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 5044 Desktop Board DP35DP
e4bf cc4d CCM-BOOGIE
@@ -27085,6 +27738,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f0 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 5044 Desktop Board DP35DP
e4bf cc4d CCM-BOOGIE
@@ -27103,6 +27757,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f0 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 5044 Desktop Board DP35DP
e4bf cc4d CCM-BOOGIE
@@ -27119,6 +27774,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f0 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 5044 Desktop Board DP35DP
e4bf cc4d CCM-BOOGIE
@@ -27135,6 +27791,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f0 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 2937 Optiplex 755
8086 2942 828011 (ICH9 Family ) USB UHCI Controller
@@ -27152,6 +27809,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f0 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 2938 Optiplex 755
8086 5044 Desktop Board DP35DP
@@ -27164,6 +27822,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f0 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 5044 Desktop Board DP35DP
e4bf cc4d CCM-BOOGIE
@@ -27182,6 +27841,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f1 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 5044 Desktop Board DP35DP
e4bf cc4d CCM-BOOGIE
@@ -27197,6 +27857,7 @@
1043 8277 P5K PRO Motherboard: 82801IR [ICH9R]
1462 7345 MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f1 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 293c Optiplex 755
8086 5044 Desktop Board DP35DP
@@ -27209,6 +27870,7 @@
1043 829f P5K PRO Motherboard: 82801IR [ICH9R]
1462 735a MS-7345 Motherboard: Intel 82801I/IR [ICH9/ICH9R]
1462 7360 G33/P35 Neo
+ 17aa 20f2 ThinkPad T400
1af4 1100 QEMU Virtual Machine
8086 293e Optiplex 755
8086 2940 Optiplex 755
@@ -27384,14 +28046,18 @@
2a16 Mobile GME965/GLE960 PT IDER Controller
2a17 Mobile GME965/GLE960 KT Controller
2a40 Mobile 4 Series Chipset Memory Controller Hub
+ 17aa 20e0 ThinkPad T400
e4bf cc4d CCM-BOOGIE
2a41 Mobile 4 Series Chipset PCI Express Graphics Port
e4bf cc4d CCM-BOOGIE
2a42 Mobile 4 Series Chipset Integrated Graphics Controller
+ 17aa 2112 ThinkPad T400
e4bf cc4d CCM-BOOGIE
2a43 Mobile 4 Series Chipset Integrated Graphics Controller
+ 17aa 2112 ThinkPad T400
e4bf cc4d CCM-BOOGIE
2a44 Mobile 4 Series Chipset MEI Controller
+ 17aa 20e6 ThinkPad T400
2a45 Mobile 4 Series Chipset MEI Controller
2a46 Mobile 4 Series Chipset PT IDER Controller
2a47 Mobile 4 Series Chipset AMT SOL Redirection
@@ -27799,6 +28465,21 @@
8086 4210 Dual Band Wireless AC 3165
3166 Dual Band Wireless-AC 3165 Plus Bluetooth
3184 UHD Graphics 605
+ 318c Celeron/Pentium Silver Processor Dynamic Platform and Thermal Framework Processor Participant
+ 318e Celeron/Pentium Silver Processor NorthPeak
+ 3197 Celeron/Pentium Silver Processor PCI-default ISA-bridge
+ 319a Celeron/Pentium Silver Processor Trusted Execution Engine Interface
+ 31ac Celeron/Pentium Silver Processor Serial IO I2C Host Controller
+ 31ae Celeron/Pentium Silver Processor Serial IO I2C Host Controller
+ 31bc Celeron/Pentium Silver Processor Serial IO UART Host Controller
+ 31be Celeron/Pentium Silver Processor Serial IO UART Host Controller
+ 31c0 Celeron/Pentium Silver Processor Serial IO UART Host Controller
+ 31c2 Celeron/Pentium Silver Processor Serial IO SPI Host Controller
+ 31c4 Celeron/Pentium Silver Processor Serial IO SPI Host Controller
+ 31c6 Celeron/Pentium Silver Processor Serial IO SPI Host Controller
+ 31cc Celeron/Pentium Silver Processor SDA Standard Compliant SD Host Controller
+ 31d4 Celeron/Pentium Silver Processor Gaussian Mixture Model
+ 31ee Celeron/Pentium Silver Processor Serial IO UART Host Controller
3200 GD31244 PCI-X SATA HBA
1775 c200 C2K onboard SATA host bus adapter
3310 IOP348 I/O Processor
@@ -28274,6 +28955,7 @@
3b12 3400 Series Chipset LPC Interface Controller
3b13 5 Series/3400 Series Chipset LPC Interface Controller
3b14 3420 Chipset LPC Interface Controller
+ 15d9 0605 X8SIL
3b15 5 Series/3400 Series Chipset LPC Interface Controller
3b16 3450 Chipset LPC Interface Controller
3b17 5 Series/3400 Series Chipset LPC Interface Controller
@@ -28289,6 +28971,7 @@
3b21 5 Series/3400 Series Chipset 2 port SATA IDE Controller
3b22 5 Series/3400 Series Chipset 6 port SATA AHCI Controller
1028 02da OptiPlex 980
+ 15d9 0605 X8SIL
15d9 060d C7SIM-Q Motherboard
3b23 5 Series/3400 Series Chipset 4 port SATA AHCI Controller
3b25 5 Series/3400 Series Chipset SATA RAID Controller
@@ -28320,6 +29003,7 @@
1043 3838 P7P55-M Motherboard
1043 8383 P7P55-M Motherboard
144d c06a R730 Laptop
+ 15d9 0605 X8SIL
15d9 060d C7SIM-Q Motherboard
17c0 10d2 Medion Akoya E7214 Notebook PC [MD98410]
e4bf 50c1 PC1-GROOVE
@@ -28334,6 +29018,7 @@
1028 040a Latitude E6410
1028 040b Latitude E6510
144d c06a R730 Laptop
+ 15d9 0605 X8SIL
15d9 060d C7SIM-Q Motherboard
17c0 10d2 Medion Akoya E7214 Notebook PC [MD98410]
e4bf 50c1 PC1-GROOVE
@@ -28349,6 +29034,7 @@
1028 040a Latitude E6410
1028 040b Latitude E6510
144d c06a R730 Laptop
+ 15d9 0605 X8SIL
15d9 060d C7SIM-Q Motherboard
17c0 10d2 Medion Akoya E7214 Notebook PC [MD98410]
e4bf 50c1 PC1-GROOVE
@@ -28479,15 +29165,20 @@
3cf4 Xeon E5/Core i7 Integrated Memory Controller System Address Decoder 0
3cf5 Xeon E5/Core i7 Integrated Memory Controller System Address Decoder 1
3cf6 Xeon E5/Core i7 System Address Decoder
- 3e18 8th Gen Core Processor Host Bridge/DRAM Registers
- 3e1f 8th Gen Core Processor Host Bridge/DRAM Registers
+ 3e10 8th Gen Core 4-core Processor Host Bridge/DRAM Registers [Coffee Lake H]
+ 3e18 8th Gen Core 4-core Workstation Processor Host Bridge/DRAM Registers [Coffee Lake S]
+ 3e1f 8th Gen Core 4-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
+ 3e30 8th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
3e81 8th Gen Core Processor PCIe Controller (x16)
3e85 8th Gen Core Processor PCIe Controller (x8)
3e89 8th Gen Core Processor PCIe Controller (x4)
3e91 8th Gen Core Processor Gaussian Mixture Model
3e92 UHD Graphics 630 (Desktop)
+ 3e93 UHD Graphics 610
+ 3e98 UHD Graphics 630 (Desktop 9 Series)
3e9b UHD Graphics 630 (Mobile)
3ea0 UHD Graphics 620 (Whiskey Lake)
+ 1028 089e Inspiron 5482
3ea5 Iris Plus Graphics 655
3ec2 8th Gen Core Processor Host Bridge/DRAM Registers
3ec4 8th Gen Core Processor Host Bridge/DRAM Registers
@@ -28684,13 +29375,21 @@
5911 Xeon E3-1200 v6/7th Gen Core Processor Gaussian Mixture Model
5912 HD Graphics 630
5914 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers
+ 17aa 225d ThinkPad T480
5916 HD Graphics 620
17aa 2248 ThinkPad T570
17aa 224f ThinkPad X1 Carbon 5th Gen
5917 UHD Graphics 620
+ 17aa 225e ThinkPad T480
5918 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers
+ 591b HD Graphics 630
+ 591c UHD Graphics 615
591d HD Graphics P630
+ 591e HD Graphics 615
591f Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers
+ 5923 HD Graphics 635
+ 5926 Iris Plus Graphics 640
+ 5927 Iris Plus Graphics 650
5a84 Celeron N3350/Pentium N4200/Atom E3900 Series Integrated Graphics Controller
5a88 Celeron N3350/Pentium N4200/Atom E3900 Series Imaging Unit
5a98 Celeron N3350/Pentium N4200/Atom E3900 Series Audio Cluster
@@ -28747,6 +29446,7 @@
65fa 5100 Chipset PCI Express x16 Port 4-7
65ff 5100 Chipset DMA Engine
6f00 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2
+ 15d9 0832 X10SRL-F
6f01 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 0
6f02 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 1
6f03 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D PCI Express Root Port 1
@@ -28775,17 +29475,29 @@
6f1e Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Ubox
6f1f Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Ubox
6f20 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 0
+ 15d9 0832 X10SRL-F
6f21 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 1
+ 15d9 0832 X10SRL-F
6f22 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 2
+ 15d9 0832 X10SRL-F
6f23 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 3
+ 15d9 0832 X10SRL-F
6f24 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 4
+ 15d9 0832 X10SRL-F
6f25 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 5
+ 15d9 0832 X10SRL-F
6f26 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 6
+ 15d9 0832 X10SRL-F
6f27 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Crystal Beach DMA Channel 7
+ 15d9 0832 X10SRL-F
6f28 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Map/VTd_Misc/System Management
+ 15d9 0832 X10SRL-F
6f29 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Hot Plug
+ 15d9 0832 X10SRL-F
6f2a Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO RAS/Control Status/Global Errors
+ 15d9 0832 X10SRL-F
6f2c Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC
+ 15d9 0832 X10SRL-F
6f30 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 0
6f32 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 0
6f33 Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D QPI Link 1
@@ -29038,6 +29750,7 @@
1993 0ded mGuard-PCI AV#2
1993 0dee mGuard-PCI AV#1
1993 0def mGuard-PCI AV#0
+ 87c0 UHD Graphics 617
8800 Platform Controller Hub EG20T PCI Express Port
8801 Platform Controller Hub EG20T Packet Hub
8802 Platform Controller Hub EG20T Gigabit Ethernet Controller
@@ -29067,6 +29780,7 @@
8c00 8 Series/C220 Series Chipset Family 4-port SATA Controller 1 [IDE mode]
8c01 8 Series Chipset Family 4-port SATA Controller 1 [IDE mode] - Mobile
8c02 8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode]
+ 17aa 309f ThinkCentre M83
8c03 8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode]
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
@@ -29099,28 +29813,34 @@
8c20 8 Series/C220 Series Chipset High Definition Audio Controller
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
+ 17aa 309f ThinkCentre M83
8c21 8 Series/C220 Series Chipset High Definition Audio Controller
8c22 8 Series/C220 Series Chipset Family SMBus Controller
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
+ 17aa 309f ThinkCentre M83
8c23 8 Series Chipset Family CHAP Counters
8c24 8 Series Chipset Family Thermal Management Controller
8c26 8 Series/C220 Series Chipset Family USB EHCI #1
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
17aa 2210 ThinkPad T540p
+ 17aa 309f ThinkCentre M83
2210 17aa ThinkPad T540p
8c2d 8 Series/C220 Series Chipset Family USB EHCI #2
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
+ 17aa 309f ThinkCentre M83
8c31 8 Series/C220 Series Chipset Family USB xHCI
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
+ 17aa 309f ThinkCentre M83
8c33 8 Series/C220 Series Chipset Family LAN Controller
8c34 8 Series/C220 Series Chipset Family NAND Controller
8c3a 8 Series/C220 Series Chipset Family MEI Controller #1
103c 1909 ZBook 15
17aa 220e ThinkPad T440p
+ 17aa 309f ThinkCentre M83
8c3b 8 Series/C220 Series Chipset Family MEI Controller #2
8c3c 8 Series/C220 Series Chipset Family IDE-r Controller
8c3d 8 Series/C220 Series Chipset Family KT Controller
@@ -29137,6 +29857,7 @@
8c4a H87 Express LPC Controller
8c4b HM87 Express LPC Controller
8c4c Q85 Express LPC Controller
+ 17aa 309f ThinkCentre M83
8c4d 8 Series/C220 Series Chipset Family LPC Controller
8c4e Q87 Express LPC Controller
8c4f QM87 Express LPC Controller
@@ -29221,14 +29942,20 @@
8d20 C610/X99 series chipset HD Audio Controller
8d21 C610/X99 series chipset HD Audio Controller
8d22 C610/X99 series chipset SMBus Controller
+ 15d9 0832 X10SRL-F
8d24 C610/X99 series chipset Thermal Subsystem
8d26 C610/X99 series chipset USB Enhanced Host Controller #1
+ 15d9 0832 X10SRL-F
8d2d C610/X99 series chipset USB Enhanced Host Controller #2
+ 15d9 0832 X10SRL-F
8d31 C610/X99 series chipset USB xHCI Host Controller
+ 15d9 0832 X10SRL-F
8d33 C610/X99 series chipset LAN Controller
8d34 C610/X99 series chipset NAND Controller
8d3a C610/X99 series chipset MEI Controller #1
+ 15d9 0832 X10SRL-F
8d3b C610/X99 series chipset MEI Controller #2
+ 15d9 0832 X10SRL-F
8d3c C610/X99 series chipset IDE-r Controller
8d3d C610/X99 series chipset KT Controller
8d40 C610/X99 series chipset LPC Controller
@@ -29236,6 +29963,7 @@
8d42 C610/X99 series chipset LPC Controller
8d43 C610/X99 series chipset LPC Controller
8d44 C610/X99 series chipset LPC Controller
+ 15d9 0832 X10SRL-F
8d45 C610/X99 series chipset LPC Controller
8d46 C610/X99 series chipset LPC Controller
8d47 C610/X99 series chipset LPC Controller
@@ -29254,6 +29982,7 @@
8d68 C610/X99 series chipset sSATA Controller [IDE mode]
8d6e C610/X99 series chipset sSATA Controller [RAID mode]
8d7c C610/X99 series chipset SPSR
+ 15d9 0832 X10SRL-F
8d7d C610/X99 series chipset MS SMBus 0
8d7e C610/X99 series chipset MS SMBus 1
8d7f C610/X99 series chipset MS SMBus 2
@@ -29371,10 +30100,15 @@
9ce5 Wildcat Point-LP Serial IO GSPI Controller #0
9ce6 Wildcat Point-LP Serial IO GSPI Controller #1
9d03 Sunrise Point-LP SATA Controller [AHCI mode]
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
+ 17aa 225d ThinkPad T480
17aa 382a B51-80 Laptop
9d10 Sunrise Point-LP PCI Express Root Port #1
+ 9d11 Sunrise Point-LP PCI Express Root Port #2
9d12 Sunrise Point-LP PCI Express Root Port #3
+ 9d13 Sunrise Point-LP PCI Express Root Port #4
9d14 Sunrise Point-LP PCI Express Root Port #5
17aa 382a B51-80 Laptop
9d15 Sunrise Point-LP PCI Express Root Port #6
@@ -29384,14 +30118,21 @@
9d18 Sunrise Point-LP PCI Express Root Port #9
17aa 382a B51-80 Laptop
9d19 Sunrise Point-LP PCI Express Root Port #10
+ 9d1a Sunrise Point-LP PCI Express Root Port #11
9d21 Sunrise Point-LP PMC
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
17aa 224f ThinkPad X1 Carbon 5th Gen
+ 17aa 225d ThinkPad T480
17aa 382a B51-80 Laptop
9d23 Sunrise Point-LP SMBus
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
17aa 2247 ThinkPad T570
17aa 224f ThinkPad X1 Carbon 5th Gen
+ 17aa 225d ThinkPad T480
17aa 382a B51-80 Laptop
9d27 Sunrise Point-LP Serial IO UART Controller #0
9d28 Sunrise Point-LP Serial IO UART Controller #1
@@ -29399,31 +30140,48 @@
9d2a Sunrise Point-LP Serial IO SPI Controller #1
9d2d Sunrise Point-LP Secure Digital IO Controller
9d2f Sunrise Point-LP USB 3.0 xHCI Controller
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
17aa 2247 ThinkPad T570
+ 17aa 225d ThinkPad T480
17aa 382a B51-80 Laptop
9d31 Sunrise Point-LP Thermal subsystem
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
17aa 2247 ThinkPad T570
17aa 224f ThinkPad X1 Carbon 5th Gen
+ 17aa 225d ThinkPad T480
17aa 382a B51-80 Laptop
9d35 Sunrise Point-LP Integrated Sensor Hub
9d3a Sunrise Point-LP CSME HECI #1
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
17aa 2247 ThinkPad T570
17aa 224f ThinkPad X1 Carbon 5th Gen
+ 17aa 225d ThinkPad T480
17aa 382a B51-80 Laptop
+ 9d3d Sunrise Point-LP Active Management Technology - SOL
+ 103c 8079 EliteBook 840 G3
9d43 Sunrise Point-LP LPC Controller
17aa 382a B51-80 Laptop
9d48 Sunrise Point-LP LPC Controller
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
- 9d4e Intel(R) 100 Series Chipset Family LPC Controller/eSPI Controller - 9D4E
+ 103c 8079 EliteBook 840 G3
+ 9d4e Sunrise Point LPC Controller/eSPI Controller
+ 17aa 225d ThinkPad T480
+ 9d50 Sunrise Point LPC Controller
9d56 Sunrise Point-LP LPC Controller
9d58 Sunrise Point-LP LPC Controller
17aa 2247 ThinkPad T570
17aa 224f ThinkPad X1 Carbon 5th Gen
9d60 Sunrise Point-LP Serial IO I2C Controller #0
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
+ 17aa 225d ThinkPad T480
8086 9d60 100 Series PCH/Sunrise Point PCH I2C0 [Skylake/Kaby Lake LPSS I2C]
9d61 Sunrise Point-LP Serial IO I2C Controller #1
9d62 Sunrise Point-LP Serial IO I2C Controller #2
@@ -29432,9 +30190,35 @@
9d65 Sunrise Point-LP Serial IO I2C Controller #5
9d66 Sunrise Point-LP Serial IO UART Controller #2
9d70 Sunrise Point-LP HD Audio
+ 1028 06dc Latitude E7470
1028 06f3 Latitude 3570
+ 103c 8079 EliteBook 840 G3
17aa 382a B51-80 Laptop
9d71 Sunrise Point-LP HD Audio
+ 17aa 225d ThinkPad T480
+ 9d84 Cannon Point-LP LPC Controller
+ 1028 089e Inspiron 5482
+ 9da3 Cannon Point-LP SMBus Controller
+ 9da4 Cannon Point-LP SPI Controller
+ 9db0 Cannon Point-LP PCI Express Root Port #9
+ 9db4 Cannon Point-LP PCI Express Root Port #13
+ 1028 089e Inspiron 5482
+ 9db6 Cannon Point-LP PCI Express Root Port #15
+ 9db8 Cannon Point-LP PCI Express Root Port #1
+ 9dbc Cannon Point-LP PCI Express Root Port #5
+ 9dc8 Cannon Point-LP High Definition Audio Controller
+ 1028 089e Inspiron 5482
+ 9dd3 Cannon Point-LP SATA Controller [AHCI Mode]
+ 9de0 Cannon Point-LP MEI Controller #1
+ 9de8 Cannon Point-LP Serial IO I2C Controller #0
+ 1028 089e Inspiron 5482
+ 9de9 Cannon Point-LP Serial IO I2C Controller #1
+ 1028 089e Inspiron 5482
+ 9ded Cannon Point-LP USB 3.1 xHCI Controller
+ 9def Cannon Point-LP Shared SRAM
+ 9df0 Cannon Point-LP CNVi [Wireless-AC]
+ 9df9 Cannon Point-LP Thermal Controller
+ 9dfc Cannon Point-LP Integrated Sensor Hub
a000 Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge
1458 5000 GA-D525TUD
8086 4f4d DeskTop Board D510MO
@@ -29446,10 +30230,13 @@
a002 Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller
a003 Atom Processor D4xx/D5xx/N4xx/N5xx CHAPS counter
a010 Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge
+ 1043 83ac Eee PC 1015PX
144d c072 Notebook N150P
a011 Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller
+ 1043 83ac Eee PC 1015PX
144d c072 Notebook N150P
a012 Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller
+ 1043 83ac Eee PC 1015PX
144d c072 Notebook N150P
a013 Atom Processor D4xx/D5xx/N4xx/N5xx CHAPS counter
a102 Q170/Q150/B150/H170/H110/Z170/CM236 Chipset SATA Controller [AHCI Mode]
@@ -29567,19 +30354,28 @@
a19f C620 Series Chipset Family PCI Express Root Port #16
a1a0 C620 Series Chipset Family P2SB
a1a1 C620 Series Chipset Family Power Management Controller
+ 15d9 095d X11SPM-TF
a1a2 C620 Series Chipset Family cAVS
a1a3 C620 Series Chipset Family SMBus
+ 15d9 095d X11SPM-TF
a1a4 C620 Series Chipset Family SPI Controller
+ 15d9 095d X11SPM-TF
a1a6 C620 Series Chipset Family Trace Hub
a1af C620 Series Chipset Family USB 3.0 xHCI Controller
+ 15d9 095d X11SPM-TF
a1b1 C620 Series Chipset Family Thermal Subsystem
+ 15d9 095d X11SPM-TF
a1ba C620 Series Chipset Family MEI Controller #1
+ 15d9 095d X11SPM-TF
a1bb C620 Series Chipset Family MEI Controller #2
+ 15d9 095d X11SPM-TF
a1bc C620 Series Chipset Family IDE Redirection
a1bd C620 Series Chipset Family KT Redirection
a1be C620 Series Chipset Family MEI Controller #3
+ 15d9 095d X11SPM-TF
a1c1 C621 Series Chipset LPC/eSPI Controller
a1c2 C622 Series Chipset LPC/eSPI Controller
+ 15d9 095d X11SPM-TF
a1c3 C624 Series Chipset LPC/eSPI Controller
a1c4 C625 Series Chipset LPC/eSPI Controller
a1c5 C626 Series Chipset LPC/eSPI Controller
@@ -29661,6 +30457,9 @@
a2ee 200 Series PCH PCI Express Root Port #24
a2f0 200 Series PCH HD Audio
a304 H370 Chipset LPC/eSPI Controller
+ a305 Z390 Chipset LPC/eSPI Controller
+ a306 Q370 Chipset LPC/eSPI Controller
+ a30c QM370 Chipset LPC/eSPI Controller
a323 Cannon Lake PCH SMBus Controller
a324 Cannon Lake PCH SPI Controller
a32c Cannon Lake PCH PCI Express Root Port #21
@@ -29689,7 +30488,13 @@
a343 Cannon Lake PCH PCI Express Root Port #20
a348 Cannon Lake PCH cAVS
a352 Cannon Lake PCH SATA AHCI Controller
+ a353 Cannon Lake Mobile PCH SATA AHCI Controller
a360 Cannon Lake PCH HECI Controller
+ a363 Cannon Lake PCH Active Management Technology - SOL
+ a368 Cannon Lake PCH Serial IO I2C Controller #0
+ a369 Cannon Lake PCH Serial IO I2C Controller #1
+ a36a Cannon Lake PCH Serial IO I2C Controller #2
+ a36b Cannon Lake PCH Serial IO I2C Controller #3
a36d Cannon Lake PCH USB 3.1 xHCI Host Controller
a36f Cannon Lake PCH Shared SRAM
a370 Wireless-AC 9560 [Jefferson Peak]
@@ -29708,6 +30513,7 @@
4c53 1051 CE7 mainboard
e4bf 1000 CC8-1-BLUES
d130 Core Processor DMI
+ 15d9 0605 X8SIL
d131 Core Processor DMI
1028 02da OptiPlex 980
15d9 060d C7SIM-Q Motherboard
@@ -29733,6 +30539,8 @@
d158 Core Processor Miscellaneous Registers
f1a5 SSD 600P Series
f1a6 SSD Pro 7600p/760p/E 6100p Series
+ f1a8 SSDPEKNW020T8 [660p, 2TB]
+ 8086 390d SSDPEKNW020T8 [660p, 2TB]
80ee InnoTek Systemberatung GmbH
beef VirtualBox Graphics Adapter
cafe VirtualBox Guest Service
@@ -29863,7 +30671,7 @@
9004 7888 AHA-2930UW SCSI Controller
8b78 ABA-1030
ec78 AHA-4944W/UW
-# acquired by Microsemi
+# Acquired by Microchip Technology
9005 Adaptec
0010 AHA-2940U2/U2W
9005 2180 AHA-2940U2 SCSI Controller
@@ -30320,6 +31128,8 @@ caed Canny Edge
cafe Chrysalis-ITS
0003 Luna K3 Hardware Security Module
0006 Luna PCI-e 3000 Hardware Security Module
+ 0007 Luna K6 Hardware Security Module
+ 0008 Luna K7 Hardware Security Module
cc53 ScaleFlux Inc.
cccc Catapult Communications
ccec Curtiss-Wright Controls Embedded Computing
@@ -30531,6 +31341,7 @@ edd8 ARK Logic Inc
# Found on M2N68-AM Motherboard
f043 ASUSTeK Computer Inc. (Wrong ID)
f05b Foxconn International, Inc. (Wrong ID)
+f15e SiFive, Inc.
f1d0 AJA Video
c0fe Xena HS/HD-R
c0ff Kona/Xena 2
@@ -30541,7 +31352,9 @@ f1d0 AJA Video
db09 Corvid 24
dcaf Kona HD
dfee Xena HD-DA
+ eb0d Corvid 88
eb0e Corvid 44
+ eb1d Kona 5
efac Xena SD-MM/SD-22-MM
facd Xena HD-MM
f5f5 F5 Networks, Inc.
diff --git a/usr/src/data/hwdata/usb.ids b/usr/src/data/hwdata/usb.ids
index d52f1a0a71..424843848e 100644
--- a/usr/src/data/hwdata/usb.ids
+++ b/usr/src/data/hwdata/usb.ids
@@ -9,8 +9,8 @@
# The latest version can be obtained from
# http://www.linux-usb.org/usb.ids
#
-# Version: 2018.10.23
-# Date: 2018-10-23 20:34:06
+# Version: 2019.02.25
+# Date: 2019-02-25 20:34:06
#
# Vendors, devices and interfaces. Please keep sorted.
@@ -72,6 +72,7 @@
0002 HD44780 LCD interface
03e7 Intel
2150 Myriad VPU [Movidius Neural Compute Stick]
+ 2485 Movidius MyriadX
03e8 EndPoints, Inc.
0004 SE401 Webcam
0008 101 Ethernet [klsi]
@@ -450,6 +451,7 @@
3005 ScanJet 4670v
3011 PSC 1100 series
3017 Printing Support
+ 304a Slim Keyboard
3102 PhotoSmart P1100 Printer w/ Card Reader
3104 DeskJet 960c
3111 OfficeJet 4100 series
@@ -775,6 +777,7 @@
6011 FT4232H Quad HS USB-UART/FIFO IC
6014 FT232H Single HS USB-UART/FIFO IC
6015 Bridge(I2C/SPI/UART/FIFO)
+ 6f70 HB-RF-USB
8028 Dev board JTAG (FT232H based)
8040 4 Port Hub
8070 7 Port Hub
@@ -783,6 +786,7 @@
8370 7 Port Hub
8371 PS/2 Keyboard And Mouse
8372 FT8U100AX Serial Port
+ 87d0 Cressi Dive Computer Interface
8a28 Rainforest Automation ZigBee Controller
8a98 TIAO Multi-Protocol Adapter
8b28 Alpermann+Velte TCI70
@@ -815,6 +819,7 @@
bcd8 Stellaris Development Board
bcd9 Stellaris Evaluation Board
bcda Stellaris ICDI Board
+ bd90 PICAXE Download Cable [AXE027]
bdc8 Egnite GmbH - JTAG/RS-232 adapter
bfd8 OpenDCC
bfd9 OpenDCC (Sniffer)
@@ -884,9 +889,11 @@
f0c8 SPROG Decoder Programmer
f0c9 SPROG-DCC CAN-USB
f0e9 Tagsys L-P101
+ f0ee Tagsys Medio P200x
f1a0 Asix PRESTO Programmer
f208 Papenmeier Braille-Display
f3c0 4N-GALAXY Serial Converter
+ f458 ABACUS ELECTRICS Optical Probe
f608 CTI USB-485-Mini
f60b CTI USB-Nano-485
f680 Suunto Sports Instrument
@@ -941,6 +948,7 @@
0103 FV TouchCam N1 (Audio)
030c HP Webcam
03b2 HP Webcam
+ 03f4 HP Webcam
1030 FV TouchCam N1 (Video)
3000 Optical dual-touch panel
3001 Optical Touch Screen
@@ -1191,6 +1199,7 @@
00da WLI-U2-KG54L 802.11bg [ZyDAS ZD1211B]
00db External Hard Drive HD-PF32OU2 [Buffalo Ministation]
00e8 WLI-UC-G300N Wireless LAN Adapter [Ralink RT2870]
+ 00f9 Portable DVD Writer (DVSM-PL58U2)
0105 External Hard Drive HD-CEU2 [Drive Station]
012c SATA Bridge
012e WLI-UC-AG300N Wireless LAN Adapter
@@ -1204,11 +1213,14 @@
019e WLI-UC-GNP Wireless LAN Adapter
01a1 MiniStation Metro
01a2 WLI-UC-GNM Wireless LAN Adapter [Ralink RT8070]
+ 01ba SATA Bridge
01dc Ultra-Slim Portable DVD Writer (DVSM-PC58U2V)
01de External Hard Drive HD-PCTU3 [Buffalo MiniStation]
+ 01ea SATA Bridge
01ee WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
01f1 SATA Adapter [HD-LBU3]
01fd WLI-UC-G450 Wireless LAN Adapter
+ 027e HD-LCU3
0412 Award Software International
0413 Leadtek Research, Inc.
1310 WinFast TV - NTSC + FM
@@ -1293,6 +1305,7 @@
041b d'TV
041d S3, Inc.
041e Creative Technology, Ltd
+ 0414 HS-720 Headset
1002 Nomad II
1003 Blaster GamePad Cobra
1050 GamePad Cobra
@@ -1318,6 +1331,7 @@
3121 WoW tap chat
3220 Sound Blaster Tactic(3D) Sigma sound card
3232 Sound Blaster Premium HD [SBX]
+ 3237 SB X-Fi Surround 5.1 Pro
3f00 E-Mu Xboard 25 MIDI Controller
3f02 E-Mu 0202
3f04 E-Mu 0404
@@ -1606,6 +1620,7 @@
2602 USB 2.0 Hub
2640 USB 2.0 Hub
2660 Hub
+ 2744 Hub
274d HTC Hub Controller
3fcc RME MADIface
4041 Hub and media card controller
@@ -1613,6 +1628,7 @@
4064 Ultra Fast Media Reader
5434 Hub
5534 Hub
+ 5744 Hub
7500 LAN7500 Ethernet 10/100/1000 Adapter
9500 LAN9500/LAN9500i
9512 SMC9512/9514 USB Hub
@@ -1902,12 +1918,15 @@
b323 Dual Trigger 3-in-1 (PC Mode)
b324 Dual Trigger 3-in-1 (PS3 Mode)
b326 Gamepad GP XID
+ b351 F16 MFD 1
+ b352 F16 MFD 2
b603 force feedback Wheel
b605 force feedback Racing Wheel
b651 Ferrari GT Rumble Force Wheel
b653 RGT Force Feedback Clutch Racing Wheel
b654 Ferrari GT Force Feedback Wheel
b678 T.Flight Rudder Pedals
+ b679 T-Rudder
b687 TWCS Throttle
b700 Tacticalboard
0450 DFI, Inc.
@@ -1937,6 +1956,7 @@
8140 TUSB8041 4-Port Hub
8142 TUSB8041 4-Port Hub
926b TUSB9260 Boot Loader
+ bef3 CC1352R1 Launchpad
dbc0 Device Bay Controller
e001 GraphLink [SilverLink]
e003 TI-84 Plus Calculator
@@ -2098,6 +2118,7 @@
5221 Rio Eigen
045b Hitachi, Ltd
0053 RX610 RX-Stick
+ 0229 mSATA Adapter [renkforce Pi-102]
045d Nortel Networks, Ltd
045e Microsoft Corp.
0007 SideWinder Game Pad
@@ -2382,6 +2403,7 @@
0797 Optical Mouse 200
0799 Surface Pro embedded keyboard
07a5 Wireless Receiver 1461C
+ 07b2 2.4GHz Transceiver v8.0 used by mouse Wireless Desktop 900
07b9 Wired Keyboard 200
07c6 RTL8153 GigE [Surface Dock Ethernet]
07ca Surface Pro 3 Docking Station Audio Device
@@ -2397,6 +2419,7 @@
090b Hub
090c SD Card
091a Hub
+ 09c0 Surface Type Cover
0a00 Lumia 950 Dual SIM (RM-1118)
930a ISOUSB.SYS Intel 82930 Isochronous IO Test Board
ffca Catalina
@@ -2464,6 +2487,9 @@
4d62 HP Laser Mobile Mini Mouse
4d75 Rocketfish RF-FLBTAD Bluetooth Adapter
4d81 Dell N889 Optical Mouse
+ 4d91 Laser mouse M-D16DL
+ 4d92 Optical mouse M-D17DR
+ 4db1 Dell Laptop Integrated Webcam 2Mpix
4de3 HP 5-Button Optical Comfort Mouse
4de7 webcam
4e04 Lenovo Keyboard KB1021
@@ -2525,6 +2551,7 @@
080f Webcam C120
0810 QuickCam Pro
0819 Webcam C210
+ 081a Webcam C260
081b Webcam C310
081d HD Webcam C510
0820 QuickCam VC
@@ -2727,7 +2754,9 @@
c07c M-R0017 [G700s Rechargeable Gaming Mouse]
c07d G502 Mouse
c07e G402 Gaming Mouse
+ c080 G303 Gaming Mouse
c083 G403 Prodigy Gaming Mouse
+ c084 G203 Gaming Mouse
c101 UltraX Media Remote
c110 Harmony 785/880/885 Remote
c111 Harmony 525 Remote
@@ -2824,9 +2853,11 @@
c31c Keyboard K120
c31d Media Keyboard K200
c31f Comfort Keyboard K290
+ c326 Washable Keyboard K310
c328 Corded Keyboard K280e
c332 G502 Proteus Spectrum Optical Mouse
c335 G910 Orion Spectrum Mechanical Keyboard
+ c33a G413 Gaming Keyboard
c401 TrackMan Marble Wheel
c402 Marble Mouse (2-button)
c403 Turbo TrackMan Marble FX
@@ -3158,6 +3189,7 @@
4254 BUA-100 Bluetooth Adapter
ac01 Savi 7xx
ad01 GameCom 777 5.1 Headset
+ af01 DA80
c008 Audio 655 DSP
c00e Blackwire C310 headset
0480 Toshiba America Inc
@@ -3167,11 +3199,13 @@
0014 InTouch Module
0100 Stor.E Slim USB 3.0
0200 External Disk
+ 0820 Canvio Advance Disk
a006 External Disk 1.5TB
a007 External Disk USB 3.0
a009 Stor.E Basics
a00d STOR.E BASICS 500GB
a100 Canvio Alu 2TB 2.5" Black External Disk Model HDTH320EK3CA
+ a102 Canvio Alu 2TB 2.5" Black External Disk Model HDTH320EK3CA
a202 Canvio Basics HDD
a208 Canvio Basics 2TB USB 3.0 Portable Hard Drive
b001 Stor.E Partner
@@ -3199,6 +3233,8 @@
0483 STMicroelectronics
0137 BeWAN ADSL USB ST (blue or green)
0138 Unicorn II (ST70138B + MTC-20174TQ chipset)
+ 0adb Android Debug Bridge (ADB) device
+ 0afb Android Fastboot device
1307 Cytronix 6in1 Card Reader
163d Cool Icam Digi-MP3
2015 TouchChip® Fingerprint Reader
@@ -3210,13 +3246,18 @@
3747 ST Micro Connect Lite
3748 ST-LINK/V2
374b ST-LINK/V2.1
+ 374d STLINK-V3 Loader
+ 374e STLINK-V3
+ 374f STLINK-V3
+ 3752 ST-LINK/V2.1
+ 3753 STLINK-V3
4810 ISDN adapter
481d BT Digital Access adapter
5000 ST Micro/Ergenic ERG BT-002 Bluetooth Adapter
5001 ST Micro Bluetooth Device
5710 Joystick in FS Mode
5720 Mass Storage Device
- 5721 Hantek DDS-3X25 Arbitrary Waveform Generator
+ 5721 Interrupt Demo
5722 Bulk Demo
5730 Audio Speaker
5731 Microphone
@@ -3713,6 +3754,7 @@
1787 PIXMA MX490 Series
178a PIXMA MG3600 Series
178d PIXMA MG6853
+ 180b PIXMA MG3000 series
1900 CanoScan LiDE 90
1901 CanoScan 8800F
1904 CanoScan LiDE 100
@@ -3844,6 +3886,7 @@
26b0 MF4600 series
26b4 MF4010 series
26b5 MF4200 series
+ 26b6 FAX-L140/L130
26da LBP3010B printer
26e6 iR1024
271a LBP6000
@@ -4151,18 +4194,27 @@
329c PowerShot SX400 IS
329d PowerShot G7 X
329f PowerShot SX530 HS
+ 32a0 EOS M10
32a6 PowerShot SX710 HS
+ 32a7 PowerShot SX610 HS
+ 32a8 PowerShot G3 X
32aa Powershot ELPH 160 / IXUS 160
32ab PowerShot ELPH 350HS / IXUS 275 HS
32ac PowerShot ELPH 170 IS / IXUS 170
32ad PowerShot SX410 IS
32b1 SELPHY CP1200
32b2 PowerShot G9 X
+ 32b3 PowerShot G5 X
32b4 EOS Rebel T6
32bb EOS M5
32bf PowerShot SX420 IS
32c1 PowerShot ELPH 180 / IXUS 175
32c2 PowerShot SX720 HS
+ 32c5 EOS M6
+ 32cc EOS 200D
+ 32d1 EOS M100
+ 32d2 EOS M50
+ 32d4 Powershot ELPH 185 / IXUS 185 / IXY 200
32d5 PowerShot SX430 IS
32db SELPHY CP1300
04aa DaeWoo Telecom, Ltd
@@ -4513,6 +4565,8 @@
0891 Stylus Office BX535WD
0892 Stylus Office BX935FWD
0893 EP-774A
+ 1114 XP-440 [Expression Home Small-in-One Printer]
+ 1129 ET-4750 [WorkForce ET-4750 EcoTank All-in-One]
04b9 Rainbow Technologies, Inc.
0300 SafeNet USB SuperPro/UltraPro
1000 iKey 1000 Token
@@ -4623,8 +4677,12 @@
10e1 fi-5220C
10e7 fi-5900C
10fe S500
+ 1104 KD02906 Line Thermal Printer
+ 114f fi-6130
1150 fi-6230
+ 11f3 fi-6130Z
125a PalmSecure Sensor Device - MP
+ 132e fi-7160
200f Sigma DP2 (Mass Storage)
2010 Sigma DP2 (PictBridge)
201d SATA 3.0 6Gbit/s Adaptor [GROOVY]
@@ -4808,6 +4866,7 @@
9004 Microchip REAL ICE
900a PICkit3
9012 PICkit4
+ 9015 ICD 4 In-Circuit Debugger
c001 PicoLCD 20x4
e11c TL866CS EEPROM Programmer [MiniPRO]
f2c4 Macareux-labs Hygrometry Temperature Sensor
@@ -4815,6 +4874,7 @@
f3aa Macareux-labs Usbce Bootloader mode
f437 SBE Tech Ultrasonic Anemometer
f4b5 SmartScope
+ f5fe TrueRNG
f8da Hughski Ltd. ColorHug
f8e8 Harmony 300/350 Remote
f91c SPROG IIv3
@@ -4846,6 +4906,7 @@
2519 Shenzhen LogoTech 2.4GHz receiver
2832 HT82A832R Audio MCU
2834 HT82A834R Audio MCU
+ 4545 Keyboard [Diatec Majestouch 2 Tenkeyless]
a01c wireless multimedia keyboard with trackball [Trust ADURA 17911]
a050 Chatman V1
a052 USB-zyTemp
@@ -4865,6 +4926,7 @@
0d0a CD-R Drive KXL-CB20AN
0d0d CDRCB03
0d0e DVD-ROM & CD-R/RW
+ 0d14 DVD-RAM MLT08
0f07 KX-MB2030 Multifunction Laser Printer
0f40 Printer
104d Elite Panaboard UB-T880 (HID)
@@ -5235,8 +5297,8 @@
685c GT-I9250 Phone [Galaxy Nexus] (Mass storage mode)
685d GT-I9100 Phone [Galaxy S II] (Download mode)
685e GT-I9100 / GT-C3350 Phones (USB Debugging mode)
- 6860 Galaxy (MTP)
- 6863 GT-I9500 [Galaxy S4] / GT-I9250 [Galaxy Nexus] (network tethering)
+ 6860 Galaxy series, misc. (MTP mode)
+ 6863 Galaxy series, misc. (tethering mode)
6864 GT-I9070 (network tethering, USB debugging enabled)
6865 Galaxy (PTP mode)
6866 Galaxy (debugging mode)
@@ -5256,6 +5318,7 @@
7080 Anycall SCH-W580
7081 Human Interface Device
8001 Handheld
+ d003 GT-I9003
e020 SERI E02 SCOM 6200 UMTS Phone
e021 SERI E02 SCOM 6200 Virtual UARTs
e022 SERI E02 SCOM 6200 Flash Load Disk
@@ -5376,8 +5439,10 @@
b3fd HD WebCam (Asus N-series)
b40e HP Truevision HD camera
b444 Lenovo Integrated Webcam
+ b563 Integrated Camera
b5ce Integrated Camera
b5cf Integrated IR Camera
+ b5db HP Webcam
04f3 Elan Microelectronics Corp.
000a Touchscreen
0103 ActiveJet K-2024 Multimedia Keyboard
@@ -5953,6 +6018,7 @@
04fd Soliton Systems, K.K.
0003 Smart Card Reader II
04fe PFU, Ltd
+ 0006 Happy Hacking Keyboard Lite2
04ff E-CMOS Corp.
0500 Siam United Hi-Tech
0001 DART Keyboard Mouse
@@ -6044,6 +6110,7 @@
0257 F5U257 Serial
0304 FSU304 USB 2.0 - 4 Ports Hub
0307 USB 2.0 - 7 ports Hub [FSU307]
+ 038c F2CU038 HDMI Adapter
0409 F5U409 Serial
0416 Staples 12416 7 port desktop hub
0551 F6C550-AVR UPS
@@ -6484,6 +6551,7 @@
07c4 ILCE-6000 (aka Alpha-6000) in Mass Storage mode
082f Walkman NWZW Series
0847 WG-C10 Portable Wireless Server
+ 0884 MDR-ZX770BN [Wireless Noise Canceling Stereo Headset]
088c Portable Headphone Amplifier
08b7 ILCE-6000 (aka Alpha-6000) in MTP mode
094e ILCE-6000 (aka Alpha-6000) in PC Remote mode
@@ -6491,6 +6559,10 @@
09cc DualShock 4 [CUH-ZCT2x]
0ba0 Dualshock4 Wireless Adaptor
0bb5 Headset MDR-1000X
+ 0c02 ILCE-7M3 [A7III] in Mass Storage mode
+ 0c03 ILCE-7M3 [A7III] in MTP mode
+ 0c34 ILCE-7M3 [A7III] in PC Remote mode
+ 0cda PlayStation Classic controller
1000 Wireless Buzz! Receiver
054d Try Corp.
054e Proside Corp.
@@ -6647,7 +6719,9 @@
2802 Kbd Hub
3002 Keyboard
3004 Genius KB-29E
+ 3027 Sun-Flex ProTouch
3107 Keyboard
+ 3132 Optical mouse M-DY4DR / M-DY6DR
4006 FID 638 Mouse (Sun Microsystems)
0567 Xyratex International, Ltd
0568 Quartz Ingenierie
@@ -6812,6 +6886,7 @@
038d DTH-3220 [Cintiq Pro 32] internal hub
038e DTH-3220 [Cintiq Pro 32] external hub
038f DTH-3220 [Cintiq Pro 32] internal hub
+ 0390 DTK-1660 [Cintiq 16]
0400 PenPartner 4x5
4001 TPC4001
4004 TPC4004
@@ -6832,18 +6907,21 @@
0003 Device Bay Controller
056e Elecom Co., Ltd
0002 29UO Mouse
- 0057 M-PGDL Mouse
- 005c M-PGDL Mouse
- 005d M-FGDL Mouse
- 005e M-FG2DL Mouse
- 0062 M-D18DR Mouse
- 0063 M-SODL Mouse
- 0069 M-GE1UL Mouse
- 0071 M-GE3DL Mouse
- 0072 M-LS6UL Mouse
- 0073 M-LS7UL Mouse
- 0074 M-FW1UL Mouse
- 0075 M-FW2DL Mouse
+ 0057 Micro Grast Pop M-PGDL
+ 005c Micro Grast Pop M-PG2DL
+ 005d Micro Grast Fit M-FGDL
+ 005e Micro Grast Fit M-FG2DL
+ 0062 Optical mouse M-D18DR
+ 0063 Laser mouse M-SODL
+ 0069 Laser mouse M-GE1UL
+ 0071 Laser mouse M-GE3DL
+ 0072 Laser mouse M-LS6UL
+ 0073 Laser mouse M-LS7UL
+ 0074 Optical mouse M-FW1UL
+ 0075 Laser mouse M-FW2DL
+ 0077 Laser mouse M-LY2UL
+ 2003 JC-U3613M
+ 2004 JC-U3613M
200c LD-USB/TX
4002 Laneed 100Mbps Ethernet LD-USB/TX [pegasus]
4005 LD-USBL/TX
@@ -15328,43 +15406,251 @@
02df Serial cable (v2) for TD-10 Mobile Phone
1203 TSC Auto ID Technology Co., Ltd
0140 TTP-245C
-1209 InterBiometrics
- 1001 USB Hub
- 1002 USB Relais
- 1003 IBSecureCam-P
- 1004 IBSecureCam-O
- 1005 IBSecureCam-N
- 1006 Mini IO-Board
+1209 Generic
+ 0001 pid.codes Test PID
+ 01c0 Input Club Kiibohd Device
+ 01cb Input Club Kiibohd Device Bootloader
+ 0256 Schwalm & Tate LLC pISO Raspberry Pi Hat
+ 053a Hackerspace San Salvador HSSV SAMR21-Mote
+ 0cbd Andrzej Szombierski kuku.eu.org keyboard
+ 0d32 ODrive Robotics ODrive v3
+ 1001 InterBiometrics Hub
+ 1002 InterBiometrics Relais
+ 1003 InterBiometrics IBSecureCam-P
+ 1004 InterBiometrics IBSecureCam-O
+ 1005 InterBiometrics IBSecureCam-N
+ 1006 InterBiometrics Mini IO-Board
+ 1007 e-radionica.com Croduino SAMD
+ 1986 dgrubb Jaguar Tap
1ab5 Arachnid Labs Tsunami
+ 1ab6 Arachnid Labs Tsunami Bootloader
2000 Zygmunt Krynicki Lantern Brightness Sensor
+ 2001 OSHEC Pi-pilot opensource and openhardware autopilot system
+ 2002 Peter Lawrence PIC16F1-USB-DFU-Bootloader
+ 2003 Peter Lawrence SAMDx1-USB-DFU-Bootloader
+ 2004 GCBASIC Serial CDC Stack
+ 2005 GCBASIC OakTree Stack
+ 2006 GCBASIC Simulation Stack
+ 2016 Cupkee
+ 2017 Benjamin Shockley Mini SAM
+ 2020 Captain Credible Gate Crystal
2048 Housedillon.com MRF49XA Transciever
+ 2100 TinyFPGA B1 and B2 Boards
+ 2101 TinyFPGA A-Series Programmer
+ 2200 Dygma Shortcut Bootloader
+ 2201 Dygma Shortcut Keyboard
2222 LabConnect Signalgenerator
- 2300 Keyboardio Keyboardio Model 01 Bootloader
- 2301 Keyboardio Keyboardio Model 01
- 2327 K.T.E.C.Bootloader Device
+ 2300 Keyboardio Model 01 Bootloader
+ 2301 Keyboardio Model 01
+ 2323 bytewerk.org candleLight
+ 2327 K.T.E.C. Bootloader Device
2328 K.T.E.C. Keyboard Device
- 2337 /Dev or SlashDev /Net
+ 2333 Kai Ryu Kimera
+ 2334 Kai Ryu Staryu
+ 2335 Portwell Sense8
+ 2336 Portwell Sense8
+ 2337 /Dev /Net
+ 2342 Andreas Bogk Big Red Button
+ 2345 VV-Soft Simple Generic HID IO
+ 2357 KarolKucza TinyPassword
+ 2400 phooky Snap-Pad
+ 2488 Peter Lawrence CMSIS-DAP Dapper Miser
+ 2552 ProjectIota Electrolink
+ 2600 Majenko Technologies chipKIT Lenny
+ 2635 Sevinz GameBot
+ 2800 Entropic Engineering Triangulation
+ 2801 Entropic Engineering Object Manipulation
+ 2a00 mooware Wii adapter
+ 2a01 mooware SNES adapter
3000 lloyd3000
+ 3100 OpenSimHardware Pedals & Buttons Controller
+ 317e Codecrete Wirekite
+ 3210 OSH Lab, LLC Magic Keys
3333 LabConnect Digitalnetzteil
+ 3690 Kigakudoh TouchMIDI32
+ 4096 CynaraKrewe Cynara
+ 414c Adi Linden
+ 414d Adi Linden
+ 4242 Komakallio Astrophotography Community KomaHub Remote Power Switch
+ 4256 CuVoodoo BusVoodoo multi-protocol debugging adapter
+ 4321 mooltipass Offline Password Keeper Bootloader
+ 4322 mooltipass Arduino Sketch
+ 4356 CuVoodoo firmware
+ 4443 j1rie IRMP_STM32 Bootloader
+ 4444 j1rie IRMP_STM32
+ 4545 SlothCo Enterprises Teletype Adapter
+ 4646 SmartPID SPC1000
+ 4748 Kate Gray GHETT-iO Bootloader
+ 4750 Chris Pavlina (c4757p) C4-x computer (development interface)
+ 4757 Chris Pavlina (c4757p) WCP52 Gain/Phase Analyzer
+ 4801 Wojciech Krutnik NVMemProg
+ 4c60 MightyPork GEX module
+ 4c61 MightyPork GEX wireless dongle
+ 4d53 mindsensors.com NXTCam5
+ 5038 frotz.net mdebug rswd protocol
+ 5039 frotz.net lpcboot protocol
+ 5050 trebb ISO50
5222 telavivmakers attami
53c0 SatoshiLabs TREZOR Bootloader
53c1 SatoshiLabs TREZOR
+ 5432 Open Programmer
+ 5457 Openlab.Taipei Taiwanduino
+ 571c StreetoArcade PancadariaStick
5a22 ikari_01 sd2snes
- 7530 Refflion - IoT Board - Bootloader
- 7531 Refflion - IoT Board - Sketch
+ 6000 Pulsar Heavy Industries Cenx4
+ 600d Makdaam N93 Interface
+ 6464 Electric Exploits Shinewave
+ 6502 jj1bdx avrhwrng v2rev1
+ 6570 Iowa Scaled Engineering, LLC CKT-AVRPROGRAMMER
+ 6666 Talpa Chen VSFLogic
+ 6667 SensePost Universal Serial aBUSe - Generic HID
+ 6742 NPK Cubitel Atomic Force Microscope
+ 6809 Tach Radio Doppelganger
+ 6948 MySensors Sensebender Gateway BootLoader
+ 6949 MySensors Sensebender Gateway
+ 6bcf blaste Gameboy Cart Flasher
+ 7000 Secalot Dongle
+ 7001 Secalot Bootloader
+ 70b1 Sutajio Ko-Usagi (Kosagi) Tomu
+ 7331 Dangerous Prototypes Bus Pirate Next Gen CDC
+ 7332 Dangerous Prototypes Bus Pirate Next Gen Logic Analyzer
+ 7401 Beststream-jp Tool_CDC
+ 7530 PotentialLabs Refflion - IoT Development Board - Bootloader
+ 7531 PotentialLabs Refflion - IoT Development Board - Sketch
+ 7551 The Tessel Project Tessel 2
+ 7777 circuitvalley IO Board V3
+ 7778 circuitvalley IO Board V3 Bootloader
7bd0 pokey9000 Tiny Bit Dingus
- abd0 tibounise ADB converter
- aced Open Lighting Project - Ja Rule Device
- acee Open Lighting Project - Ja Rule Bootloader
+ 8000 Autonomii NODii 2
+ 8086 MisfitTech Nano Zero Bootloader
+ 8087 MisfitTech Nano Zero
+ 8123 Danyboard M0 bootloader
+ 812a Danyboard M0
+ 813a MickMad HACK Bootloader
+ 813b MickMad HACK Sketch
+ 8242 Tom Wimmenhove Electronics NBS-DAC 192/24 UAC1
+ 8243 Tom Wimmenhove Electronics NBS-DAC 192/24 UAC2
+ 8472 Shantea Controls OpenDeck
+ 8661 ProgHQ TL866 programmer
+ 8844 munia.io MUNIA
+ 8888 Blinkinlabs POV Pendant
+ 8889 Blinkinlabs POV Pendant (bootloader)
+ 8b00 ReSwitched Libtransistor Serial Console
+ 9021 Connected Community Hackerspace ESPlant
+ 9317 Sutajio Ko-Usagi (Kosagi) Palawan-Tx
+ 9999 Sandeepan Sengupta CodeBridge Infineo
+ 9db5 PD Buddy Sink
+ a033 area0x33 Memtype
+ a100 KB LES Narsil analog breakout
+ a10c KB LES Aminoacid Synthesizer
+ a1e5 Atreus Keyboards Atreus Keyboard
+ a3a4 MK::Box MK::Kbd
+ a3a5 MK::Box MK::Kbd Bootloader
+ a55a Forever Young Software ATTINY2313
+ a602 Robotips RTBoard
+ a7ea area3001 Knixx SW04
+ a800 sowbug.com WebLight
+ a8b0 Intelectron BootWare
+ a8b1 Intelectron FrameWare
+ aa00 Serg Oskin LinuxCNC HID Extender
+ aa0b Open Bionics
+ ab3d 3DArtists Alligator board
+ abba CoinWISE SafeWISE
+ abc0 Omzlo controller
+ abcd Sandeepan Sengupta CodeBridge
+ abd1 OpenMV Cam
+ acdc Gediminas Zukaitis midi-grid
+ ace5 SimAces Panel Ace
+ aced Open Lighting Project Ja Rule Device
+ acee Open Lighting Project Ja Rule Bootloader
+ adb0 tibounise ADB converter
+ adda MicroPython Boards
+ b007 Konsgn Global_Boot
+ b00b CrapLab Random Device
+ b010 IObitZ CodeBridge
+ b01d WyoLum VeloKey
+ b058 Model B, LLC Holoseat
+ b0b0 Monero Hardware Monero Bootloader
+ b100 ptrandem iBizi
+ b101 IObitZ Infineo
+ b195 flehrad Big Switch PCB
+ bab1 ElectronicCats Meow Meow
+ babe brunofreitas.com STM32 HID Bootloader
+ bad1 Gregory POTEAU CommLinkUSB
+ bad2 Gregory POTEAU XLinkUSB
+ bade Semarme SemarmeHID
+ bb00 keyplus split keyboard firmware
+ bb01 keyplus xusb bootloader
+ bb02 keyplus nRF24 wireless keyboard dongle
+ bb03 keyplus nrf24lu1p-512 bootloader
+ bb05 keyplus kp_boot_32u4 bootloader
+ beba serasidis.gr STM32 HID Bootloader
beef Modal MC-USB
+ c001 Cynteract Alpha
+ c0c0 Geppetto_Electronics Orthrus
+ c0c1 Michael Bemmerl cookie-mouse
+ c0ca Jean THOMAS DirtyJTAG
+ c0d3 Samy Kamkar USBdriveby
+ c0da Monero Hardware Monero Firmware
+ c0de KMRH Labs SBL Brain
c0f5 unethi PERswitch
- ca1c KnightOS Hub
+ c1aa Proyecto CIAA Computadora Industrial Abierta Argentina
+ c1b1 Chibitronics Love-to-Code
+ c311 bg nerilex GB-USB-Link
+ ca1c KnightOS Generic Hub
ca1d KnightOS MTP Device
+ caea Open Music Kontrollers Chimaera
cafe ii iigadget
+ cc14 trebb NaN-15
+ cc86 Manfred's Technologies Anastasia Bootloader
+ ceb0 KG4LNE GE-FlashUSB
+ cf20 Smart Citizen SCK 2.0
+ d00d Monero Hardware Monero Developer
+ d017 empiriKit empiriKit Controller
+ d11d Koi Science DI-Lambda AVR
+ d3d8 Duet3d Duet 0.8.5
+ d706 SkyBean SkyDrop
+ da42 Devan Lai dap42 debug access probe
+ daa0 darknao btClubSportWheel
dada Rebel Technology OWL
+ db42 Devan Lai dapboot DFU bootloader
+ dc21 FPGA-Computer Dual Charger
+ dddd Stephan Electronics OpenCVMeter
dead chaosfield.at AVR-Ruler
+ deaf CrapLab 4chord MIDI
+ ded1 ManCave Made Quark One
+ df00 D.F.Mac. @TripArts Music mi:muz:tuch
+ df01 D.F.Mac. @TripArts Music mi:muz:can
+ df02 D.F.Mac. @TripArts Music mi:muz:can-lite
+ e116 Elijah Motornyy open-oscilloscope-stm32f3
+ e1ec FreeSRP
+ e4ee trebb keytee
+ e500 GitleMikkelsen Helios Laser DAC
+ eaea Pinscape Controller
+ eb01 RobotMaker.club EB1
+ eba7 VictorGrigoryev USBscope
+ ee00 Explore Embedded SODA(SWD OpenSource Debug Adapter)
+ ee02 Explore Embedded Explore M3 VCOM
+ ee03 Explore Embedded Explore M3 DFU
+ ee2c jaka USB2RS485
+ effa EffigyLabs atmega32u4-USB-LUFA-Bootloader
+ effe EffigyLabs Control Pedal
+ f000 Uniti ARC
+ f00d RomanStepanov Shifter/Pedals Adapter
+ f12e Michael Bemmerl Feuermelder
+ f16a uri_ba Cougar TQS adapter
+ f16c uri_ba adapter for Vipercore's FCC3 Force Sensing Module
+ f380 Windsor Schmidt MD-380 Open Radio Firmware
+ f3fc dRonin Flight controller-Lumenier Lux
+ f49a TimVideos.us & HDMI2USB.tv Projects FPGA Programmer & UART Bridge (PIC based Firmware)
fa11 moonglow OpenXHC
+ fa57 3DRacers Pilot Board
+ fa58 3DRacers Pilot Board (Bootloader)
+ fab1 PAP Mechatronic Technology LamDiNao
+ face Protean Synth Craft
+ fade Open Collector dude
feed ProgramGyar AVR-IR Sender
+ ffff Life2Device Smart House
120e Hudson Soft Co., Ltd
120f Magellan
524e RoadMate 1475T
@@ -18765,6 +19051,9 @@
22b9 eTurboTouch Technology, Inc.
0006 Touch Screen
22ba Technology Innovation Holdings, Ltd
+22e0 secunet Security Networks AG
+ 0002 SINA Flash Drive
+ 0003 SINA ID Token A
2304 Pinnacle Systems, Inc.
0109 Studio PCTV USB (SECAM)
0110 Studio PCTV USB (PAL)
@@ -18901,6 +19190,21 @@
1213 MediaTV Pro III MiniPCIe (US)
2676 Basler AG
ba02 ace
+2717 Xiaomi Inc.
+ 0011 100Mbps Network Card Adapter
+ 0360 Mi3W
+ 0368 Mi4 LTE
+ 3801 Mi ANC & Type-C In-Ear Earphones
+ 4106 MediaTek MT7601U [MI WiFi]
+ ff08 Redmi Note 3 (ADB Interface)
+ ff10 Mi/Redmi series (PTP)
+ ff18 Mi/Redmi series (PTP + ADB)
+ ff40 Mi/Redmi series (MTP)
+ ff48 Mi/Redmi series (MTP + ADB)
+ ff60 redmi prime 2
+ ff68 Mi-4c
+ ff80 Mi/Redmi series (RNDIS)
+ ff88 Mi/Redmi series (RNDIS + ADB)
2730 Citizen
200f CT-S310 Label printer
2735 DigitalWay
@@ -19029,6 +19333,15 @@
200b MX Phone (PTP)
200c MX Phone (PTP & ADB)
2012 MX Phone (MTP & ACM)
+2ac7 Ultrahaptics Ltd.
+ 0101 Evaluation Kit [Dragonfly]
+ 0102 UHDK5
+ 0104 Touchbase
+ 0110 STRATOS Explore
+ 0111 STRATOS Explore DFU
+ 0112 STRATOS Inspire
+ 0113 STRATOS Inspire DFU
+ ffff DFU
2b24 KeepKey LLC
0001 Bitcoin hardware wallet
2c02 Planex Communications
@@ -19048,6 +19361,8 @@
2fb2 Fujitsu, Ltd
3016 Boundary Devices, LLC
0001 Nitrogen Bootloader
+30ee Fujitsu Connected Technologies Limited
+ 1001 F-01L
3125 Eagletron
0001 TrackerPod Camera Stand
3136 Navini Networks
diff --git a/usr/src/head/floatingpoint.h b/usr/src/head/floatingpoint.h
index 1935b611c6..c8d658cc83 100644
--- a/usr/src/head/floatingpoint.h
+++ b/usr/src/head/floatingpoint.h
@@ -62,8 +62,6 @@ extern "C" {
typedef __FILE FILE;
#endif
-#define N_IEEE_EXCEPTION 5 /* Number of floating-point exceptions. */
-
typedef int sigfpe_code_type; /* Type of SIGFPE code. */
typedef void (*sigfpe_handler_type)(); /* Pointer to exception handler */
diff --git a/usr/src/head/signal.h b/usr/src/head/signal.h
index 3848a93f2c..042372d679 100644
--- a/usr/src/head/signal.h
+++ b/usr/src/head/signal.h
@@ -70,7 +70,7 @@ extern const int _sys_siglistn; /* # of signal descriptions */
extern int kill(pid_t, int);
extern int sigaction(int, const struct sigaction *_RESTRICT_KYWD,
struct sigaction *_RESTRICT_KYWD);
-#ifndef _KERNEL
+#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
extern int sigaddset(sigset_t *, int);
extern int sigdelset(sigset_t *, int);
extern int sigemptyset(sigset_t *);
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index a6877bb589..d271ff0211 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -22,7 +22,7 @@
#
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012 by Delphix. All rights reserved.
-# Copyright 2018, Joyent, Inc.
+# Copyright 2019, Joyent, Inc.
# Copyright (c) 2013 Gary Mills
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
# Copyright (c) 2015 Gary Mills
@@ -271,6 +271,7 @@ SUBDIRS += \
rpcsec_gss \
sasl_plugins \
scsi \
+ smbclnt \
smbsrv \
smhba \
sun_fc \
@@ -722,6 +723,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/brand/lx/testing/Readme_ltp b/usr/src/lib/brand/lx/testing/Readme_ltp
index 4a2fcd353b..5165546c1a 100644
--- a/usr/src/lib/brand/lx/testing/Readme_ltp
+++ b/usr/src/lib/brand/lx/testing/Readme_ltp
@@ -19,6 +19,7 @@ Additional prerequisites are required activate some tests:
As a normal user:
git clone https://github.com/linux-test-project/ltp.git
cd ltp
+ git checkout ed01f6a05c77f65cb5d1089474c9a0e2129c581a
make autotools
./configure
make all
@@ -50,7 +51,7 @@ which now work.
As root:
cd /opt/ltp
/opt/ltp/runltp -f `cat /native/usr/lib/brand/lx/ltp_tests` \
- -S /native/usr/lib/brand/lx/ltp_skiplist -p >/tmp/test.log
+ -S /native/usr/lib/brand/lx/ltp_skiplist -p >/tmp/test.log 2>&1
When the test run has finished, the results will be logged in a date/time
stamped file under /opt/ltp/results. The summary at the end of the log file
diff --git a/usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c b/usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c
index ad4dcd6dd3..b30433c2be 100644
--- a/usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c
+++ b/usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c
@@ -23,6 +23,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <sys/param.h>
@@ -1745,7 +1746,7 @@ cfga_msg(struct cfga_msg *msgp, const char *str)
}
(void) strcpy(q, str);
- (*msgp->message_routine)(msgp->appdata_ptr, q);
+ (void) (*msgp->message_routine)(msgp->appdata_ptr, q);
free(q);
}
diff --git a/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c b/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c
index 81f62ad0cf..e999d0e217 100644
--- a/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c
+++ b/usr/src/lib/fm/libdiskstatus/common/ds_scsi_uscsi.c
@@ -22,10 +22,9 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2019, Joyent, Inc.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This file contains routines for sending and receiving SCSI commands. The
* higher level logic is contained in ds_scsi.c.
@@ -99,7 +98,7 @@ static slist_t mode_select_strings[] = {
};
static slist_t sensekey_strings[] = {
- { "No sense error", KEY_NO_SENSE },
+ { "No sense error", KEY_NO_SENSE },
{ "Recoverable error", KEY_RECOVERABLE_ERROR },
{ "Not ready error", KEY_NOT_READY },
{ "Medium error", KEY_MEDIUM_ERROR },
@@ -1244,6 +1243,19 @@ uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
*/
hdr = (struct mode_header *)mode_sense_buf;
(void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
+
+ /*
+ * Check to see if we have a valid header length. We've occasionally
+ * seen hardware return zero here, even though they filled in the media
+ * type.
+ */
+ if (hdr->length == 0) {
+ dprintf("\nMode sense page 0x%x: has header length for zero\n",
+ hdr->length);
+ ddump("Mode sense:", mode_sense_buf, nbytes);
+ return (-1);
+ }
+
if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
hdr->bdesc_length != 0) {
dprintf("\nMode sense page 0x%x: block descriptor "
@@ -1259,6 +1271,13 @@ uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
if (page_code == MODEPAGE_ALLPAGES) {
/* special case */
+ if ((hdr->length + sizeof (header->ms_header.length)) <
+ (MODE_HEADER_LENGTH + hdr->bdesc_length)) {
+ dprintf("\nHeader length would spiral into a "
+ "negative bcopy\n");
+ return (-1);
+ }
+
(void) memcpy(page_data, (caddr_t)pg,
(hdr->length + sizeof (header->ms_header.length)) -
(MODE_HEADER_LENGTH + hdr->bdesc_length));
diff --git a/usr/src/lib/fm/topo/libtopo/Makefile.com b/usr/src/lib/fm/topo/libtopo/Makefile.com
index c0c164fa18..4f397a589e 100644
--- a/usr/src/lib/fm/topo/libtopo/Makefile.com
+++ b/usr/src/lib/fm/topo/libtopo/Makefile.com
@@ -76,6 +76,7 @@ SRCDIR = ../common
CLEANFILES += $(SRCDIR)/topo_error.c $(SRCDIR)/topo_tables.c
CPPFLAGS += -I../common -I$(ADJUNCT_PROTO)/usr/include/libxml2 -I.
+CSTD = $(CSTD_GNU99)
CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS)
CFLAGS += -D_POSIX_PTHREAD_SEMANTICS
CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS)
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c b/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c
index d7edbc31e7..768d47d182 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c
@@ -45,8 +45,15 @@
* 10 bytes for base-10 value + 1 for sign + nul
*/
#define INT32BUFSZ 12
-/* 2 bytes for "0x" + 16 bytes for the hex value + 1 for sign + nul */
-#define INT64BUFSZ 20
+/*
+ * Buffer that is large enough to hold the string representation of any signed
+ * or unsigned 64-bit integer.
+ *
+ * 2 bytes for "0x" + 16 bytes for the base-16 value + nul
+ * or
+ * 19 bytes for base-10 value + 1 for sign + nul
+ */
+#define INT64BUFSZ 21
#define XML_VERSION "1.0"
static int txml_print_range(topo_hdl_t *, FILE *, tnode_t *, int);
@@ -115,129 +122,240 @@ txml_print_prop(topo_hdl_t *thp, FILE *fp, tnode_t *node, const char *pgname,
topo_propval_t *pv)
{
int err;
- char *fmri = NULL;
- char vbuf[INT64BUFSZ], tbuf[32], *pval = NULL, *aval = NULL;
+ uint_t nelem;
+ char vbuf[INT64BUFSZ];
switch (pv->tp_type) {
case TOPO_TYPE_INT32: {
int32_t val;
+
if (topo_prop_get_int32(node, pgname, pv->tp_name, &val,
- &err) == 0) {
- (void) snprintf(vbuf, INT64BUFSZ, "%d", val);
- (void) snprintf(tbuf, sizeof (tbuf), "%s",
- Int32);
- pval = vbuf;
- } else
+ &err) != 0)
return;
+
+ (void) snprintf(vbuf, INT64BUFSZ, "%d", val);
+ begin_end_element(fp, Propval, Name, pv->tp_name, Type,
+ Int32, Value, vbuf, NULL);
break;
}
case TOPO_TYPE_UINT32: {
uint32_t val;
+
if (topo_prop_get_uint32(node, pgname, pv->tp_name,
- &val, &err) == 0) {
- (void) snprintf(vbuf, INT64BUFSZ, "0x%x", val);
- (void) snprintf(tbuf, sizeof (tbuf), "%s",
- UInt32);
- pval = vbuf;
- } else
+ &val, &err) != 0)
return;
+
+ (void) snprintf(vbuf, INT64BUFSZ, "0x%x", val);
+ begin_end_element(fp, Propval, Name, pv->tp_name, Type,
+ UInt32, Value, vbuf, NULL);
break;
}
case TOPO_TYPE_INT64: {
int64_t val;
+
if (topo_prop_get_int64(node, pgname, pv->tp_name, &val,
- &err) == 0) {
- (void) snprintf(vbuf, INT64BUFSZ, "0x%llx",
- (longlong_t)val);
- (void) snprintf(tbuf, sizeof (tbuf), "%s",
- Int64);
- pval = vbuf;
- } else
+ &err) != 0)
return;
+
+ (void) snprintf(vbuf, INT64BUFSZ, "%" PRId64, val);
+ begin_end_element(fp, Propval, Name, pv->tp_name, Type,
+ Int64, Value, vbuf, NULL);
break;
}
case TOPO_TYPE_UINT64: {
uint64_t val;
+
if (topo_prop_get_uint64(node, pgname, pv->tp_name,
- &val, &err) == 0) {
- (void) snprintf(vbuf, INT64BUFSZ, "0x%llx",
- (u_longlong_t)val);
- (void) snprintf(tbuf, sizeof (tbuf), "%s",
- UInt64);
- pval = vbuf;
- } else
+ &val, &err) != 0)
return;
+
+ (void) snprintf(vbuf, INT64BUFSZ, "0x%" PRIx64, val);
+ begin_end_element(fp, Propval, Name, pv->tp_name, Type,
+ UInt64, Value, vbuf, NULL);
+ break;
+ }
+ case TOPO_TYPE_DOUBLE: {
+ double val;
+ char *dblstr = NULL;
+
+ if (topo_prop_get_double(node, pgname, pv->tp_name,
+ &val, &err) != 0)
+ return;
+
+ /*
+ * The %a format specifier allows floating point values
+ * to be serialized without losing precision.
+ */
+ if (asprintf(&dblstr, "%a", val) < 0)
+ return;
+ begin_end_element(fp, Propval, Name, pv->tp_name, Type,
+ Double, Value, dblstr, NULL);
+ free(dblstr);
break;
}
case TOPO_TYPE_STRING: {
+ char *strbuf = NULL;
+
if (topo_prop_get_string(node, pgname, pv->tp_name,
- &pval, &err) != 0)
+ &strbuf, &err) != 0)
return;
- (void) snprintf(tbuf, sizeof (tbuf), "%s", "string");
+
+ begin_end_element(fp, Propval, Name, pv->tp_name, Type,
+ String, Value, strbuf, NULL);
+ topo_hdl_strfree(thp, strbuf);
break;
}
case TOPO_TYPE_FMRI: {
- nvlist_t *val;
+ nvlist_t *val = NULL;
+ char *fmristr = NULL;
if (topo_prop_get_fmri(node, pgname, pv->tp_name, &val,
- &err) == 0) {
- if (topo_fmri_nvl2str(thp, val, &fmri, &err)
- == 0) {
- nvlist_free(val);
- pval = fmri;
- } else {
- nvlist_free(val);
- return;
- }
- } else
+ &err) != 0 ||
+ topo_fmri_nvl2str(thp, val, &fmristr, &err) != 0) {
+ nvlist_free(val);
return;
- (void) snprintf(tbuf, sizeof (tbuf), "%s", FMRI);
+ }
+ nvlist_free(val);
+ begin_end_element(fp, Propval, Name, pv->tp_name, Type,
+ FMRI, Value, fmristr, NULL);
+ topo_hdl_strfree(thp, fmristr);
+ break;
+ }
+ case TOPO_TYPE_INT32_ARRAY: {
+ int32_t *val;
+
+ if (topo_prop_get_int32_array(node, pgname,
+ pv->tp_name, &val, &nelem, &err) != 0)
+ return;
+
+ begin_element(fp, Propval, Name, pv->tp_name, Type,
+ Int32_Arr, NULL);
+
+ for (uint_t i = 0; i < nelem; i++) {
+ (void) snprintf(vbuf, INT64BUFSZ, "%d", val[i]);
+ begin_end_element(fp, Propitem, Value, vbuf,
+ NULL);
+ }
+
+ topo_hdl_free(thp, val, nelem * sizeof (int32_t));
+ end_element(fp, Propval);
break;
}
case TOPO_TYPE_UINT32_ARRAY: {
uint32_t *val;
- uint_t nelem, i;
+
if (topo_prop_get_uint32_array(node, pgname,
pv->tp_name, &val, &nelem, &err) != 0)
return;
- if (nelem > 0) {
- if ((aval = calloc((nelem * 9 - 1),
- sizeof (uchar_t))) == NULL) {
-
- topo_hdl_free(thp, val,
- nelem * sizeof (uint32_t));
- return;
- }
-
- (void) sprintf(aval, "0x%x", val[0]);
- for (i = 1; i < nelem; i++) {
- (void) sprintf(vbuf, " 0x%x", val[i]);
- (void) strcat(aval, vbuf);
- }
- topo_hdl_free(thp, val,
- nelem * sizeof (uint32_t));
- (void) snprintf(tbuf, sizeof (tbuf), "%s",
- UInt32_Arr);
- pval = aval;
+ begin_element(fp, Propval, Name, pv->tp_name, Type,
+ UInt32_Arr, NULL);
+
+ for (uint_t i = 0; i < nelem; i++) {
+ (void) snprintf(vbuf, INT64BUFSZ, "0x%x",
+ val[i]);
+ begin_end_element(fp, Propitem, Value, vbuf,
+ NULL);
}
+
+ topo_hdl_free(thp, val, nelem * sizeof (uint32_t));
+ end_element(fp, Propval);
break;
}
- default:
- return;
- }
+ case TOPO_TYPE_INT64_ARRAY: {
+ int64_t *val;
- begin_end_element(fp, Propval, Name, pv->tp_name, Type, tbuf,
- Value, pval, NULL);
+ if (topo_prop_get_int64_array(node, pgname,
+ pv->tp_name, &val, &nelem, &err) != 0)
+ return;
+
+ begin_element(fp, Propval, Name, pv->tp_name, Type,
+ Int64_Arr, NULL);
+
+ for (uint_t i = 0; i < nelem; i++) {
+ (void) snprintf(vbuf, INT64BUFSZ, "%" PRId64,
+ val[i]);
+ begin_end_element(fp, Propitem, Value, vbuf,
+ NULL);
+ }
+
+ topo_hdl_free(thp, val, nelem * sizeof (int64_t));
+ end_element(fp, Propval);
+ break;
+ }
+ case TOPO_TYPE_UINT64_ARRAY: {
+ uint64_t *val;
+
+ if (topo_prop_get_uint64_array(node, pgname,
+ pv->tp_name, &val, &nelem, &err) != 0)
+ return;
+
+ begin_element(fp, Propval, Name, pv->tp_name, Type,
+ UInt64_Arr, NULL);
- if (pval != NULL && pv->tp_type == TOPO_TYPE_STRING)
- topo_hdl_strfree(thp, pval);
+ for (uint_t i = 0; i < nelem; i++) {
+ (void) snprintf(vbuf, INT64BUFSZ, "0x%" PRIx64,
+ val[i]);
+ begin_end_element(fp, Propitem, Value, vbuf,
+ NULL);
+ }
+
+ topo_hdl_free(thp, val, nelem * sizeof (uint64_t));
+ end_element(fp, Propval);
+ break;
+ }
+ case TOPO_TYPE_STRING_ARRAY: {
+ char **val;
+
+ if (topo_prop_get_string_array(node, pgname,
+ pv->tp_name, &val, &nelem, &err) != 0)
+ return;
- if (fmri != NULL)
- topo_hdl_strfree(thp, fmri);
+ begin_element(fp, Propval, Name, pv->tp_name, Type,
+ String_Arr, NULL);
- if (aval != NULL)
- free(aval);
+ for (uint_t i = 0; i < nelem; i++) {
+ begin_end_element(fp, Propitem, Value, val[i],
+ NULL);
+ }
+ for (uint_t i = 0; i < nelem; i++) {
+ topo_hdl_strfree(thp, val[i]);
+ }
+ topo_hdl_free(thp, val, nelem * sizeof (char *));
+
+ end_element(fp, Propval);
+ break;
+ }
+ case TOPO_TYPE_FMRI_ARRAY: {
+ nvlist_t **val;
+ char *fmristr = NULL;
+ int ret;
+
+ if (topo_prop_get_fmri_array(node, pgname,
+ pv->tp_name, &val, &nelem, &err) != 0)
+ return;
+
+ begin_element(fp, Propval, Name, pv->tp_name, Type,
+ FMRI_Arr, NULL);
+
+ for (uint_t i = 0; i < nelem; i++) {
+ if ((ret = topo_fmri_nvl2str(thp, val[i],
+ &fmristr, &err)) != 0)
+ break;
+ begin_end_element(fp, Propitem, Value, fmristr,
+ NULL);
+ topo_hdl_strfree(thp, fmristr);
+ }
+ for (uint_t i = 0; i < nelem; i++) {
+ nvlist_free(val[i]);
+ }
+ topo_hdl_free(thp, val, nelem * sizeof (nvlist_t *));
+ end_element(fp, Propval);
+ break;
+ }
+ default:
+ return;
+ }
}
static void
@@ -277,7 +395,19 @@ txml_print_node(topo_hdl_t *thp, FILE *fp, tnode_t *node)
topo_pgroup_t *pg;
(void) snprintf(inst, INT32BUFSZ, "%d", node->tn_instance);
- begin_element(fp, Node, Instance, inst, Static, True, NULL);
+ /*
+ * The "static" attribute for the "node" element controls whether the
+ * node gets enumerated, if it doesn't already exist. Setting it to
+ * true causes the node to not be created. The primary use-case for
+ * setting it to true is when want to use XML to override a property
+ * value on a topo node that was already created by an enumerator
+ * module. In this case we're trying to serialize the whole topology
+ * in a fashion such that we could reconstitute it from the generated
+ * XML. In which case, we relly need it to create all the nodes becuase
+ * no enumerator modules will be running. Hence, we set static to
+ * false.
+ */
+ begin_element(fp, Node, Instance, inst, Static, False, NULL);
for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
pg = topo_list_next(pg)) {
txml_print_pgroup(thp, fp, node, pg);
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_subr.c b/usr/src/lib/fm/topo/libtopo/common/topo_subr.c
index 94693e2a5f..a7afb3297a 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_subr.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_subr.c
@@ -534,14 +534,21 @@ topo_sensor_state_name(uint32_t sensor_type, uint8_t state, char *buf,
(void) snprintf(buf, len, "0x%02x", state);
return;
}
+ if (state == 0) {
+ (void) snprintf(buf, len, "NO_STATES_ASSERTED");
+ return;
+ }
+ buf[0] = '\0';
for (; ntp->int_name != NULL; ntp++) {
- if (ntp->int_value == state) {
- (void) strlcpy(buf, ntp->int_name, len);
- return;
+ if (state & ntp->int_value) {
+ if (buf[0] != '\0')
+ (void) strlcat(buf, "|", len);
+ (void) strlcat(buf, ntp->int_name, len);
}
}
- (void) snprintf(buf, len, "0x%02x", state);
+ if (buf[0] == '\0')
+ (void) snprintf(buf, len, "0x%02x", state);
}
static const topo_pgroup_info_t sys_pgroup = {
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
index d907c72c44..3e3241c8f3 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <libxml/parser.h>
@@ -118,8 +118,10 @@ xmlattr_to_int(topo_mod_t *mp,
propname);
if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL)
return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
- *value = strtoull((char *)str, (char **)&estr, 10);
- if (estr == str) {
+
+ errno = 0;
+ *value = strtoull((char *)str, (char **)&estr, 0);
+ if (errno != 0 || *estr != '\0') {
/* no conversion was done */
xmlFree(str);
return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
@@ -139,8 +141,10 @@ xmlattr_to_double(topo_mod_t *mp,
"xmlattr_to_double(propname=%s)\n", propname);
if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL)
return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
- *value = strtod((char *)str, (char **)&estr);
- if (estr == str || *estr != '\0') {
+
+ errno = 0;
+ *value = strtold((char *)str, (char **)&estr);
+ if (errno != 0 || *estr != '\0') {
/* full or partial conversion failure */
xmlFree(str);
return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
@@ -301,13 +305,9 @@ xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
(xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
- if ((str = xmlGetProp(cn, (xmlChar *)Value))
- == NULL)
+ if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
return (-1);
-
- ((int32_t *)arrbuf)[i++]
- = atoi((const char *)str);
- xmlFree(str);
+ ((int32_t *)arrbuf)[i++] = (int32_t)ui;
}
}
@@ -323,13 +323,9 @@ xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
(xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
- if ((str = xmlGetProp(cn, (xmlChar *)Value))
- == NULL)
+ if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
return (-1);
-
- ((uint32_t *)arrbuf)[i++]
- = atoi((const char *)str);
- xmlFree(str);
+ ((uint32_t *)arrbuf)[i++] = (uint32_t)ui;
}
}
@@ -345,13 +341,9 @@ xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
(xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
- if ((str = xmlGetProp(cn, (xmlChar *)Value))
- == NULL)
+ if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
return (-1);
-
- ((int64_t *)arrbuf)[i++]
- = atol((const char *)str);
- xmlFree(str);
+ ((int64_t *)arrbuf)[i++] = (int64_t)ui;
}
}
@@ -367,13 +359,9 @@ xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
(xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
- if ((str = xmlGetProp(cn, (xmlChar *)Value))
- == NULL)
+ if (xmlattr_to_int(mp, cn, Value, &ui) < 0)
return (-1);
-
- ((uint64_t *)arrbuf)[i++]
- = atol((const char *)str);
- xmlFree(str);
+ ((uint64_t *)arrbuf)[i++] = ui;
}
}
diff --git a/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c b/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c
index 434790fd65..64309245b0 100644
--- a/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c
+++ b/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <unistd.h>
#include <stdio.h>
@@ -347,14 +347,14 @@ static int
ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
nvlist_t *in, nvlist_t **out)
{
- char **entity_refs;
+ char **entity_refs, *sensor_class;
uint_t nelems;
ipmi_sdr_t *sdr = NULL;
ipmi_sensor_reading_t *reading;
ipmi_handle_t *hdl;
int err, i;
uint8_t sensor_num;
- uint32_t e_id, e_inst;
+ uint32_t e_id, e_inst, state;
ipmi_sdr_full_sensor_t *fsensor;
ipmi_sdr_compact_sensor_t *csensor;
nvlist_t *nvl;
@@ -430,12 +430,31 @@ ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
strarr_free(mod, entity_refs, nelems);
topo_mod_ipmi_rele(mod);
+ if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
+ &sensor_class, &err) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup prop %s/%s on node %s ",
+ "(%s)", TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
+ topo_node_name(node), topo_strerror(err));
+ return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
+ }
+ /*
+ * Mask off bits that are marked as reserved in the IPMI spec.
+ * For threshold sensors, bits 6:7 are reserved.
+ * For discrete sensors, bit 15 is reserved.
+ */
+ state = reading->isr_state;
+ if (strcmp(sensor_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0)
+ state = state & 0x3F;
+ else
+ state = state & 0x7FFF;
+
+ topo_mod_strfree(mod, sensor_class);
+
if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
TOPO_SENSOR_STATE) != 0 ||
nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
- nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, reading->isr_state)
- != 0) {
+ nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, state) != 0) {
topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
nvlist_free(nvl);
return (topo_mod_seterrno(mod, EMOD_NOMEM));
diff --git a/usr/src/lib/fm/topo/modules/common/ses/ses.c b/usr/src/lib/fm/topo/modules/common/ses/ses.c
index 081ed619ec..39f18783e8 100644
--- a/usr/src/lib/fm/topo/modules/common/ses/ses.c
+++ b/usr/src/lib/fm/topo/modules/common/ses/ses.c
@@ -23,7 +23,7 @@
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <alloca.h>
@@ -293,6 +293,34 @@ static ses_open_fail_list_t *ses_sofh;
static pthread_mutex_t ses_sofmt;
static void ses_ct_print(char *ptr);
+/*
+ * Static list of enclosure manufacturers/models that we will skip enumerating.
+ * To skip all models from a particular vendor, set the seb_model field to "*".
+ */
+typedef struct ses_enc_blacklist {
+ const char *seb_manuf;
+ const char *seb_model;
+} ses_enc_blacklist_t;
+
+static const ses_enc_blacklist_t enc_blacklist[] = {
+ { "LSI", "VirtualSES" }
+};
+
+#define N_ENC_BLACKLIST (sizeof (enc_blacklist) / \
+ sizeof (enc_blacklist[0]))
+
+static boolean_t
+ses_is_blacklisted(ses_enc_blacklist_t *seb)
+{
+ for (uint_t i = 0; i < N_ENC_BLACKLIST; i++) {
+ if (strcmp(seb->seb_manuf, enc_blacklist[i].seb_manuf) == 0 &&
+ (strcmp(enc_blacklist[i].seb_model, "*") == 0 ||
+ strcmp(seb->seb_model, enc_blacklist[i].seb_model) == 0))
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
static void
ses_recheck_dir()
{
@@ -3196,9 +3224,24 @@ ses_enum_gather(ses_node_t *np, void *data)
uint64_t prevstatus, status;
boolean_t report;
uint64_t subchassis = NO_SUBCHASSIS;
+ ses_enc_blacklist_t seb;
if (ses_node_type(np) == SES_NODE_ENCLOSURE) {
/*
+ * Compare the enclosure identity against the entries in the SES
+ * enclosure blacklist and ignore it, if found.
+ */
+ verify(nvlist_lookup_string(props, SES_EN_PROP_VID,
+ (char **)&seb.seb_manuf) == 0);
+ verify(nvlist_lookup_string(props, SES_EN_PROP_PID,
+ (char **)&seb.seb_model) == 0);
+ if (ses_is_blacklisted(&seb) == B_TRUE) {
+ topo_mod_dprintf(mod, "Skipping enclosure %s-%s: is "
+ "blacklisted", seb.seb_manuf, seb.seb_model);
+ return (SES_WALK_ACTION_TERMINATE);
+ }
+
+ /*
* If we have already identified the chassis for this target,
* then this is a secondary enclosure and we should ignore it,
* along with the rest of the tree (since this is depth-first).
diff --git a/usr/src/lib/gss_mechs/mech_dh/dh_common/dh_template.c b/usr/src/lib/gss_mechs/mech_dh/dh_common/dh_template.c
index be8dab28cb..4640cce212 100644
--- a/usr/src/lib/gss_mechs/mech_dh/dh_common/dh_template.c
+++ b/usr/src/lib/gss_mechs/mech_dh/dh_common/dh_template.c
@@ -26,7 +26,9 @@
* All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
#include <stdlib.h>
#include <string.h>
@@ -104,7 +106,7 @@ dh_getpublickey(const char *remote, keylen_t keylen, algtype_t algtype,
static const char NIS_SYMBOL[] = "__rpcsec_gss_is_server";
if (!init_nis_pubkey) {
- mutex_lock(&init_nis_pubkey_lock);
+ (void) mutex_lock(&init_nis_pubkey_lock);
if (!init_nis_pubkey) {
void *dlhandle = dlopen(0, RTLD_NOLOAD);
if (dlhandle == 0) {
@@ -117,7 +119,7 @@ dh_getpublickey(const char *remote, keylen_t keylen, algtype_t algtype,
}
init_nis_pubkey = 1;
}
- mutex_unlock(&init_nis_pubkey_lock);
+ (void) mutex_unlock(&init_nis_pubkey_lock);
}
if (nis_call && (*nis_call)()) {
int key_cached;
diff --git a/usr/src/lib/libc/port/fp/sigfpe.c b/usr/src/lib/libc/port/fp/sigfpe.c
index 9b1942423f..dca4e3428a 100644
--- a/usr/src/lib/libc/port/fp/sigfpe.c
+++ b/usr/src/lib/libc/port/fp/sigfpe.c
@@ -150,6 +150,11 @@ _sigfpe_master(int sig, siginfo_t *siginfo, void *arg)
case FPE_FLTOVF:
exception = fp_overflow;
goto ieee;
+#if defined(__i386) || defined(__amd64)
+ case FPE_FLTDEN:
+ exception = fp_denormalized;
+ goto ieee;
+#endif
default: /* The common default treatment is to abort. */
break;
}
diff --git a/usr/src/lib/libcmdutils/common/process_xattrs.c b/usr/src/lib/libcmdutils/common/process_xattrs.c
index 50b1de58d6..802981053c 100644
--- a/usr/src/lib/libcmdutils/common/process_xattrs.c
+++ b/usr/src/lib/libcmdutils/common/process_xattrs.c
@@ -23,6 +23,7 @@
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include "libcmdutils.h"
@@ -70,7 +71,7 @@ get_attrdirs(int indfd, int outdfd, char *attrfile, int *sfd, int *tfd)
/*
* mv_xattrs - Copies the content of the extended attribute files. Then
- * moves the extended system attributes from the input attribute files
+ * moves the extended system attributes from the input attribute files
* to the target attribute files. Moves the extended system attributes
* from source to the target file. This function returns 0 on success
* and nonzero on error.
@@ -162,8 +163,7 @@ mv_xattrs(char *cmd, char *infile, char *outfile, int sattr, int silent)
* Gets non default extended system attributes from
* source to copy to target.
*/
- if (dp->d_name != NULL)
- res = sysattr_list(cmd, sattrfd, dp->d_name);
+ res = sysattr_list(cmd, sattrfd, dp->d_name);
if (res != NULL &&
get_attrdirs(indfd, outdfd, dp->d_name, &asfd,
diff --git a/usr/src/lib/libctf/common/ctf_convert.c b/usr/src/lib/libctf/common/ctf_convert.c
index 1a433d17db..7190e66718 100644
--- a/usr/src/lib/libctf/common/ctf_convert.c
+++ b/usr/src/lib/libctf/common/ctf_convert.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -168,9 +168,7 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
/*
* Succsesful conversion.
*/
- if (fp != NULL) {
- if (label == NULL)
- label = "";
+ if (fp != NULL && label != NULL) {
if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) {
*errp = ctf_errno(fp);
ctf_close(fp);
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c
index 18be598ed9..7cd02db43c 100644
--- a/usr/src/lib/libctf/common/ctf_dwarf.c
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c
@@ -28,7 +28,7 @@
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -282,9 +282,6 @@ static int ctf_dwarf_function_count(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *,
static int ctf_dwarf_convert_fargs(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *,
ctf_id_t *);
-typedef int (ctf_dwarf_symtab_f)(ctf_cu_t *, const GElf_Sym *, ulong_t,
- const char *, const char *, void *);
-
/*
* This is a generic way to set a CTF Conversion backend error depending on what
* we were doing. Unless it was one of a specific set of errors that don't
@@ -2166,126 +2163,132 @@ ctf_dwarf_fixup_die(ctf_cu_t *cup, boolean_t addpass)
return (0);
}
+/*
+ * The DWARF information about a symbol and the information in the symbol table
+ * may not be the same due to symbol reduction that is performed by ld due to a
+ * mapfile or other such directive. We process weak symbols at a later time.
+ *
+ * The following are the rules that we employ:
+ *
+ * 1. A DWARF function that is considered exported matches STB_GLOBAL entries
+ * with the same name.
+ *
+ * 2. A DWARF function that is considered exported matches STB_LOCAL entries
+ * with the same name and the same file. This case may happen due to mapfile
+ * reduction.
+ *
+ * 3. A DWARF function that is not considered exported matches STB_LOCAL entries
+ * with the same name and the same file.
+ *
+ * 4. A DWARF function that has the same name as the symbol table entry, but the
+ * files do not match. This is considered a 'fuzzy' match. This may also happen
+ * due to a mapfile reduction. Fuzzy matching is only used when we know that the
+ * file in question refers to the primary object. This is because when a symbol
+ * is reduced in a mapfile, it's always going to be tagged as a local value in
+ * the generated output and it is considered as to belong to the primary file
+ * which is the first STT_FILE symbol we see.
+ */
+static boolean_t
+ctf_dwarf_symbol_match(const char *symtab_file, const char *symtab_name,
+ uint_t symtab_bind, const char *dwarf_file, const char *dwarf_name,
+ boolean_t dwarf_global, boolean_t *is_fuzzy)
+{
+ *is_fuzzy = B_FALSE;
+
+ if (symtab_bind != STB_LOCAL && symtab_bind != STB_GLOBAL) {
+ return (B_FALSE);
+ }
+
+ if (strcmp(symtab_name, dwarf_name) != 0) {
+ return (B_FALSE);
+ }
+
+ if (symtab_bind == STB_GLOBAL) {
+ return (dwarf_global);
+ }
+
+ if (strcmp(symtab_file, dwarf_file) == 0) {
+ return (B_TRUE);
+ }
+
+ if (dwarf_global) {
+ *is_fuzzy = B_TRUE;
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
static ctf_dwfunc_t *
ctf_dwarf_match_func(ctf_cu_t *cup, const char *file, const char *name,
- int bind)
+ uint_t bind, boolean_t primary)
{
- ctf_dwfunc_t *cdf;
+ ctf_dwfunc_t *cdf, *fuzzy = NULL;
if (bind == STB_WEAK)
return (NULL);
- /* Nothing we can do if we can't find a name to compare it to. */
if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
return (NULL);
for (cdf = ctf_list_next(&cup->cu_funcs); cdf != NULL;
cdf = ctf_list_next(cdf)) {
- if (bind == STB_GLOBAL && cdf->cdf_global == B_FALSE)
- continue;
- if (bind == STB_LOCAL && cdf->cdf_global == B_TRUE)
- continue;
- if (strcmp(name, cdf->cdf_name) != 0)
- continue;
- if (bind == STB_LOCAL && strcmp(file, cup->cu_name) != 0)
- continue;
- return (cdf);
+ boolean_t is_fuzzy = B_FALSE;
+
+ if (ctf_dwarf_symbol_match(file, name, bind, cup->cu_name,
+ cdf->cdf_name, cdf->cdf_global, &is_fuzzy)) {
+ if (is_fuzzy) {
+ if (primary) {
+ fuzzy = cdf;
+ }
+ continue;
+ } else {
+ return (cdf);
+ }
+ }
}
- return (NULL);
+ return (fuzzy);
}
+
static ctf_dwvar_t *
ctf_dwarf_match_var(ctf_cu_t *cup, const char *file, const char *name,
- int bind)
+ uint_t bind, boolean_t primary)
{
- ctf_dwvar_t *cdv;
+ ctf_dwvar_t *cdv, *fuzzy = NULL;
+
+ if (bind == STB_WEAK)
+ return (NULL);
- /* Nothing we can do if we can't find a name to compare it to. */
if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
return (NULL);
- ctf_dprintf("Still considering %s\n", name);
for (cdv = ctf_list_next(&cup->cu_vars); cdv != NULL;
cdv = ctf_list_next(cdv)) {
- if (bind == STB_GLOBAL && cdv->cdv_global == B_FALSE)
- continue;
- if (bind == STB_LOCAL && cdv->cdv_global == B_TRUE)
- continue;
- if (strcmp(name, cdv->cdv_name) != 0)
- continue;
- if (bind == STB_LOCAL && strcmp(file, cup->cu_name) != 0)
- continue;
- return (cdv);
- }
-
- return (NULL);
-}
-
-static int
-ctf_dwarf_symtab_iter(ctf_cu_t *cup, ctf_dwarf_symtab_f *func, void *arg)
-{
- int ret;
- ulong_t i;
- ctf_file_t *fp = cup->cu_ctfp;
- const char *file = NULL;
- uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
- uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
-
- for (i = 0; i < fp->ctf_nsyms; i++) {
- const char *name;
- int type;
- GElf_Sym gsym;
- const GElf_Sym *gsymp;
-
- if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
- const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
- type = ELF32_ST_TYPE(symp->st_info);
- if (type == STT_FILE) {
- file = (char *)(strbase + symp->st_name);
- continue;
+ boolean_t is_fuzzy = B_FALSE;
+
+ if (ctf_dwarf_symbol_match(file, name, bind, cup->cu_name,
+ cdv->cdv_name, cdv->cdv_global, &is_fuzzy)) {
+ if (is_fuzzy) {
+ if (primary) {
+ fuzzy = cdv;
+ }
+ } else {
+ return (cdv);
}
- if (type != STT_OBJECT && type != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- gsym.st_name = symp->st_name;
- gsym.st_value = symp->st_value;
- gsym.st_size = symp->st_size;
- gsym.st_info = symp->st_info;
- gsym.st_other = symp->st_other;
- gsym.st_shndx = symp->st_shndx;
- gsymp = &gsym;
- } else {
- const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
- type = ELF64_ST_TYPE(symp->st_info);
- if (type == STT_FILE) {
- file = (char *)(strbase + symp->st_name);
- continue;
- }
- if (type != STT_OBJECT && type != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- gsymp = symp;
}
-
- ret = func(cup, gsymp, i, file, name, arg);
- if (ret != 0)
- return (ret);
}
- return (0);
+ return (fuzzy);
}
static int
-ctf_dwarf_conv_funcvars_cb(ctf_cu_t *cup, const GElf_Sym *symp, ulong_t idx,
- const char *file, const char *name, void *arg)
+ctf_dwarf_conv_funcvars_cb(const Elf64_Sym *symp, ulong_t idx,
+ const char *file, const char *name, boolean_t primary, void *arg)
{
- int ret, bind, type;
+ int ret;
+ uint_t bind, type;
+ ctf_cu_t *cup = arg;
bind = GELF_ST_BIND(symp->st_info);
type = GELF_ST_TYPE(symp->st_info);
@@ -2298,19 +2301,19 @@ ctf_dwarf_conv_funcvars_cb(ctf_cu_t *cup, const GElf_Sym *symp, ulong_t idx,
if (type == STT_OBJECT) {
ctf_dwvar_t *cdv = ctf_dwarf_match_var(cup, file, name,
- bind);
- ctf_dprintf("match for %s (%d): %p\n", name, idx, cdv);
+ bind, primary);
if (cdv == NULL)
return (0);
ret = ctf_add_object(cup->cu_ctfp, idx, cdv->cdv_type);
- ctf_dprintf("added object %s\n", name);
+ ctf_dprintf("added object %s->%ld\n", name, cdv->cdv_type);
} else {
ctf_dwfunc_t *cdf = ctf_dwarf_match_func(cup, file, name,
- bind);
+ bind, primary);
if (cdf == NULL)
return (0);
ret = ctf_add_function(cup->cu_ctfp, idx, &cdf->cdf_fip,
cdf->cdf_argv);
+ ctf_dprintf("added function %s\n", name);
}
if (ret == CTF_ERR) {
@@ -2323,7 +2326,7 @@ ctf_dwarf_conv_funcvars_cb(ctf_cu_t *cup, const GElf_Sym *symp, ulong_t idx,
static int
ctf_dwarf_conv_funcvars(ctf_cu_t *cup)
{
- return (ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_funcvars_cb, NULL));
+ return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_funcvars_cb, cup));
}
/*
@@ -2365,18 +2368,19 @@ ctf_dwarf_conv_funcvars(ctf_cu_t *cup)
* that we can consume.
*/
typedef struct ctf_dwarf_weak_arg {
- const GElf_Sym *cweak_symp;
+ const Elf64_Sym *cweak_symp;
const char *cweak_file;
boolean_t cweak_candidate;
ulong_t cweak_idx;
} ctf_dwarf_weak_arg_t;
static int
-ctf_dwarf_conv_check_weak(ctf_cu_t *cup, const GElf_Sym *symp,
- ulong_t idx, const char *file, const char *name, void *arg)
+ctf_dwarf_conv_check_weak(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
{
ctf_dwarf_weak_arg_t *cweak = arg;
- const GElf_Sym *wsymp = cweak->cweak_symp;
+
+ const Elf64_Sym *wsymp = cweak->cweak_symp;
ctf_dprintf("comparing weak to %s\n", name);
@@ -2476,11 +2480,12 @@ ctf_dwarf_duplicate_func(ctf_cu_t *cup, ulong_t idx, ulong_t matchidx)
}
static int
-ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
- ulong_t idx, const char *file, const char *name, void *arg)
+ctf_dwarf_conv_weaks_cb(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
{
int ret, type;
ctf_dwarf_weak_arg_t cweak;
+ ctf_cu_t *cup = arg;
/*
* We only care about weak symbols.
@@ -2503,7 +2508,7 @@ ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
ctf_dprintf("Trying to find weak equiv for %s\n", name);
- ret = ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_check_weak, &cweak);
+ ret = ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_check_weak, &cweak);
VERIFY(ret == 0 || ret == 1);
/*
@@ -2518,6 +2523,7 @@ ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
/*
* Now, finally go and add the type based on the match.
*/
+ ctf_dprintf("matched weak symbol %lu to %lu\n", idx, cweak.cweak_idx);
if (type == STT_OBJECT) {
ret = ctf_dwarf_duplicate_sym(cup, idx, cweak.cweak_idx);
} else {
@@ -2530,7 +2536,7 @@ ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
static int
ctf_dwarf_conv_weaks(ctf_cu_t *cup)
{
- return (ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_weaks_cb, NULL));
+ return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_weaks_cb, cup));
}
/* ARGSUSED */
@@ -2601,20 +2607,21 @@ ctf_dwarf_convert_one(void *arg, void *unused)
}
}
- ctf_phase_dump(cup->cu_ctfp, "pre-dedup");
+ ctf_phase_dump(cup->cu_ctfp, "pre-dwarf-dedup", cup->cu_name);
ctf_dprintf("adding inputs for dedup\n");
if ((ret = ctf_merge_add(cup->cu_cmh, cup->cu_ctfp)) != 0) {
return (ctf_dwarf_error(cup, NULL, ret,
"failed to add inputs for merge"));
}
- ctf_dprintf("starting merge\n");
+ ctf_dprintf("starting dedup of %s\n", cup->cu_name);
if ((ret = ctf_merge_dedup(cup->cu_cmh, &dedup)) != 0) {
return (ctf_dwarf_error(cup, NULL, ret,
"failed to deduplicate die"));
}
ctf_close(cup->cu_ctfp);
cup->cu_ctfp = dedup;
+ ctf_phase_dump(cup->cu_ctfp, "post-dwarf-dedup", cup->cu_name);
return (0);
}
@@ -2904,10 +2911,11 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
*errp = ret;
goto out;
}
+
cup->cu_doweaks = ndies > 1 ? B_FALSE : B_TRUE;
}
- ctf_dprintf("found %d DWARF die(s)\n", ndies);
+ ctf_dprintf("found %d DWARF CUs\n", ndies);
/*
* If we only have one compilation unit, there's no reason to use
@@ -2924,7 +2932,7 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
for (i = 0; i < ndies; i++) {
cup = &cdies[i];
- ctf_dprintf("adding die %s: %p, %x %x\n", cup->cu_name,
+ ctf_dprintf("adding cu %s: %p, %x %x\n", cup->cu_name,
cup->cu_cu, cup->cu_cuoff, cup->cu_maxoff);
if (workq_add(wqp, cup) == -1) {
*errp = errno;
@@ -2942,7 +2950,7 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
goto out;
}
- ctf_dprintf("Determining next phase: have %d dies\n", ndies);
+ ctf_dprintf("Determining next phase: have %d CUs\n", ndies);
if (ndies != 1) {
ctf_merge_t *cmp;
@@ -2959,9 +2967,10 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
goto out;
}
- ctf_dprintf("adding dies\n");
for (i = 0; i < ndies; i++) {
cup = &cdies[i];
+ ctf_dprintf("adding cu %s (%p)\n", cup->cu_name,
+ cup->cu_ctfp);
if ((ret = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) {
ctf_merge_fini(cmp);
*errp = ret;
diff --git a/usr/src/lib/libctf/common/ctf_lib.c b/usr/src/lib/libctf/common/ctf_lib.c
index bc533b766e..5177409200 100644
--- a/usr/src/lib/libctf/common/ctf_lib.c
+++ b/usr/src/lib/libctf/common/ctf_lib.c
@@ -24,13 +24,13 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <ctf_impl.h>
+#include <libctf_impl.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
@@ -769,7 +769,7 @@ ctf_version(int version)
* A utility function for folks debugging CTF conversion and merging.
*/
void
-ctf_phase_dump(ctf_file_t *fp, const char *phase)
+ctf_phase_dump(ctf_file_t *fp, const char *phase, const char *name)
{
int fd;
static char *base;
@@ -778,7 +778,10 @@ ctf_phase_dump(ctf_file_t *fp, const char *phase)
if (base == NULL && (base = getenv("LIBCTF_WRITE_PHASES")) == NULL)
return;
- (void) snprintf(path, sizeof (path), "%s/libctf.%s.%d.ctf", base,
+ if (name == NULL)
+ name = "libctf";
+
+ (void) snprintf(path, sizeof (path), "%s/%s.%s.%d.ctf", base, name,
phase != NULL ? phase : "",
ctf_phase);
if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0)
@@ -786,3 +789,89 @@ ctf_phase_dump(ctf_file_t *fp, const char *phase)
(void) ctf_write(fp, fd);
(void) close(fd);
}
+
+void
+ctf_phase_bump(void)
+{
+ ctf_phase++;
+}
+
+int
+ctf_symtab_iter(ctf_file_t *fp, ctf_symtab_f func, void *arg)
+{
+ ulong_t i;
+ uintptr_t symbase;
+ uintptr_t strbase;
+ const char *file = NULL;
+ boolean_t primary = B_TRUE;
+
+ if (fp->ctf_symtab.cts_data == NULL ||
+ fp->ctf_strtab.cts_data == NULL) {
+ return (ECTF_NOSYMTAB);
+ }
+
+ symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ const char *name;
+ int ret;
+ uint_t type;
+ Elf64_Sym sym;
+
+ /*
+ * The CTF library has historically tried to handle large file
+ * offsets itself so that way clients can be unaware of such
+ * isseus. Therefore, we translate everything to a 64-bit ELF
+ * symbol, this is done to make it so that the rest of the
+ * library doesn't have to know about these differences. For
+ * more information see, lib/libctf/common/ctf_lib.c.
+ */
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ uint_t bind, itype;
+
+ sym.st_name = symp->st_name;
+ sym.st_value = symp->st_value;
+ sym.st_size = symp->st_size;
+ bind = ELF32_ST_BIND(symp->st_info);
+ itype = ELF32_ST_TYPE(symp->st_info);
+ sym.st_info = ELF64_ST_INFO(bind, itype);
+ sym.st_other = symp->st_other;
+ sym.st_shndx = symp->st_shndx;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+
+ sym = *symp;
+ }
+
+ type = ELF64_ST_TYPE(sym.st_info);
+ name = (const char *)(strbase + sym.st_name);
+
+ /*
+ * Check first if we have an STT_FILE entry. This is used to
+ * distinguish between various local symbols when merging.
+ */
+ if (type == STT_FILE) {
+ if (file != NULL) {
+ primary = B_FALSE;
+ }
+ file = name;
+ continue;
+ }
+
+ /*
+ * Check if this is a symbol that we care about.
+ */
+ if (!ctf_sym_valid(strbase, type, sym.st_shndx, sym.st_value,
+ sym.st_name)) {
+ continue;
+ }
+
+ if ((ret = func(&sym, i, file, name, primary, arg)) != 0) {
+ return (ret);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libctf/common/ctf_merge.c b/usr/src/lib/libctf/common/ctf_merge.c
index c93a2a4f7c..755c6ebc9e 100644
--- a/usr/src/lib/libctf/common/ctf_merge.c
+++ b/usr/src/lib/libctf/common/ctf_merge.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (c) 2015 Joyent, Inc.
+ * Copyright (c) 2019 Joyent, Inc.
*/
/*
@@ -60,14 +60,18 @@ typedef struct ctf_merge_types {
typedef struct ctf_merge_objmap {
list_node_t cmo_node;
const char *cmo_name; /* Symbol name */
+ const char *cmo_file; /* Symbol file */
ulong_t cmo_idx; /* Symbol ID */
+ Elf64_Sym cmo_sym; /* Symbol Entry */
ctf_id_t cmo_tid; /* Type ID */
} ctf_merge_objmap_t;
typedef struct ctf_merge_funcmap {
list_node_t cmf_node;
const char *cmf_name; /* Symbol name */
+ const char *cmf_file; /* Symbol file */
ulong_t cmf_idx; /* Symbol ID */
+ Elf64_Sym cmf_sym; /* Symbol Entry */
ctf_id_t cmf_rtid; /* Type ID */
uint_t cmf_flags; /* ctf_funcinfo_t ctc_flags */
uint_t cmf_argc; /* Number of arguments */
@@ -94,6 +98,13 @@ struct ctf_merge_handle {
char *cmh_pname; /* Parent name */
};
+typedef struct ctf_merge_symbol_arg {
+ list_t *cmsa_objmap;
+ list_t *cmsa_funcmap;
+ ctf_file_t *cmsa_out;
+ boolean_t cmsa_dedup;
+} ctf_merge_symbol_arg_t;
+
static int ctf_merge_add_type(ctf_merge_types_t *, ctf_id_t);
static ctf_id_t
@@ -661,8 +672,8 @@ ctf_merge_common(ctf_merge_types_t *cmp)
{
int ret, i;
- ctf_phase_dump(cmp->cm_src, "merge-common-src");
- ctf_phase_dump(cmp->cm_out, "merge-common-dest");
+ ctf_phase_dump(cmp->cm_src, "merge-common-src", NULL);
+ ctf_phase_dump(cmp->cm_out, "merge-common-dest", NULL);
/* Pass 1 */
for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
@@ -764,6 +775,37 @@ ctf_merge_types_fini(ctf_merge_types_t *cmp)
}
/*
+ * After performing a pass, we need to go through the object and function type
+ * maps and potentially fix them up based on the new maps that we have.
+ */
+static void
+ctf_merge_fixup_symmaps(ctf_merge_types_t *cmp, ctf_merge_input_t *cmi)
+{
+ ctf_merge_objmap_t *cmo;
+ ctf_merge_funcmap_t *cmf;
+
+ for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&cmi->cmi_omap, cmo)) {
+ VERIFY3S(cmo->cmo_tid, !=, 0);
+ VERIFY(cmp->cm_tmap[cmo->cmo_tid].cmt_map != 0);
+ cmo->cmo_tid = cmp->cm_tmap[cmo->cmo_tid].cmt_map;
+ }
+
+ for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&cmi->cmi_fmap, cmf)) {
+ int i;
+
+ VERIFY(cmp->cm_tmap[cmf->cmf_rtid].cmt_map != 0);
+ cmf->cmf_rtid = cmp->cm_tmap[cmf->cmf_rtid].cmt_map;
+ for (i = 0; i < cmf->cmf_argc; i++) {
+ VERIFY(cmp->cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
+ cmf->cmf_args[i] =
+ cmp->cm_tmap[cmf->cmf_args[i]].cmt_map;
+ }
+ }
+}
+
+/*
* Merge the types contained inside of two input files. The second input file is
* always going to be the destination. We're guaranteed that it's always
* writeable.
@@ -774,8 +816,6 @@ ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
int ret;
ctf_merge_types_t cm;
ctf_diff_t *cdp;
- ctf_merge_objmap_t *cmo;
- ctf_merge_funcmap_t *cmf;
ctf_merge_input_t *scmi = arg;
ctf_merge_input_t *dcmi = arg2;
ctf_file_t *out = dcmi->cmi_input;
@@ -817,25 +857,7 @@ ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
/*
* Now we need to fix up the object and function maps.
*/
- for (cmo = list_head(&scmi->cmi_omap); cmo != NULL;
- cmo = list_next(&scmi->cmi_omap, cmo)) {
- if (cmo->cmo_tid == 0)
- continue;
- VERIFY(cm.cm_tmap[cmo->cmo_tid].cmt_map != 0);
- cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
- }
-
- for (cmf = list_head(&scmi->cmi_fmap); cmf != NULL;
- cmf = list_next(&scmi->cmi_fmap, cmf)) {
- int i;
-
- VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
- cmf->cmf_rtid = cm.cm_tmap[cmf->cmf_rtid].cmt_map;
- for (i = 0; i < cmf->cmf_argc; i++) {
- VERIFY(cm.cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
- cmf->cmf_args[i] = cm.cm_tmap[cmf->cmf_args[i]].cmt_map;
- }
- }
+ ctf_merge_fixup_symmaps(&cm, scmi);
/*
* Now that we've fixed things up, we need to give our function and
@@ -852,42 +874,10 @@ cleanup:
ctf_diff_fini(cdp);
if (ret != 0)
return (ctf_errno(out));
+ ctf_phase_bump();
return (0);
}
-/*
- * After performing a pass, we need to go through the object and function type
- * maps and potentially fix them up based on the new maps that we haev.
- */
-static void
-ctf_merge_fixup_nontypes(ctf_merge_types_t *cmp, ctf_merge_input_t *cmi)
-{
- ctf_merge_objmap_t *cmo;
- ctf_merge_funcmap_t *cmf;
-
- for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
- cmo = list_next(&cmi->cmi_omap, cmo)) {
- if (cmo->cmo_tid == 0)
- continue;
- VERIFY(cmp->cm_tmap[cmo->cmo_tid].cmt_map != 0);
- cmo->cmo_tid = cmp->cm_tmap[cmo->cmo_tid].cmt_map;
- }
-
- for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
- cmf = list_next(&cmi->cmi_fmap, cmf)) {
- int i;
-
- VERIFY(cmp->cm_tmap[cmf->cmf_rtid].cmt_map != 0);
- cmf->cmf_rtid = cmp->cm_tmap[cmf->cmf_rtid].cmt_map;
- for (i = 0; i < cmf->cmf_argc; i++) {
- VERIFY(cmp->cm_tmap[cmf->cmf_args[i]].cmt_map !=
- 0);
- cmf->cmf_args[i] =
- cmp->cm_tmap[cmf->cmf_args[i]].cmt_map;
- }
- }
-}
-
static int
ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
{
@@ -948,7 +938,7 @@ ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
cmi = list_next(&cmh->cmh_inputs, cmi)) {
- ctf_merge_fixup_nontypes(&cm, cmi);
+ ctf_merge_fixup_symmaps(&cm, cmi);
}
ctf_merge_types_fini(&cm);
@@ -1060,10 +1050,9 @@ ctf_merge_label(ctf_merge_t *cmh, const char *label)
}
static int
-ctf_merge_add_funcs_cb(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
- void *arg)
+ctf_merge_add_function(ctf_merge_input_t *cmi, ctf_funcinfo_t *fip, ulong_t idx,
+ const char *file, const char *name, const Elf64_Sym *symp)
{
- ctf_merge_input_t *cmi = arg;
ctf_merge_funcmap_t *fmap;
fmap = ctf_alloc(sizeof (ctf_merge_funcmap_t) +
@@ -1072,10 +1061,16 @@ ctf_merge_add_funcs_cb(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
return (ENOMEM);
fmap->cmf_idx = idx;
+ fmap->cmf_sym = *symp;
fmap->cmf_rtid = fip->ctc_return;
fmap->cmf_flags = fip->ctc_flags;
fmap->cmf_argc = fip->ctc_argc;
fmap->cmf_name = name;
+ if (ELF64_ST_BIND(symp->st_info) == STB_LOCAL) {
+ fmap->cmf_file = file;
+ } else {
+ fmap->cmf_file = NULL;
+ }
if (ctf_func_args(cmi->cmi_input, idx, fmap->cmf_argc,
fmap->cmf_args) != 0) {
@@ -1084,14 +1079,17 @@ ctf_merge_add_funcs_cb(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
return (ctf_errno(cmi->cmi_input));
}
+ ctf_dprintf("added initial function %s, %lu, %s %u\n", name, idx,
+ fmap->cmf_file != NULL ? fmap->cmf_file : "global",
+ ELF64_ST_BIND(symp->st_info));
list_insert_tail(&cmi->cmi_fmap, fmap);
return (0);
}
static int
-ctf_merge_add_objs_cb(const char *name, ctf_id_t id, ulong_t idx, void *arg)
+ctf_merge_add_object(ctf_merge_input_t *cmi, ctf_id_t id, ulong_t idx,
+ const char *file, const char *name, const Elf64_Sym *symp)
{
- ctf_merge_input_t *cmi = arg;
ctf_merge_objmap_t *cmo;
cmo = ctf_alloc(sizeof (ctf_merge_objmap_t));
@@ -1099,12 +1097,71 @@ ctf_merge_add_objs_cb(const char *name, ctf_id_t id, ulong_t idx, void *arg)
return (ENOMEM);
cmo->cmo_name = name;
+ if (ELF64_ST_BIND(symp->st_info) == STB_LOCAL) {
+ cmo->cmo_file = file;
+ } else {
+ cmo->cmo_file = NULL;
+ }
cmo->cmo_idx = idx;
cmo->cmo_tid = id;
+ cmo->cmo_sym = *symp;
list_insert_tail(&cmi->cmi_omap, cmo);
+
+ ctf_dprintf("added initial object %s, %lu, %ld, %s\n", name, idx, id,
+ cmo->cmo_file != NULL ? cmo->cmo_file : "global");
+
return (0);
}
+static int
+ctf_merge_add_symbol(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
+{
+ ctf_merge_input_t *cmi = arg;
+ ctf_file_t *fp = cmi->cmi_input;
+ ushort_t *data, funcbase;
+ uint_t type;
+ ctf_funcinfo_t fi;
+
+ /*
+ * See if there is type information for this. If there is no
+ * type information for this entry or no translation, then we
+ * will find the value zero. This indicates no type ID for
+ * objects and encodes unknown information for functions.
+ */
+ if (fp->ctf_sxlate[idx] == -1u)
+ return (0);
+ data = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[idx]);
+ if (*data == 0)
+ return (0);
+
+ type = ELF64_ST_TYPE(symp->st_info);
+
+ switch (type) {
+ case STT_FUNC:
+ funcbase = *data;
+ if (LCTF_INFO_KIND(fp, funcbase) != CTF_K_FUNCTION)
+ return (0);
+ data++;
+ fi.ctc_return = *data;
+ data++;
+ fi.ctc_argc = LCTF_INFO_VLEN(fp, funcbase);
+ fi.ctc_flags = 0;
+
+ if (fi.ctc_argc != 0 && data[fi.ctc_argc - 1] == 0) {
+ fi.ctc_flags |= CTF_FUNC_VARARG;
+ fi.ctc_argc--;
+ }
+ return (ctf_merge_add_function(cmi, &fi, idx, file, name,
+ symp));
+ case STT_OBJECT:
+ return (ctf_merge_add_object(cmi, *data, idx, file, name,
+ symp));
+ default:
+ return (0);
+ }
+}
+
/*
* Whenever we create an entry to merge, we then go and add a second empty
* ctf_file_t which we use for the purposes of our merging. It's not the best,
@@ -1117,6 +1174,8 @@ ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
ctf_merge_input_t *cmi;
ctf_file_t *empty;
+ ctf_dprintf("adding input %p\n", input);
+
if (input->ctf_flags & LCTF_CHILD)
return (ECTF_MCHILD);
@@ -1132,13 +1191,7 @@ ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
offsetof(ctf_merge_objmap_t, cmo_node));
if (cmh->cmh_msyms == B_TRUE) {
- if ((ret = ctf_function_iter(input, ctf_merge_add_funcs_cb,
- cmi)) != 0) {
- ctf_merge_fini_input(cmi);
- return (ret);
- }
-
- if ((ret = ctf_object_iter(input, ctf_merge_add_objs_cb,
+ if ((ret = ctf_symtab_iter(input, ctf_merge_add_symbol,
cmi)) != 0) {
ctf_merge_fini_input(cmi);
return (ret);
@@ -1194,122 +1247,193 @@ ctf_merge_uniquify(ctf_merge_t *cmh, ctf_file_t *u, const char *pname)
return (0);
}
-static int
-ctf_merge_symbols(ctf_merge_t *cmh, ctf_file_t *fp)
+/*
+ * Symbol matching rules: the purpose of this is to verify that the type
+ * information that we have for a given symbol actually matches the output
+ * symbol. This is unfortunately complicated by several different factors:
+ *
+ * 1. When merging multiple .o's into a single item, the symbol table index will
+ * not match.
+ *
+ * 2. Visibility of a symbol may not be identical to the object file or the
+ * DWARF information due to symbol reduction via a mapfile.
+ *
+ * As such, we have to employ the following rules:
+ *
+ * 1. A global symbol table entry always matches a global CTF symbol with the
+ * same name.
+ *
+ * 2. A local symbol table entry always matches a local CTF symbol if they have
+ * the same name and they belong to the same file.
+ *
+ * 3. A weak symbol matches a non-weak symbol. This happens if we find that the
+ * types match, the values match, the sizes match, and the section indexes
+ * match. This happens when we do a conversion in one pass, it almost never
+ * happens when we're merging multiple object files. If we match a CTF global
+ * symbol, that's a fixed match, otherwise it's a fuzzy match.
+ *
+ * 4. A local symbol table entry matches a global CTF entry if the
+ * other pieces fail, but they have the same name. This is considered a fuzzy
+ * match and is not used unless we have no other options.
+ *
+ * 5. A weak symbol table entry matches a weak CTF entry if the other pieces
+ * fail, but they have the same name. This is considered a fuzzy match and is
+ * not used unless we have no other options. When merging independent .o files,
+ * this is often the only recourse we have to matching weak symbols.
+ *
+ * In the end, this would all be much simpler if we were able to do this as part
+ * of libld which would be able to do all the symbol transformations.
+ */
+static boolean_t
+ctf_merge_symbol_match(const char *ctf_file, const char *ctf_name,
+ const Elf64_Sym *ctf_symp, const char *symtab_file, const char *symtab_name,
+ const Elf64_Sym *symtab_symp, boolean_t *is_fuzzy)
{
- int err;
- ulong_t i;
-
- uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
- uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
-
- for (i = 0; i < fp->ctf_nsyms; i++) {
- const char *name;
- ctf_merge_input_t *cmi;
- ctf_merge_objmap_t *cmo;
-
- if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
- const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
- int type = ELF32_ST_TYPE(symp->st_info);
- if (type != STT_OBJECT)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- } else {
- const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
- int type = ELF64_ST_TYPE(symp->st_info);
- if (type != STT_OBJECT)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- }
+ *is_fuzzy = B_FALSE;
+ uint_t symtab_bind, ctf_bind;
- cmo = NULL;
- for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
- cmi = list_next(&cmh->cmh_inputs, cmi)) {
- for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
- cmo = list_next(&cmi->cmi_omap, cmo)) {
- if (strcmp(cmo->cmo_name, name) == 0)
- goto found;
- }
+ symtab_bind = ELF64_ST_BIND(symtab_symp->st_info);
+ ctf_bind = ELF64_ST_BIND(ctf_symp->st_info);
+
+ ctf_dprintf("comparing merge match for %s/%s/%u->%s/%s/%u\n",
+ symtab_file, symtab_name, symtab_bind,
+ ctf_file, ctf_name, ctf_bind);
+ if (strcmp(ctf_name, symtab_name) != 0) {
+ return (B_FALSE);
+ }
+
+ if (symtab_bind == STB_GLOBAL && ctf_bind == STB_GLOBAL) {
+ return (B_TRUE);
+ } else if (symtab_bind == STB_GLOBAL) {
+ return (B_FALSE);
+ }
+
+ if (ctf_bind == STB_LOCAL && ctf_bind == symtab_bind &&
+ ctf_file != NULL && symtab_file != NULL &&
+ strcmp(ctf_file, symtab_file) == 0) {
+ return (B_TRUE);
+ }
+
+ if (symtab_bind == STB_WEAK && ctf_bind != STB_WEAK &&
+ ELF64_ST_TYPE(symtab_symp->st_info) ==
+ ELF64_ST_TYPE(ctf_symp->st_info) &&
+ symtab_symp->st_value == ctf_symp->st_value &&
+ symtab_symp->st_size == ctf_symp->st_size &&
+ symtab_symp->st_shndx == ctf_symp->st_shndx) {
+ if (ctf_bind == STB_GLOBAL) {
+ return (B_TRUE);
}
-found:
- if (cmo != NULL) {
- if (cmo->cmo_tid == 0)
- continue;
- if ((err = ctf_add_object(fp, i, cmo->cmo_tid)) != 0) {
- ctf_dprintf("Failed to add symbol %s->%d: %s\n",
- name, cmo->cmo_tid,
- ctf_errmsg(ctf_errno(fp)));
- return (err);
- }
+
+ if (ctf_bind == STB_LOCAL && ctf_file != NULL &&
+ symtab_file != NULL && strcmp(ctf_file, symtab_file) == 0) {
+ *is_fuzzy = B_TRUE;
+ return (B_TRUE);
}
}
- return (0);
+ if (ctf_bind == STB_GLOBAL ||
+ (ctf_bind == STB_WEAK && symtab_bind == STB_WEAK)) {
+ *is_fuzzy = B_TRUE;
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
}
+/*
+ * For each symbol, try and find a match. We will attempt to find an exact
+ * match; however, we will settle for a fuzzy match in general. There is one
+ * case where we will not opt to use a fuzzy match, which is when performing the
+ * deduplication of a container. In such a case we are trying to reduce common
+ * types and a fuzzy match would be inappropriate as if we're in the context of
+ * a single container, the conversion process should have identified any exact
+ * or fuzzy matches that were required.
+ */
static int
-ctf_merge_functions(ctf_merge_t *cmh, ctf_file_t *fp)
+ctf_merge_symbols(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
{
int err;
- ulong_t i;
- ctf_funcinfo_t fi;
+ uint_t type, bind;
+ ctf_merge_symbol_arg_t *csa = arg;
+ ctf_file_t *fp = csa->cmsa_out;
+
+ type = ELF64_ST_TYPE(symp->st_info);
+ bind = ELF64_ST_BIND(symp->st_info);
+
+ ctf_dprintf("Trying to find match for %s/%s/%u\n", file, name,
+ ELF64_ST_BIND(symp->st_info));
+
+ if (type == STT_OBJECT) {
+ ctf_merge_objmap_t *cmo, *match = NULL;
+
+ for (cmo = list_head(csa->cmsa_objmap); cmo != NULL;
+ cmo = list_next(csa->cmsa_objmap, cmo)) {
+ boolean_t is_fuzzy = B_FALSE;
+ if (ctf_merge_symbol_match(cmo->cmo_file, cmo->cmo_name,
+ &cmo->cmo_sym, file, name, symp, &is_fuzzy)) {
+ if (is_fuzzy && csa->cmsa_dedup &&
+ bind != STB_WEAK) {
+ continue;
+ }
+ match = cmo;
+ if (is_fuzzy) {
+ continue;
+ }
+ break;
+ }
+ }
- uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
- uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
-
- for (i = 0; i < fp->ctf_nsyms; i++) {
- const char *name;
- ctf_merge_input_t *cmi;
- ctf_merge_funcmap_t *cmf;
-
- if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
- const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
- int type = ELF32_ST_TYPE(symp->st_info);
- if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- } else {
- const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
- int type = ELF64_ST_TYPE(symp->st_info);
- if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
+ if (match == NULL) {
+ return (0);
}
- cmf = NULL;
- for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
- cmi = list_next(&cmh->cmh_inputs, cmi)) {
- for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
- cmf = list_next(&cmi->cmi_fmap, cmf)) {
- if (strcmp(cmf->cmf_name, name) == 0)
- goto found;
+ if ((err = ctf_add_object(fp, idx, match->cmo_tid)) != 0) {
+ ctf_dprintf("Failed to add symbol %s->%d: %s\n", name,
+ match->cmo_tid, ctf_errmsg(ctf_errno(fp)));
+ return (ctf_errno(fp));
+ }
+ ctf_dprintf("mapped object into output %s/%s->%ld\n", file,
+ name, match->cmo_tid);
+ } else {
+ ctf_merge_funcmap_t *cmf, *match = NULL;
+ ctf_funcinfo_t fi;
+
+ for (cmf = list_head(csa->cmsa_funcmap); cmf != NULL;
+ cmf = list_next(csa->cmsa_funcmap, cmf)) {
+ boolean_t is_fuzzy = B_FALSE;
+ if (ctf_merge_symbol_match(cmf->cmf_file, cmf->cmf_name,
+ &cmf->cmf_sym, file, name, symp, &is_fuzzy)) {
+ if (is_fuzzy && csa->cmsa_dedup &&
+ bind != STB_WEAK) {
+ continue;
+ }
+ match = cmf;
+ if (is_fuzzy) {
+ continue;
+ }
+ break;
}
}
-found:
- if (cmf != NULL) {
- fi.ctc_return = cmf->cmf_rtid;
- fi.ctc_argc = cmf->cmf_argc;
- fi.ctc_flags = cmf->cmf_flags;
- if ((err = ctf_add_function(fp, i, &fi,
- cmf->cmf_args)) != 0)
- return (err);
+
+ if (match == NULL) {
+ return (0);
}
+
+ fi.ctc_return = match->cmf_rtid;
+ fi.ctc_argc = match->cmf_argc;
+ fi.ctc_flags = match->cmf_flags;
+ if ((err = ctf_add_function(fp, idx, &fi, match->cmf_args)) !=
+ 0) {
+ ctf_dprintf("Failed to add function %s: %s\n", name,
+ ctf_errmsg(ctf_errno(fp)));
+ return (ctf_errno(fp));
+ }
+ ctf_dprintf("mapped function into output %s/%s\n", file,
+ name);
}
return (0);
-
}
int
@@ -1322,6 +1446,7 @@ ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
ctf_merge_input_t *final;
ctf_file_t *out;
+ ctf_dprintf("Beginning ctf_merge_merge()\n");
if (cmh->cmh_label != NULL && cmh->cmh_unique != NULL) {
const char *label = ctf_label_topmost(cmh->cmh_unique);
if (label == NULL)
@@ -1387,23 +1512,23 @@ ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
ctf_dprintf("merging symbols and the like\n");
if (cmh->cmh_msyms == B_TRUE) {
- err = ctf_merge_symbols(cmh, out);
- if (err != 0) {
- ctf_close(out);
- return (ctf_errno(out));
- }
-
- err = ctf_merge_functions(cmh, out);
+ ctf_merge_symbol_arg_t arg;
+ arg.cmsa_objmap = &final->cmi_omap;
+ arg.cmsa_funcmap = &final->cmi_fmap;
+ arg.cmsa_out = out;
+ arg.cmsa_dedup = B_FALSE;
+ err = ctf_symtab_iter(out, ctf_merge_symbols, &arg);
if (err != 0) {
ctf_close(out);
- return (ctf_errno(out));
+ return (err);
}
}
err = ctf_update(out);
if (err != 0) {
+ err = ctf_errno(out);
ctf_close(out);
- return (ctf_errno(out));
+ return (err);
}
*outp = out;
@@ -1505,29 +1630,25 @@ ctf_merge_dedup(ctf_merge_t *cmp, ctf_file_t **outp)
goto err;
ctf_dprintf("Successfully deduped types\n");
- ctf_phase_dump(cm.cm_out, "dedup-pre-syms");
+ ctf_phase_dump(cm.cm_out, "dedup-pre-syms", NULL);
/*
* Now we need to fix up the object and function maps.
*/
- ctf_merge_fixup_nontypes(&cm, cmi);
+ ctf_merge_fixup_symmaps(&cm, cmi);
if (cmp->cmh_msyms == B_TRUE) {
- ret = ctf_merge_symbols(cmp, cm.cm_out);
+ ctf_merge_symbol_arg_t arg;
+ arg.cmsa_objmap = &cmi->cmi_omap;
+ arg.cmsa_funcmap = &cmi->cmi_fmap;
+ arg.cmsa_out = cm.cm_out;
+ arg.cmsa_dedup = B_TRUE;
+ ret = ctf_symtab_iter(cm.cm_out, ctf_merge_symbols, &arg);
if (ret != 0) {
- ret = ctf_errno(cm.cm_out);
ctf_dprintf("failed to dedup symbols: %s\n",
ctf_errmsg(ret));
goto err;
}
-
- ret = ctf_merge_functions(cmp, cm.cm_out);
- if (ret != 0) {
- ret = ctf_errno(cm.cm_out);
- ctf_dprintf("failed to dedup functions: %s\n",
- ctf_errmsg(ret));
- goto err;
- }
}
ret = ctf_update(cm.cm_out);
@@ -1535,6 +1656,7 @@ ctf_merge_dedup(ctf_merge_t *cmp, ctf_file_t **outp)
cmc->cmi_input = NULL;
*outp = cm.cm_out;
}
+ ctf_phase_dump(cm.cm_out, "dedup-post-syms", NULL);
err:
ctf_merge_types_fini(&cm);
ctf_diff_fini(cdp);
diff --git a/usr/src/lib/libctf/common/libctf_impl.h b/usr/src/lib/libctf/common/libctf_impl.h
index 11193e97d0..be091ef199 100644
--- a/usr/src/lib/libctf/common/libctf_impl.h
+++ b/usr/src/lib/libctf/common/libctf_impl.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _LIBCTF_IMPL_H
@@ -41,6 +41,13 @@ extern ctf_conv_status_t ctf_dwarf_convert(int, Elf *, uint_t, int *,
ctf_file_t **, char *, size_t);
/*
+ * Symbol walking
+ */
+typedef int (*ctf_symtab_f)(const Elf64_Sym *, ulong_t, const char *,
+ const char *, boolean_t, void *);
+extern int ctf_symtab_iter(ctf_file_t *, ctf_symtab_f, void *);
+
+/*
* zlib compression routines
*/
extern int ctf_compress(ctf_file_t *fp, void **, size_t *, size_t *);
@@ -50,7 +57,8 @@ extern int ctf_diff_self(ctf_diff_t *, ctf_diff_type_f, void *);
/*
* Internal debugging aids
*/
-extern void ctf_phase_dump(ctf_file_t *, const char *);
+extern void ctf_phase_dump(ctf_file_t *, const char *, const char *);
+extern void ctf_phase_bump(void);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libcustr/common/custr.c b/usr/src/lib/libcustr/common/custr.c
index 5c5b0e370a..6d3a003e6b 100644
--- a/usr/src/lib/libcustr/common/custr.c
+++ b/usr/src/lib/libcustr/common/custr.c
@@ -14,7 +14,7 @@
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <stdlib.h>
@@ -27,6 +27,19 @@
#include "libcustr.h"
+/*
+ * libcustr is used by some things in usr/src/tools. If we are building
+ * on an older platform, __unused might not be defined on the build host.
+ * We define it here if needed.
+ */
+#ifndef __unused
+#if __GNUC_VERSION >= 20700
+#define __unused __attribute__((_unused__))
+#else
+#define __unused
+#endif /* __GNUC_VERSION */
+#endif /* __unused */
+
typedef enum {
CUSTR_FIXEDBUF = 0x01
} custr_flags_t;
@@ -36,10 +49,32 @@ struct custr {
size_t cus_datalen;
char *cus_data;
custr_flags_t cus_flags;
+ custr_alloc_t *cus_alloc;
};
+#define CUSTR_ALLOC(_cus, _len) \
+ (_cus)->cus_alloc->cua_ops->custr_ao_alloc((_cus)->cus_alloc, (_len))
+#define CUSTR_FREE(_cus, _p, _len) \
+ (_cus)->cus_alloc->cua_ops->custr_ao_free((_cus)->cus_alloc, \
+ (_p), (_len))
#define STRING_CHUNK_SIZE 64
+static void *custr_def_alloc(custr_alloc_t *, size_t);
+static void custr_def_free(custr_alloc_t *, void *, size_t);
+
+static custr_alloc_ops_t custr_alloc_ops_default = {
+ NULL, /* custr_ao_init */
+ NULL, /* custr_ao_fini */
+ custr_def_alloc, /* custr_ao_alloc */
+ custr_def_free /* custr_ao_free */
+};
+
+static custr_alloc_t custr_alloc_default = {
+ CUSTR_VERSION, /* cua_version */
+ &custr_alloc_ops_default, /* cua_ops */
+ NULL /* cua_arg */
+};
+
void
custr_reset(custr_t *cus)
{
@@ -97,7 +132,7 @@ custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap)
/*
* Allocate replacement memory:
*/
- if ((new_data = malloc(new_datalen)) == NULL) {
+ if ((new_data = CUSTR_ALLOC(cus, new_datalen)) == NULL) {
return (-1);
}
@@ -108,7 +143,7 @@ custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap)
if (cus->cus_data != NULL) {
(void) memcpy(new_data, cus->cus_data,
cus->cus_strlen + 1);
- free(cus->cus_data);
+ CUSTR_FREE(cus, cus->cus_data, cus->cus_datalen);
}
/*
@@ -155,21 +190,64 @@ custr_append(custr_t *cus, const char *name)
}
int
-custr_alloc(custr_t **cus)
+custr_alloc_init(custr_alloc_t *cua, const custr_alloc_ops_t *ops, ...)
+{
+ int ret = 0;
+
+ if (cua->cua_version != CUSTR_VERSION || ops->custr_ao_alloc == NULL ||
+ ops->custr_ao_free == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ cua->cua_ops = ops;
+ cua->cua_arg = NULL;
+
+ if (ops->custr_ao_init != NULL) {
+ va_list ap;
+
+ va_start(ap, ops);
+ ret = ops->custr_ao_init(cua, ap);
+ va_end(ap);
+ }
+
+ return ((ret == 0) ? 0 : -1);
+}
+
+void
+custr_alloc_fini(custr_alloc_t *cua)
+{
+ if (cua->cua_ops->custr_ao_fini != NULL)
+ cua->cua_ops->custr_ao_fini(cua);
+}
+
+int
+custr_xalloc(custr_t **cus, custr_alloc_t *cao)
{
custr_t *t;
- if ((t = calloc(1, sizeof (*t))) == NULL) {
+ if (cao == NULL)
+ cao = &custr_alloc_default;
+
+ if ((t = cao->cua_ops->custr_ao_alloc(cao, sizeof (*t))) == NULL) {
*cus = NULL;
return (-1);
}
+ (void) memset(t, 0, sizeof (*t));
+ t->cus_alloc = cao;
*cus = t;
return (0);
}
int
-custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
+custr_alloc(custr_t **cus)
+{
+ return (custr_xalloc(cus, NULL));
+}
+
+int
+custr_xalloc_buf(custr_t **cus, void *buf, size_t buflen, custr_alloc_t *cao)
{
int ret;
@@ -178,7 +256,7 @@ custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
return (-1);
}
- if ((ret = custr_alloc(cus)) != 0)
+ if ((ret = custr_xalloc(cus, cao)) != 0)
return (ret);
(*cus)->cus_data = buf;
@@ -190,13 +268,37 @@ custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
return (0);
}
+int
+custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
+{
+ return (custr_xalloc_buf(cus, buf, buflen, NULL));
+}
+
void
custr_free(custr_t *cus)
{
+ custr_alloc_t *cao;
+
if (cus == NULL)
return;
if ((cus->cus_flags & CUSTR_FIXEDBUF) == 0)
- free(cus->cus_data);
- free(cus);
+ CUSTR_FREE(cus, cus->cus_data, cus->cus_datalen);
+
+ cao = cus->cus_alloc;
+ cao->cua_ops->custr_ao_free(cao, cus, sizeof (*cus));
+}
+
+/*ARGSUSED*/
+static void *
+custr_def_alloc(custr_alloc_t *cao __unused, size_t len)
+{
+ return (malloc(len));
+}
+
+/*ARGSUSED*/
+static void
+custr_def_free(custr_alloc_t *cao __unused, void *p, size_t len __unused)
+{
+ free(p);
}
diff --git a/usr/src/lib/libcustr/common/libcustr.h b/usr/src/lib/libcustr/common/libcustr.h
index 7671390d7f..8fe5fee1b7 100644
--- a/usr/src/lib/libcustr/common/libcustr.h
+++ b/usr/src/lib/libcustr/common/libcustr.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
*/
#ifndef _LIBCUSTR_H
@@ -26,12 +26,78 @@ extern "C" {
#endif
typedef struct custr custr_t;
+typedef struct custr_alloc_ops custr_alloc_ops_t;
+typedef struct custr_alloc custr_alloc_t;
+
+/*
+ * A custom allocator instance. To use a custom allocator, the user provides
+ * the memory for a given custr_alloc_t and calls custr_alloc_init() with the
+ * address of the instance to initialize it. custr_alloc_init() will invoke
+ * the init op (if defined) with any additional arguments. The user can then
+ * save any desired state for the allocator instance in cua_arg. If a
+ * custom allocator instance needs to do any cleanup after it's no longer
+ * needed, it should also define the fini op and invoke custr_alloc_fini() to
+ * do the cleanup.
+ */
+#define CUSTR_VERSION 1
+struct custr_alloc {
+ uint_t cua_version;
+ const custr_alloc_ops_t *cua_ops;
+ void *cua_arg;
+};
+
+struct custr_alloc_ops {
+ /*
+ * Optional allocator constructor. Returns 0 on success, -1
+ * on failure (and should set errno on failure).
+ */
+ int (*custr_ao_init)(custr_alloc_t *, va_list);
+ /*
+ * Optional allocator destructor.
+ */
+ void (*custr_ao_fini)(custr_alloc_t *);
+ /*
+ * Returns at least size_t bytes of allocated memory, or NULL.
+ * It should also set errno on failure.
+ */
+ void *(*custr_ao_alloc)(custr_alloc_t *, size_t);
+ /*
+ * Free the memory previously allocated with custr_ao_alloc.
+ */
+ void (*custr_ao_free)(custr_alloc_t *, void *, size_t);
+};
+
+/*
+ * Initializes a custr allocator. custr_alloc_t->cua_version should be set to
+ * CUSTR_VERSION prior to calling custr_alloc_init(). Both the custr_ao_alloc
+ * and custr_ao_free functions must be defined in custr_alloc_ops_t (the
+ * init and fini functions are both optional). If an init function is
+ * provided, it will be called with a va_list parameter initialized to
+ * point to any arguments after the custr_alloc_ops_t * argument.
+ *
+ * If cua_version is not CUSTR_VERSION, or if the custr_ao_alloc or
+ * custr_ao_free functions are missing, -1 is returned and errno is set to
+ * EINVAL. If an init function was given and it fails (returns -1 -- see
+ * the struct custr_alloc_ops definition aboive), -1 is returned and any
+ * value of errno set by the init function is left unchanged.
+ *
+ * On success, 0 is returned.
+ */
+int custr_alloc_init(custr_alloc_t *, const custr_alloc_ops_t *, ...);
+
+/*
+ * If a fini function was given in the custr_alloc_init() call that initalized
+ * the given custr_alloc_t instance, it is called to perform any custom
+ * cleanup needed.
+ */
+void custr_alloc_fini(custr_alloc_t *);
/*
* Allocate and free a "custr_t" dynamic string object. Returns 0 on success
* and -1 otherwise.
*/
int custr_alloc(custr_t **);
+int custr_xalloc(custr_t **, custr_alloc_t *);
void custr_free(custr_t *);
/*
@@ -41,6 +107,13 @@ void custr_free(custr_t *);
int custr_alloc_buf(custr_t **, void *, size_t);
/*
+ * Like custr_alloc_buf(), except the given allocator is used to allocate
+ * the custr_t * instance (but still uses a fixed external buffer for the
+ * string contents).
+ */
+int custr_xalloc_buf(custr_t **, void *, size_t, custr_alloc_t *);
+
+/*
* Append a single character, or a NUL-terminated string of characters, to a
* dynamic string. Returns 0 on success and -1 otherwise. The dynamic string
* will be unmodified if the function returns -1.
diff --git a/usr/src/lib/libcustr/common/mapfile-vers b/usr/src/lib/libcustr/common/mapfile-vers
index 369771929a..f94636b6f5 100644
--- a/usr/src/lib/libcustr/common/mapfile-vers
+++ b/usr/src/lib/libcustr/common/mapfile-vers
@@ -10,7 +10,7 @@
#
#
-# Copyright 2018, Joyent, Inc.
+# Copyright 2019, Joyent, Inc.
#
#
@@ -33,6 +33,8 @@ SYMBOL_VERSION ILLUMOSprivate {
global:
custr_alloc;
custr_alloc_buf;
+ custr_alloc_fini;
+ custr_alloc_init;
custr_append;
custr_appendc;
custr_append_printf;
@@ -41,6 +43,8 @@ SYMBOL_VERSION ILLUMOSprivate {
custr_free;
custr_len;
custr_reset;
+ custr_xalloc;
+ custr_xalloc_buf;
local:
*;
};
diff --git a/usr/src/lib/libdemangle/Makefile.com b/usr/src/lib/libdemangle/Makefile.com
index 0b0d495df7..7eba05ce1c 100644
--- a/usr/src/lib/libdemangle/Makefile.com
+++ b/usr/src/lib/libdemangle/Makefile.com
@@ -16,12 +16,12 @@
LIBRARY = libdemangle-sys.a
VERS = .1
-OBJECTS = str.o util.o cxx_util.o cxx.o demangle.o
+OBJECTS = str.o strview.o util.o cxx_util.o cxx.o demangle.o rust.o
include ../../Makefile.lib
LIBS = $(DYNLIB) $(LINTLIB)
-LDLIBS += -lc
+LDLIBS += -lc -lcustr
SRCDIR = ../common
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
diff --git a/usr/src/lib/libdemangle/common/cxx.c b/usr/src/lib/libdemangle/common/cxx.c
index e3b4c06a8a..af5f549f78 100644
--- a/usr/src/lib/libdemangle/common/cxx.c
+++ b/usr/src/lib/libdemangle/common/cxx.c
@@ -165,11 +165,10 @@ static const char *parse_vector_type(const char *, const char *, cpp_db_t *);
size_t cpp_name_max_depth = 1024; /* max depth of name stack */
char *
-cpp_demangle(const char *src, sysdem_ops_t *ops)
+cpp_demangle(const char *src, size_t srclen, sysdem_ops_t *ops)
{
char *result = NULL;
cpp_db_t db;
- size_t srclen = strlen(src);
if (!db_init(&db, ops))
goto done;
diff --git a/usr/src/lib/libdemangle/common/demangle-sys.h b/usr/src/lib/libdemangle/common/demangle-sys.h
index 02636c9521..05776ee5ee 100644
--- a/usr/src/lib/libdemangle/common/demangle-sys.h
+++ b/usr/src/lib/libdemangle/common/demangle-sys.h
@@ -11,6 +11,7 @@
/*
* Copyright 2017 Jason King
+ * Copyright 2018, Joyent, Inc.
*/
#ifndef _DEMANGLE_SYS_H
@@ -24,7 +25,8 @@ extern "C" {
typedef enum sysdem_lang_e {
SYSDEM_LANG_AUTO,
- SYSDEM_LANG_CPP
+ SYSDEM_LANG_CPP,
+ SYSDEM_LANG_RUST
} sysdem_lang_t;
typedef struct sysdem_alloc_s {
diff --git a/usr/src/lib/libdemangle/common/demangle.c b/usr/src/lib/libdemangle/common/demangle.c
index e827fd8cec..4f8e9ad678 100644
--- a/usr/src/lib/libdemangle/common/demangle.c
+++ b/usr/src/lib/libdemangle/common/demangle.c
@@ -11,13 +11,17 @@
/*
* Copyright 2018 Jason King
+ * Copyright 2019, Joyent, Inc.
*/
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
+#include <sys/ctype.h>
#include <sys/debug.h>
+#include <stdarg.h>
#include "demangle-sys.h"
#include "demangle_int.h"
@@ -25,31 +29,63 @@
static pthread_once_t debug_once = PTHREAD_ONCE_INIT;
volatile boolean_t demangle_debug;
+FILE *debugf = stderr;
+
+static const char *
+langstr(sysdem_lang_t lang)
+{
+ switch (lang) {
+ case SYSDEM_LANG_AUTO:
+ return ("auto");
+ case SYSDEM_LANG_CPP:
+ return ("c++");
+ case SYSDEM_LANG_RUST:
+ return ("rust");
+ default:
+ return ("invalid");
+ }
+}
static sysdem_lang_t
-detect_lang(const char *str)
+detect_lang(const char *str, size_t n)
{
- size_t n = strlen(str);
+ const char *p = str;
+ size_t len;
if (n < 3 || str[0] != '_')
return (SYSDEM_LANG_AUTO);
- switch (str[1]) {
- case 'Z':
+ /*
+ * Check for ^_Z or ^__Z
+ */
+ p = str + 1;
+ if (*p == '_') {
+ p++;
+ }
+
+ if (*p != 'Z')
+ return (SYSDEM_LANG_AUTO);
+
+ /*
+ * Sadly, rust currently uses the same prefix as C++, however
+ * demangling rust as a C++ mangled name yields less than desirable
+ * results. However rust names end with a hash. We use that to
+ * attempt to disambiguate
+ */
+
+ /* Find 'h'<hexdigit>+E$ */
+ if ((p = strrchr(p, 'h')) == NULL)
return (SYSDEM_LANG_CPP);
- case '_':
- break;
+ if ((len = strspn(p + 1, "0123456789abcdef")) == 0)
+ return (SYSDEM_LANG_CPP);
- default:
- return (SYSDEM_LANG_AUTO);
- }
+ p += len + 1;
- /* why they use ___Z sometimes is puzzling... *sigh* */
- if (str[2] == '_' && str[3] == 'Z')
+ if (p[0] != 'E' || p[1] != '\0')
return (SYSDEM_LANG_CPP);
- return (SYSDEM_LANG_AUTO);
+ return (SYSDEM_LANG_RUST);
}
static void
@@ -62,26 +98,76 @@ check_debug(void)
char *
sysdemangle(const char *str, sysdem_lang_t lang, sysdem_ops_t *ops)
{
+ /*
+ * While the language specific demangler code can handle non-NUL
+ * terminated strings, we currently don't expose this to consumers.
+ * Consumers should still pass in a NUL-terminated string.
+ */
+ size_t slen;
+
VERIFY0(pthread_once(&debug_once, check_debug));
+ DEMDEBUG("name = '%s'", (str == NULL) ? "(NULL)" : str);
+ DEMDEBUG("lang = %s (%d)", langstr(lang), lang);
+
+ if (str == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ slen = strlen(str);
+
+ switch (lang) {
+ case SYSDEM_LANG_AUTO:
+ case SYSDEM_LANG_CPP:
+ case SYSDEM_LANG_RUST:
+ break;
+ default:
+ errno = EINVAL;
+ return (NULL);
+ }
+
if (ops == NULL)
ops = sysdem_ops_default;
if (lang == SYSDEM_LANG_AUTO) {
- lang = detect_lang(str);
- if (lang == SYSDEM_LANG_AUTO) {
- errno = ENOTSUP;
- return (NULL);
- }
+ lang = detect_lang(str, slen);
+ if (lang != SYSDEM_LANG_AUTO)
+ DEMDEBUG("detected language is %s", langstr(lang));
}
switch (lang) {
- case SYSDEM_LANG_AUTO:
- break;
case SYSDEM_LANG_CPP:
- return (cpp_demangle(str, ops));
+ return (cpp_demangle(str, slen, ops));
+ case SYSDEM_LANG_RUST:
+ return (rust_demangle(str, slen, ops));
+ case SYSDEM_LANG_AUTO:
+ DEMDEBUG("could not detect language");
+ errno = ENOTSUP;
+ return (NULL);
+ default:
+ /*
+ * This can't happen unless there's a bug with detect_lang,
+ * but gcc doesn't know that.
+ */
+ errno = EINVAL;
+ return (NULL);
}
+}
- errno = ENOTSUP;
- return (NULL);
+int
+demdebug(const char *fmt, ...)
+{
+ va_list ap;
+
+ flockfile(debugf);
+ (void) fprintf(debugf, "LIBDEMANGLE: ");
+ va_start(ap, fmt);
+ (void) vfprintf(debugf, fmt, ap);
+ (void) fputc('\n', debugf);
+ (void) fflush(debugf);
+ va_end(ap);
+ funlockfile(debugf);
+
+ return (0);
}
diff --git a/usr/src/lib/libdemangle/common/demangle_int.h b/usr/src/lib/libdemangle/common/demangle_int.h
index 9abb2cc295..66a34cf41d 100644
--- a/usr/src/lib/libdemangle/common/demangle_int.h
+++ b/usr/src/lib/libdemangle/common/demangle_int.h
@@ -11,6 +11,7 @@
/*
* Copyright 2017 Jason King
+ * Copyright 2019, Joyent, Inc.
*/
#ifndef _DEMANGLE_INT_H
#define _DEMANGLE_INT_H
@@ -24,14 +25,26 @@ extern "C" {
extern sysdem_ops_t *sysdem_ops_default;
-char *cpp_demangle(const char *, sysdem_ops_t *);
+char *cpp_demangle(const char *, size_t, sysdem_ops_t *);
+char *rust_demangle(const char *, size_t, sysdem_ops_t *);
void *zalloc(sysdem_ops_t *, size_t);
void *xrealloc(sysdem_ops_t *, void *, size_t, size_t);
void xfree(sysdem_ops_t *, void *, size_t);
+char *xstrdup(sysdem_ops_t *, const char *);
extern volatile boolean_t demangle_debug;
+/*
+ * gcc seems to get unhappy with the ASSERT() style definition (also borrowed
+ * for the DEMDEBUG macro unless demdebug() is returns a non-void value
+ * (despite the return value never being used).
+ */
+int demdebug(const char *, ...);
+
+#define DEMDEBUG(s, ...) \
+ ((void)(demangle_debug && demdebug(s, ## __VA_ARGS__)))
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libdemangle/common/rust.c b/usr/src/lib/libdemangle/common/rust.c
new file mode 100644
index 0000000000..f99fe79a10
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/rust.c
@@ -0,0 +1,543 @@
+/*
+ * 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 2019, Joyent, Inc.
+ */
+
+#include <errno.h>
+#include <libcustr.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/ctype.h> /* We want the C locale ISXXX() versions */
+#include <sys/debug.h>
+#include <stdio.h>
+#include <sys/sysmacros.h>
+
+#include "strview.h"
+#include "demangle_int.h"
+
+/*
+ * Unfortunately, there is currently no official specification for the rust
+ * name mangling. This is an attempt to document the understanding of the
+ * mangling used here. It is based off examination of
+ * https://docs.rs/rustc-demangle/0.1.13/rustc_demangle/
+ *
+ * A mangled rust name is:
+ * <prefix> <name> <hash> E
+ *
+ * <prefix> ::= _Z
+ * __Z
+ *
+ * <name> ::= <name-segment>+
+ *
+ * <name-segment> ::= <len> <name-chars>{len}
+ *
+ * <len> ::= [1-9][0-9]+
+ *
+ * <name-chars> ::= <[A-Za-z]> <[A-Za-z0-9]>*
+ * <separator>
+ * <special>
+ *
+ * <separator> ::= '..' # '::'
+ *
+ * <special> ::= $SP$ # ' '
+ * $BP$ # '*'
+ * $RF$ # '&'
+ * $LT$ # '<'
+ * $GT$ # '>'
+ * $LP$ # '('
+ * $RP$ # ')'
+ * $C$ # ','
+ * $u7e$ # '~'
+ * $u20$ # ' '
+ * $u27$ # '\''
+ * $u3d$ # '='
+ * $u5b$ # '['
+ * $u5d$ # ']'
+ * $u7b$ # '{'
+ * $u7d$ # '}'
+ * $u3b$ # ';'
+ * $u2b$ # '+'
+ * $u22$ # '"'
+ *
+ * <hash> := <len> h <hex-digits>+
+ *
+ * <hex-digits> := <[0-9a-f]>
+ */
+
+typedef struct rustdem_state {
+ const char *rds_str;
+ custr_t *rds_demangled;
+ sysdem_ops_t *rds_ops;
+ int rds_error;
+} rustdem_state_t;
+
+static const struct rust_charmap {
+ const char *ruc_seq;
+ char ruc_ch;
+} rust_charmap[] = {
+ { "$SP$", '@' },
+ { "$BP$", '*' },
+ { "$RF$", '&' },
+ { "$LT$", '<' },
+ { "$GT$", '>' },
+ { "$LP$", '(' },
+ { "$RP$", ')' },
+ { "$C$", ',' },
+ { "$u7e$", '~' },
+ { "$u20$", ' ' },
+ { "$u27$", '\'' },
+ { "$u3d$", '=' },
+ { "$u5b$", '[' },
+ { "$u5d$", ']' },
+ { "$u7b$", '{' },
+ { "$u7d$", '}' },
+ { "$u3b$", ';' },
+ { "$u2b$", '+' },
+ { "$u22$", '"' }
+};
+static const size_t rust_charmap_sz = ARRAY_SIZE(rust_charmap);
+
+static void *rustdem_alloc(custr_alloc_t *, size_t);
+static void rustdem_free(custr_alloc_t *, void *, size_t);
+
+static boolean_t rustdem_append_c(rustdem_state_t *, char);
+static boolean_t rustdem_all_ascii(const strview_t *);
+
+static boolean_t rustdem_parse_prefix(rustdem_state_t *, strview_t *);
+static boolean_t rustdem_parse_name(rustdem_state_t *, strview_t *);
+static boolean_t rustdem_parse_hash(rustdem_state_t *, strview_t *);
+static boolean_t rustdem_parse_num(rustdem_state_t *, strview_t *, uint64_t *);
+static boolean_t rustdem_parse_special(rustdem_state_t *, strview_t *);
+static boolean_t rustdem_add_sep(rustdem_state_t *);
+
+char *
+rust_demangle(const char *s, size_t slen, sysdem_ops_t *ops)
+{
+ rustdem_state_t st = {
+ .rds_str = s,
+ .rds_ops = ops,
+ };
+ custr_alloc_ops_t custr_ops = {
+ .custr_ao_alloc = rustdem_alloc,
+ .custr_ao_free = rustdem_free
+ };
+ custr_alloc_t custr_alloc = {
+ .cua_version = CUSTR_VERSION
+ };
+ strview_t sv;
+ int ret;
+
+ if (custr_alloc_init(&custr_alloc, &custr_ops) != 0)
+ return (NULL);
+ custr_alloc.cua_arg = &st;
+
+ sv_init_str(&sv, s, s + slen);
+
+ if (sv_remaining(&sv) < 1 || sv_peek(&sv, -1) != 'E') {
+ DEMDEBUG("ERROR: string is either too small or does not end "
+ "with 'E'");
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (!rustdem_parse_prefix(&st, &sv)) {
+ DEMDEBUG("ERROR: could not parse prefix");
+ errno = EINVAL;
+ return (NULL);
+ }
+ DEMDEBUG("parsed prefix; remaining='%.*s'", SV_PRINT(&sv));
+
+ if (!rustdem_all_ascii(&sv)) {
+ /* rustdem_all_ascii() provides debug output */
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((ret = custr_xalloc(&st.rds_demangled, &custr_alloc)) != 0)
+ return (NULL);
+
+ while (sv_remaining(&sv) > 1) {
+ if (rustdem_parse_name(&st, &sv))
+ continue;
+ if (st.rds_error != 0)
+ goto fail;
+ }
+
+ if (st.rds_error != 0 || !sv_consume_if_c(&sv, 'E'))
+ goto fail;
+
+ char *res = xstrdup(ops, custr_cstr(st.rds_demangled));
+ if (res == NULL) {
+ st.rds_error = errno;
+ goto fail;
+ }
+
+ custr_free(st.rds_demangled);
+ DEMDEBUG("result = '%s'", res);
+ return (res);
+
+fail:
+ custr_free(st.rds_demangled);
+ errno = st.rds_error;
+ return (NULL);
+}
+
+static boolean_t
+rustdem_parse_prefix(rustdem_state_t *st, strview_t *svp)
+{
+ strview_t pfx;
+
+ sv_init_sv(&pfx, svp);
+
+ DEMDEBUG("checking for '_ZN' or '__ZN' in '%.*s'", SV_PRINT(&pfx));
+
+ if (st->rds_error != 0)
+ return (B_FALSE);
+
+ if (!sv_consume_if_c(&pfx, '_'))
+ return (B_FALSE);
+
+ (void) sv_consume_if_c(&pfx, '_');
+
+ if (!sv_consume_if_c(&pfx, 'Z') || !sv_consume_if_c(&pfx, 'N'))
+ return (B_FALSE);
+
+ /* Update svp with new position */
+ sv_init_sv(svp, &pfx);
+ return (B_TRUE);
+}
+
+static boolean_t
+rustdem_parse_name_segment(rustdem_state_t *st, strview_t *svp, boolean_t first)
+{
+ strview_t sv;
+ strview_t name;
+ uint64_t len;
+ size_t rem;
+ boolean_t last = B_FALSE;
+
+ if (st->rds_error != 0 || sv_remaining(svp) == 0)
+ return (B_FALSE);
+
+ sv_init_sv(&sv, svp);
+
+ if (!rustdem_parse_num(st, &sv, &len)) {
+ DEMDEBUG("ERROR: no leading length");
+ st->rds_error = EINVAL;
+ return (B_FALSE);
+ }
+
+ rem = sv_remaining(&sv);
+
+ if (rem < len || len > SIZE_MAX) {
+ st->rds_error = EINVAL;
+ return (B_FALSE);
+ }
+
+ /* Is this the last segment before the terminating E? */
+ if (rem == len + 1) {
+ VERIFY3U(sv_peek(&sv, -1), ==, 'E');
+ last = B_TRUE;
+ }
+
+ if (!first && !rustdem_add_sep(st))
+ return (B_FALSE);
+
+ /* Reduce length of seg to the length we parsed */
+ (void) sv_init_sv_range(&name, &sv, len);
+
+ DEMDEBUG("%s: segment='%.*s'", __func__, SV_PRINT(&name));
+
+ /*
+ * A rust hash starts with 'h', and is the last component of a name
+ * before the terminating 'E'
+ */
+ if (sv_peek(&name, 0) == 'h' && last) {
+ if (!rustdem_parse_hash(st, &name))
+ return (B_FALSE);
+ goto done;
+ }
+
+ while (sv_remaining(&name) > 0) {
+ switch (sv_peek(&name, 0)) {
+ case '$':
+ if (rustdem_parse_special(st, &name))
+ continue;
+ break;
+ case '_':
+ if (sv_peek(&name, 1) == '$') {
+ /*
+ * Only consume/ignore '_'. Leave
+ * $ for next round.
+ */
+ sv_consume_n(&name, 1);
+ continue;
+ }
+ break;
+ case '.':
+ /* Convert '..' to '::' */
+ if (sv_peek(&name, 1) != '.')
+ break;
+
+ if (!rustdem_add_sep(st))
+ return (B_FALSE);
+
+ sv_consume_n(&name, 2);
+ continue;
+ default:
+ break;
+ }
+
+ if (custr_appendc(st->rds_demangled,
+ sv_consume_c(&name)) != 0) {
+ st->rds_error = ENOMEM;
+ return (B_FALSE);
+ }
+ }
+
+done:
+ DEMDEBUG("%s: consumed '%.*s'", __func__, (int)len, svp->sv_first);
+ sv_consume_n(&sv, len);
+ sv_init_sv(svp, &sv);
+ return (B_TRUE);
+}
+
+static boolean_t
+rustdem_parse_name(rustdem_state_t *st, strview_t *svp)
+{
+ strview_t name;
+ boolean_t first = B_TRUE;
+
+ if (st->rds_error != 0)
+ return (B_FALSE);
+
+ sv_init_sv(&name, svp);
+
+ if (sv_remaining(&name) == 0)
+ return (B_FALSE);
+
+ while (sv_remaining(&name) > 0 && sv_peek(&name, 0) != 'E') {
+ if (!rustdem_parse_name_segment(st, &name, first))
+ return (B_FALSE);
+ first = B_FALSE;
+ }
+
+ sv_init_sv(svp, &name);
+ return (B_TRUE);
+}
+
+static boolean_t
+rustdem_parse_hash(rustdem_state_t *st, strview_t *svp)
+{
+ strview_t sv;
+
+ sv_init_sv(&sv, svp);
+
+ VERIFY(sv_consume_if_c(&sv, 'h'));
+ if (!rustdem_append_c(st, 'h'))
+ return (B_FALSE);
+
+ while (sv_remaining(&sv) > 0) {
+ char c = sv_consume_c(&sv);
+
+ switch (c) {
+ /*
+ * The upper-case hex digits (A-F) are excluded as valid
+ * hash values for several reasons:
+ *
+ * 1. It would result in two different possible names for
+ * the same function, leading to ambiguity in linking (among
+ * other things).
+ *
+ * 2. It would cause potential ambiguity in parsing -- is a
+ * trailing 'E' part of the hash, or the terminating character
+ * in the mangled name?
+ *
+ * 3. No examples were able to be found in the wild where
+ * uppercase digits are used, and other rust demanglers all
+ * seem to assume the hash must contain lower-case hex digits.
+ */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9': case 'a': case 'b':
+ case 'c': case 'd': case 'e': case 'f':
+ if (!rustdem_append_c(st, c))
+ return (B_FALSE);
+ break;
+ default:
+ return (B_FALSE);
+ }
+ }
+
+ sv_init_sv(svp, &sv);
+ return (B_TRUE);
+}
+
+/*
+ * A 10 digit value would imply a name 1Gb or larger in size. It seems
+ * unlikely to the point of absurdity any such value could every possibly
+ * be valid (or even have compiled properly). This also prevents the
+ * uint64_t conversion from possibly overflowing since the value must always
+ * be below 10 * UINT32_MAX.
+ */
+#define MAX_DIGITS 10
+
+static boolean_t
+rustdem_parse_num(rustdem_state_t *restrict st, strview_t *restrict svp,
+ uint64_t *restrict valp)
+{
+ strview_t snum;
+ uint64_t v = 0;
+ size_t ndigits = 0;
+ char c;
+
+ if (st->rds_error != 0)
+ return (B_FALSE);
+
+ sv_init_sv(&snum, svp);
+
+ DEMDEBUG("%s: str='%.*s'", __func__, SV_PRINT(&snum));
+
+ c = sv_peek(&snum, 0);
+ if (!ISDIGIT(c)) {
+ DEMDEBUG("%s: ERROR no digits in str\n", __func__);
+ st->rds_error = EINVAL;
+ return (B_FALSE);
+ }
+
+ /*
+ * Since there is currently no official specification on rust name
+ * mangling, only that it has been stated that rust follows what
+ * C++ mangling does. In the Itanium C++ ABI (what practically
+ * every non-Windows C++ implementation uses these days), it
+ * explicitly disallows leading 0s in numeric values (except for
+ * substition and template indexes, which aren't relevant here).
+ * We enforce the same restriction -- if a rust implementation allowed
+ * leading zeros in numbers (basically segment lengths) it'd
+ * cause all sorts of ambiguity problems with names that likely lead
+ * to much bigger problems with linking and such, so this seems
+ * reasonable.
+ */
+ if (c == '0') {
+ DEMDEBUG("%s: ERROR number starts with leading 0\n", __func__);
+ st->rds_error = EINVAL;
+ return (B_FALSE);
+ }
+
+ while (sv_remaining(&snum) > 0 && ndigits <= MAX_DIGITS) {
+ c = sv_consume_c(&snum);
+
+ if (!ISDIGIT(c))
+ break;
+
+ v *= 10;
+ v += c - '0';
+ ndigits++;
+ }
+
+ if (ndigits > MAX_DIGITS) {
+ DEMDEBUG("%s: value %llu is too large\n", __func__, v);
+ st->rds_error = ERANGE;
+ return (B_FALSE);
+ }
+
+ DEMDEBUG("%s: num=%llu", __func__, v);
+
+ *valp = v;
+ sv_consume_n(svp, ndigits);
+ return (B_TRUE);
+}
+
+static boolean_t
+rustdem_parse_special(rustdem_state_t *restrict st, strview_t *restrict svp)
+{
+ if (st->rds_error != 0)
+ return (B_FALSE);
+
+ if (sv_peek(svp, 0) != '$')
+ return (B_FALSE);
+
+ for (size_t i = 0; i < rust_charmap_sz; i++) {
+ if (sv_consume_if(svp, rust_charmap[i].ruc_seq)) {
+ if (!rustdem_append_c(st, rust_charmap[i].ruc_ch))
+ return (B_FALSE);
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+static boolean_t
+rustdem_add_sep(rustdem_state_t *st)
+{
+ if (st->rds_error != 0)
+ return (B_FALSE);
+
+ if (!rustdem_append_c(st, ':') ||
+ !rustdem_append_c(st, ':'))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+static boolean_t
+rustdem_append_c(rustdem_state_t *st, char c)
+{
+ if (st->rds_error != 0)
+ return (B_FALSE);
+
+ if (custr_appendc(st->rds_demangled, c) == 0)
+ return (B_TRUE);
+
+ st->rds_error = errno;
+ return (B_FALSE);
+}
+
+static boolean_t
+rustdem_all_ascii(const strview_t *svp)
+{
+ strview_t p;
+
+ sv_init_sv(&p, svp);
+
+ while (sv_remaining(&p) > 0) {
+ char c = sv_consume_c(&p);
+
+ /*
+ * #including <sys/ctype.h> conflicts with <ctype.h>. Since
+ * we want the C locale macros (ISDIGIT, etc), it also means
+ * we can't use isascii(3C).
+ */
+ if ((c & 0x80) != 0) {
+ DEMDEBUG("%s: found non-ascii character 0x%02hhx at "
+ "offset %tu", __func__, c,
+ (ptrdiff_t)(p.sv_first - svp->sv_first));
+ return (B_FALSE);
+ }
+ }
+ return (B_TRUE);
+}
+
+static void *
+rustdem_alloc(custr_alloc_t *cao, size_t len)
+{
+ rustdem_state_t *st = cao->cua_arg;
+ return (zalloc(st->rds_ops, len));
+}
+
+static void
+rustdem_free(custr_alloc_t *cao, void *p, size_t len)
+{
+ rustdem_state_t *st = cao->cua_arg;
+ xfree(st->rds_ops, p, len);
+}
diff --git a/usr/src/lib/libdemangle/common/strview.c b/usr/src/lib/libdemangle/common/strview.c
new file mode 100644
index 0000000000..e4576ee17a
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/strview.c
@@ -0,0 +1,107 @@
+/*
+ * 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 2019, Joyent, Inc.
+ */
+
+#include <string.h>
+#include <sys/debug.h>
+#include "strview.h"
+
+void
+sv_init_sv(strview_t *sv, const strview_t *src)
+{
+ *sv = *src;
+}
+
+void
+sv_init_sv_range(strview_t *sv, const strview_t *src, size_t len)
+{
+ VERIFY3U(sv_remaining(src), >=, len);
+
+ sv->sv_first = src->sv_first;
+ sv->sv_last = src->sv_first + len;
+ sv->sv_rem = len;
+}
+
+void
+sv_init_str(strview_t *sv, const char *first, const char *last)
+{
+ if (last == NULL)
+ last = first + strlen(first);
+
+ VERIFY3P(first, <=, last);
+ sv->sv_first = first;
+ sv->sv_last = last;
+ sv->sv_rem = (size_t)(uintptr_t)(sv->sv_last - sv->sv_first);
+}
+
+size_t
+sv_remaining(const strview_t *sv)
+{
+ return (sv->sv_rem);
+}
+
+boolean_t
+sv_consume_if_c(strview_t *sv, char c)
+{
+ if (sv->sv_rem < 1 || *sv->sv_first != c)
+ return (B_FALSE);
+
+ sv->sv_first++;
+ sv->sv_rem--;
+ return (B_TRUE);
+}
+
+boolean_t
+sv_consume_if(strview_t *sv, const char *str)
+{
+ size_t slen = strlen(str);
+
+ if (sv->sv_rem < slen)
+ return (B_FALSE);
+ if (strncmp(sv->sv_first, str, slen) != 0)
+ return (B_FALSE);
+
+ sv->sv_first += slen;
+ sv->sv_rem -= slen;
+ return (B_TRUE);
+}
+
+char
+sv_peek(const strview_t *sv, ssize_t n)
+{
+ const char *p;
+
+ p = (n >= 0) ? sv->sv_first + n : sv->sv_last + n;
+ return ((p >= sv->sv_first && p < sv->sv_last) ? *p : '\0');
+}
+
+char
+sv_consume_c(strview_t *sv)
+{
+ char c = '\0';
+
+ if (sv->sv_first < sv->sv_last) {
+ c = *sv->sv_first++;
+ sv->sv_rem--;
+ }
+ return (c);
+}
+
+void
+sv_consume_n(strview_t *sv, size_t n)
+{
+ VERIFY3U(sv->sv_rem, >=, n);
+ sv->sv_first += n;
+ sv->sv_rem -= n;
+}
diff --git a/usr/src/lib/libdemangle/common/strview.h b/usr/src/lib/libdemangle/common/strview.h
new file mode 100644
index 0000000000..ac94c67c6c
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/strview.h
@@ -0,0 +1,140 @@
+/*
+ * 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 2019, Joyent, Inc.
+ */
+
+#ifndef _STRVIEW_H
+#define _STRVIEW_H
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * strview_t's represent a read-only subset of a string. It is somewhat
+ * similar to the concept of ranges found in other languages in that one can
+ * create a strview_t, and then create a smaller range for iteration.
+ *
+ * sv_first is the address of the first location (and is advanced as values
+ * are consumed) in the string.
+ *
+ * sv_last is the address one byte after the last valid value of the subset.
+ * Basically, the length of the range is equal to 'sv_last - sv_first'. For
+ * example, in the string 'abcdef' to create a view 'bcd', *sv_first would
+ * equal 'b' and *sv_last would equal 'e'.
+ *
+ * sv_rem is the number of bytes remaining in the range.
+ *
+ * A strview_t maintains references to the underlying string, so the lifetime
+ * of a strview_t should be equal to or less than the underlying string (i.e.
+ * it doesn't copy the data from the underlying string, but maintains pointers
+ * to the original data).
+ *
+ * While the underlying string does not need to be NUL-terminated, NUL is still
+ * used as a sentinel value in some instances (e.g. sv_peek()), and should not
+ * be contained within the defined range.
+ *
+ * As hinted above, the functions currently do not deal with multi-byte
+ * characters, i.e. each character is assumed to be a single byte. The
+ * current consumers do not need to handle multi-byte characters (UTF-8
+ * or otherwise), so this is sufficient at the current time.
+ */
+typedef struct strview {
+ const char *sv_first;
+ const char *sv_last;
+ size_t sv_rem;
+} strview_t;
+
+/*
+ * SV_PRINT() is used for printing strview_t values during debugging, e.g.
+ * `DEMDEBUG("%*.s", SV_PRINT(sv));`
+ */
+#define SV_PRINT(_sv) (int)(_sv)->sv_rem, (_sv)->sv_first
+
+/*
+ * Initialize a strview_t from an already initialized strview_t -- the state of
+ * the source strview_t is duplicated in the newly initialized strview_t.
+ */
+void sv_init_sv(strview_t *, const strview_t *);
+
+/*
+ * Initialize a strview_t as a subset of an already initialized strview_t.
+ * The size of the subset (size_t) must be <= sv_remaining(src).
+ */
+void sv_init_sv_range(strview_t *, const strview_t *, size_t);
+
+/*
+ * Initialize a strview_t from a string. The two const char * pointers are the
+ * sv_first and sv_last values to use (see above). If the source string is
+ * NUL-terminated, one can optionally pass NULL for the second parameter in
+ * which case, the entire NUL-terminated string (starting at sv_first) is
+ * treated as a strview_t.
+ */
+void sv_init_str(strview_t *, const char *, const char *);
+
+/*
+ * Return the number of bytes remaining to consume in the strview_t
+ */
+size_t sv_remaining(const strview_t *);
+
+/*
+ * Return the char at the given position in the strview_t (without advancing
+ * the position). Position values >=0 are relative to the current position
+ * of the strview_t (e.g. '0' will return the next character, '1' will return
+ * the character after that), while negative position values are relative to
+ * the end of the strview_t (e.g. '-1' will return the last character, '-2'
+ * will return the second to last character).
+ *
+ * If the position value is out of range, '\0' is returned.
+ */
+char sv_peek(const strview_t *, ssize_t);
+
+/*
+ * Return the next character and advance the strview_t position. If no more
+ * characters are available, '\0' is returned.
+ */
+char sv_consume_c(strview_t *);
+
+/*
+ * Advance the position of the strview_t by the given number of bytes. The
+ * amount must be <= the number of bytes remaining in the strview_t.
+ */
+void sv_consume_n(strview_t *, size_t);
+
+/*
+ * Advance the strview_t position if the bytes of the strview starting at the
+ * current position match the given NUL-terminated string. The length of the
+ * NUL-terminated string must be <= the number of bytes remaining in the
+ * strview_t.
+ *
+ * If there is a match, the position of the strview_t is advanced by the
+ * length of the NUL-terminated comparison string, and B_TRUE is returned. If
+ * there is no match, the position is not advanced and B_FALSE is returned.
+ */
+boolean_t sv_consume_if(strview_t *, const char *);
+
+/*
+ * Advance the position of the strview_t if the next char in the strview_t
+ * is equal to the given char. If there is a match, the strview_t position
+ * is advanced one byte and B_TRUE is returned. If they do not match, B_FALSE
+ * is returned and the position is not advanced.
+ */
+boolean_t sv_consume_if_c(strview_t *, char);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STRVIEW_H */
diff --git a/usr/src/lib/libdemangle/common/util.c b/usr/src/lib/libdemangle/common/util.c
index 9ffb72c79b..739c554826 100644
--- a/usr/src/lib/libdemangle/common/util.c
+++ b/usr/src/lib/libdemangle/common/util.c
@@ -11,6 +11,7 @@
/*
* Copyright 2017 Jason King
+ * Copyright 2019, Joyent, Inc.
*/
#include <sys/debug.h>
@@ -71,6 +72,20 @@ xrealloc(sysdem_ops_t *ops, void *p, size_t oldsz, size_t newsz)
return (temp);
}
+char *
+xstrdup(sysdem_ops_t *ops, const char *src)
+{
+ size_t len = strlen(src);
+ char *str = zalloc(ops, len + 1);
+
+ if (str == NULL)
+ return (NULL);
+
+ /* zalloc(len+1) guarantees this will be NUL-terminated */
+ (void) memcpy(str, src, len);
+ return (str);
+}
+
/*ARGSUSED*/
static void
def_free(void *p, size_t len)
diff --git a/usr/src/lib/libdns_sd/Makefile.com b/usr/src/lib/libdns_sd/Makefile.com
index 84dfcd0c5e..44b7b6c104 100644
--- a/usr/src/lib/libdns_sd/Makefile.com
+++ b/usr/src/lib/libdns_sd/Makefile.com
@@ -38,7 +38,7 @@ LDLIBS += -lsocket -lnsl -lc
CSTD = $(CSTD_GNU99)
CPPFLAGS += -I$(SRCDIR) -DNOT_HAVE_SA_LEN -D_XPG4_2 -D__EXTENSIONS__
-CPPFLAGS += -DMDNS_VERSIONSTR_NODTS
+CPPFLAGS += -DMDNS_VERSIONSTR_NODTS -DmDNSResponderVersion=878.1.1
pics/dnssd_clientstub.o := CERRWARN += -_gcc=-Wno-unused-but-set-variable
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/kstat.c b/usr/src/lib/libfakekernel/common/kstat.c
index 849f0ddf0e..4b6d2baa08 100644
--- a/usr/src/lib/libfakekernel/common/kstat.c
+++ b/usr/src/lib/libfakekernel/common/kstat.c
@@ -12,6 +12,7 @@
/*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 RackTop Systems.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/types.h>
@@ -42,6 +43,11 @@ kstat_named_init(kstat_named_t *knp, const char *name, uchar_t type)
/*ARGSUSED*/
void
+kstat_named_setstr(kstat_named_t *knp, const char *src)
+{}
+
+/*ARGSUSED*/
+void
kstat_install(kstat_t *ksp)
{}
diff --git a/usr/src/lib/libfakekernel/common/mapfile-vers b/usr/src/lib/libfakekernel/common/mapfile-vers
index 1c41dd9b58..c7aa5a8f7d 100644
--- a/usr/src/lib/libfakekernel/common/mapfile-vers
+++ b/usr/src/lib/libfakekernel/common/mapfile-vers
@@ -13,7 +13,7 @@
# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
# Copyright (c) 2017, Joyent, Inc.
# Copyright 2017 RackTop Systems.
-# Copyright 2018, Joyent, Inc.
+# Copyright 2019, Joyent, Inc.
#
#
@@ -43,7 +43,9 @@ SYMBOL_VERSION SUNWprivate_1.1 {
aok { FLAGS = NODIRECT };
boot_time;
cmn_err;
+ copyin;
copyinstr;
+ copyout;
copystr;
cyclic_add;
@@ -56,6 +58,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
crgetgid;
crgetngroups;
crgetgroups;
+ crgetzone;
+ crgetzoneid;
crhold;
cv_broadcast;
@@ -70,12 +74,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;
@@ -147,6 +155,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
kstat_create;
kstat_create_zone;
kstat_named_init;
+ kstat_named_setstr;
kstat_delete;
kstat_install;
kstat_waitq_enter;
@@ -197,7 +206,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
strfree;
system_taskq;
- system_taskq_fini;
+ system_taskq_fini;
system_taskq_init;
taskq_create;
taskq_create_proc;
@@ -227,8 +236,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/sys/user.h b/usr/src/lib/libfakekernel/common/sys/user.h
index f37548895c..190d7ca64b 100644
--- a/usr/src/lib/libfakekernel/common/sys/user.h
+++ b/usr/src/lib/libfakekernel/common/sys/user.h
@@ -31,6 +31,7 @@ extern "C" {
struct exdata;
#if defined(_KERNEL) || defined(_FAKE_KERNEL) || defined(_KMEMUSER)
typedef struct uf_info uf_info_t;
+typedef uint_t uf_entry_gen_t;
#endif
typedef struct user user_t;
diff --git a/usr/src/lib/libfakekernel/common/taskq.c b/usr/src/lib/libfakekernel/common/taskq.c
index c445557d3f..1badeb2da5 100644
--- a/usr/src/lib/libfakekernel/common/taskq.c
+++ b/usr/src/lib/libfakekernel/common/taskq.c
@@ -101,7 +101,7 @@ again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
tq->tq_freelist = t->tqent_next;
} else {
if (tq->tq_nalloc >= tq->tq_maxalloc) {
- if (!(tqflags & KM_SLEEP))
+ if (tqflags & KM_NOSLEEP)
return (NULL);
/*
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/libmlrpc/common/ndr_server.c b/usr/src/lib/libmlrpc/common/ndr_server.c
index 4a1e2c177a..d33d138591 100644
--- a/usr/src/lib/libmlrpc/common/ndr_server.c
+++ b/usr/src/lib/libmlrpc/common/ndr_server.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -640,7 +641,7 @@ ndr_reply_fault(ndr_xa_t *mxa, unsigned long drc)
ndr_stream_t *nds = &mxa->send_nds;
unsigned long fault_status;
- NDS_RESET(nds);
+ (void) NDS_RESET(nds);
hdr->rpc_vers = 5;
hdr->rpc_vers_minor = 0;
diff --git a/usr/src/lib/libpam/pam_framework.c b/usr/src/lib/libpam/pam_framework.c
index 848483ce75..b3340ffd5e 100644
--- a/usr/src/lib/libpam/pam_framework.c
+++ b/usr/src/lib/libpam/pam_framework.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2019, Joyent, Inc.
+ */
+
#include <syslog.h>
#include <dlfcn.h>
#include <sys/types.h>
@@ -54,15 +58,15 @@ static char *pam_inames [PAM_MAX_ITEMS] = {
/* PAM_SERVICE */ "service",
/* PAM_USER */ "user",
/* PAM_TTY */ "tty",
-/* PAM_RHOST */ "rhost",
+/* PAM_RHOST */ "rhost",
/* PAM_CONV */ "conv",
/* PAM_AUTHTOK */ "authtok",
/* PAM_OLDAUTHTOK */ "oldauthtok",
-/* PAM_RUSER */ "ruser",
+/* PAM_RUSER */ "ruser",
/* PAM_USER_PROMPT */ "user_prompt",
/* PAM_REPOSITORY */ "repository",
/* PAM_RESOURCE */ "resource",
-/* PAM_AUSER */ "auser",
+/* PAM_AUSER */ "auser",
/* Undefined Items */
};
@@ -76,14 +80,14 @@ static char *pam_inames [PAM_MAX_ITEMS] = {
/* functions to dynamically load modules */
static int load_modules(pam_handle_t *, int, char *, pamtab_t *);
-static void *open_module(pam_handle_t *, char *);
+static void *open_module(pam_handle_t *, char *);
static int load_function(void *, char *, int (**func)());
/* functions to read and store the pam.conf configuration file */
static int open_pam_conf(struct pam_fh **, pam_handle_t *, char *);
static void close_pam_conf(struct pam_fh *);
static int read_pam_conf(pam_handle_t *, char *);
-static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
+static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
pamtab_t **);
static char *read_next_token(char **);
static char *nextline(struct pam_fh *, pam_handle_t *, int *);
@@ -797,8 +801,8 @@ pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data,
pam_trace(PAM_DEBUG_DATA,
"pam_set_data(%p:%s:%d)=%p", (void *)pamh,
- module_data_name ? module_data_name : "NULL", pamh->pam_inmodule,
- data);
+ (module_data_name != NULL) ? module_data_name : "NULL",
+ (pamh != NULL) ? pamh->pam_inmodule : -1, data);
if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
module_data_name == NULL) {
return (PAM_SYSTEM_ERR);
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index eb73039a21..dd7bd9f99b 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -27,6 +27,8 @@
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2018, Joyent, Inc.
* Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -710,10 +712,12 @@ extern int proc_get_secflags(pid_t, prsecflags_t **);
*/
#define FLT2STR_MAX 32 /* max. string length of faults (like SIG2STR_MAX) */
#define SYS2STR_MAX 32 /* max. string length of syscalls (like SIG2STR_MAX) */
+#define DMODELSTR_MAX 32 /* max. string length of data model names */
extern char *proc_fltname(int, char *, size_t);
extern char *proc_signame(int, char *, size_t);
extern char *proc_sysname(int, char *, size_t);
+extern char *proc_dmodelname(int, char *, size_t);
/*
* Utility functions for debugging tools to convert fault, signal, and system
diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers
index 3b2fe58812..6e5ff2c21a 100644
--- a/usr/src/lib/libproc/common/mapfile-vers
+++ b/usr/src/lib/libproc/common/mapfile-vers
@@ -23,6 +23,8 @@
# Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
# Copyright (c) 2013 by Delphix. All rights reserved.
+# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
#
@@ -204,6 +206,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
proc_arg_xgrab;
proc_arg_xpsinfo;
proc_content2str;
+ proc_dmodelname;
proc_finistdio;
proc_fltname;
proc_fltset2str;
diff --git a/usr/src/lib/libproc/common/proc_names.c b/usr/src/lib/libproc/common/proc_names.c
index 634a79b312..314b01fbcd 100644
--- a/usr/src/lib/libproc/common/proc_names.c
+++ b/usr/src/lib/libproc/common/proc_names.c
@@ -22,6 +22,8 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, Joyent, Inc. All rights reserved.
+ * Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
#include <stdio.h>
@@ -31,6 +33,7 @@
#include <signal.h>
#include <errno.h>
#include "libproc.h"
+#include <sys/procfs_isa.h>
static const char *
rawfltname(int flt)
@@ -482,7 +485,7 @@ proc_str2sys(const char *str, int *sysnum)
*/
char *
proc_fltset2str(const fltset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[FLT2STR_MAX], *p = buf;
size_t n;
@@ -522,7 +525,7 @@ proc_fltset2str(const fltset_t *set, const char *delim, int m,
*/
char *
proc_sigset2str(const sigset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[SIG2STR_MAX], *p = buf;
size_t n;
@@ -568,7 +571,7 @@ proc_sigset2str(const sigset_t *set, const char *delim, int m,
*/
char *
proc_sysset2str(const sysset_t *set, const char *delim, int m,
- char *buf, size_t len)
+ char *buf, size_t len)
{
char name[SYS2STR_MAX], *p = buf;
size_t n;
@@ -703,3 +706,34 @@ proc_str2sysset(const char *s, const char *delim, int m, sysset_t *set)
}
return (NULL);
}
+
+/*
+ * Returns a string representation of a process data model.
+ * See <sys/procfs_isa.h> for possible values.
+ */
+char *
+proc_dmodelname(int dmodel, char *buf, size_t bufsz)
+{
+ static const char *const dmdls[] = {
+ "PR_MODEL_UNKNOWN",
+ "PR_MODEL_ILP32",
+ "PR_MODEL_LP64",
+ NULL
+ };
+ size_t len;
+
+ if (bufsz == 0)
+ return (NULL);
+
+ if (dmodel > PR_MODEL_LP64 || dmodel < PR_MODEL_UNKNOWN) {
+ len = snprintf(buf, bufsz, "DMODEL#%d", dmodel);
+ } else {
+ len = strlen(dmdls[dmodel]);
+ (void) strncpy(buf, dmdls[dmodel], bufsz);
+ }
+
+ if (len >= bufsz)
+ buf[bufsz-1] = '\0';
+
+ return (buf);
+}
diff --git a/usr/src/lib/libreparse/common/fs_reparse_lib.c b/usr/src/lib/libreparse/common/fs_reparse_lib.c
index 3e395d5d7e..ae74f358cf 100644
--- a/usr/src/lib/libreparse/common/fs_reparse_lib.c
+++ b/usr/src/lib/libreparse/common/fs_reparse_lib.c
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -274,7 +278,7 @@ proto_plugin_fini()
*/
for (p = rp_proto_list; p != NULL; p = p->plugin_next) {
if (p->plugin_ops->rpo_fini)
- p->plugin_ops->rpo_fini();
+ (void) p->plugin_ops->rpo_fini();
}
while ((p = rp_proto_list) != NULL) {
rp_proto_list = p->plugin_next;
diff --git a/usr/src/lib/librpcsvc/common/rusers_simple.c b/usr/src/lib/librpcsvc/common/rusers_simple.c
index 3cccb42e78..1902fbfa5d 100644
--- a/usr/src/lib/librpcsvc/common/rusers_simple.c
+++ b/usr/src/lib/librpcsvc/common/rusers_simple.c
@@ -19,7 +19,6 @@
*
* CDDL HEADER END
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* rusers_simple.c
@@ -29,6 +28,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <string.h>
#include <rpc/rpc.h>
#include <rpcsvc/rusers.h>
@@ -85,13 +88,13 @@ rusers3(host, uap)
xdr_free(xdr_utmpidlearr, (char *)&up);
return (-1);
}
- strncpy(rutp->ut_line,
+ (void) strncpy(rutp->ut_line,
up.uia_arr[i]->ui_utmp.ut_line,
sizeof (forsize.ut_line)+1);
- strncpy(rutp->ut_user,
+ (void) strncpy(rutp->ut_user,
up.uia_arr[i]->ui_utmp.ut_name,
sizeof (forsize.ut_name)+1);
- strncpy(rutp->ut_host,
+ (void) strncpy(rutp->ut_host,
up.uia_arr[i]->ui_utmp.ut_host,
sizeof (forsize.ut_host)+1);
rutp->ut_idle = up.uia_arr[i]->ui_idle;
@@ -117,7 +120,7 @@ rnusers(host)
if (rpc_call(host, RUSERSPROG, RUSERSVERS_IDLE, RUSERSPROC_NUM,
xdr_void, (char *) NULL,
xdr_u_int, (char *) &nusers, (char *) NULL) != 0)
- return (-1);
+ return (-1);
}
return (nusers);
}
diff --git a/usr/src/lib/libsaveargs/Makefile.com b/usr/src/lib/libsaveargs/Makefile.com
index 94d80c1d5b..883afb66c9 100644
--- a/usr/src/lib/libsaveargs/Makefile.com
+++ b/usr/src/lib/libsaveargs/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright (c) 2019, Joyent, Inc.
#
# The build process for libsaveargs is sightly different from that used by other
@@ -95,9 +95,6 @@ CFLAGS += $(CFLAGS_$(CURTYPE)) $(CFLAGS_common)
CFLAGS64_standalone = $(STAND_FLAGS_64)
CFLAGS64 += $(CCVERBOSE) $(CFLAGS64_$(CURTYPE)) $(CFLAGS64_common)
-# not linted
-SMATCH=off
-
DYNFLAGS += $(ZINTERPOSE)
.KEEP_STATE:
diff --git a/usr/src/lib/libsaveargs/amd64/saveargs.c b/usr/src/lib/libsaveargs/amd64/saveargs.c
index c8276ddebb..6d3ed769f2 100644
--- a/usr/src/lib/libsaveargs/amd64/saveargs.c
+++ b/usr/src/lib/libsaveargs/amd64/saveargs.c
@@ -220,7 +220,7 @@ instr_size(dis_handle_t *dhp, uint8_t *ins, unsigned int i, size_t size)
static boolean_t
has_saved_fp(dis_handle_t *dhp, uint8_t *ins, int size)
{
- int i, j;
+ int i, j;
uint32_t n;
boolean_t found_push = B_FALSE;
ssize_t sz = 0;
diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.c b/usr/src/lib/libshare/smbfs/libshare_smbfs.c
index b1f19f917d..7c9b4fa58a 100644
--- a/usr/src/lib/libshare/smbfs/libshare_smbfs.c
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.c
@@ -22,6 +22,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -70,6 +72,7 @@ static int yes_no_validator(int, char *, char *);
static int ip_address_validator(int, char *, char *);
static int minauth_validator(int, char *, char *);
static int password_validator(int, char *, char *);
+static int protocol_validator(int, char *, char *);
static int signing_validator(int, char *, char *);
int propset_changed = 0;
@@ -182,6 +185,12 @@ struct smbclnt_proto_option_defs smbclnt_proto_options[] = {
{ "signing", NULL, PROTO_OPT_SIGNING,
0, 0, MAX_VALUE_BUFLEN,
signing_validator},
+ { "min_protocol", NULL, PROTO_OPT_MIN_PROTOCOL,
+ 0, 0, MAX_VALUE_BUFLEN,
+ protocol_validator},
+ { "max_protocol", NULL, PROTO_OPT_MAX_PROTOCOL,
+ 0, 0, MAX_VALUE_BUFLEN,
+ protocol_validator},
{NULL}
};
@@ -270,18 +279,30 @@ ip_address_validator(int index, char *section, char *value)
static int
minauth_validator(int index, char *section, char *value)
{
+ int ival;
+
if (value == NULL)
return (SA_BAD_VALUE);
- if (strlen(value) == 0)
- return (SA_OK);
- if (strcmp(value, "kerberos") == 0 ||
- strcmp(value, "ntlmv2") == 0 ||
- strcmp(value, "ntlm") == 0 ||
- strcmp(value, "lm") == 0 ||
- strcmp(value, "none") == 0)
- return (SA_OK);
- else
+ ival = smb_cf_minauth_from_str(value);
+ if (ival == -1)
return (SA_BAD_VALUE);
+
+ return (SA_OK);
+}
+
+/*ARGSUSED*/
+static int
+protocol_validator(int index, char *section, char *value)
+{
+ int ival;
+
+ if (value == NULL)
+ return (SA_BAD_VALUE);
+ ival = smb_cf_version_from_str(value);
+ if (ival == -1)
+ return (SA_BAD_VALUE);
+
+ return (SA_OK);
}
/*ARGSUSED*/
diff --git a/usr/src/lib/libshare/smbfs/libshare_smbfs.h b/usr/src/lib/libshare/smbfs/libshare_smbfs.h
index 8f95e7de68..d77fef814a 100644
--- a/usr/src/lib/libshare/smbfs/libshare_smbfs.h
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.h
@@ -22,6 +22,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,8 +61,10 @@ extern struct smbclnt_proto_option_defs smbclnt_proto_options[];
#define PROTO_OPT_DOMAIN 9
#define PROTO_OPT_WORKGROUP 10
#define PROTO_OPT_SIGNING 11
+#define PROTO_OPT_MIN_PROTOCOL 12
+#define PROTO_OPT_MAX_PROTOCOL 13
-#define SMBC_OPT_MAX PROTO_OPT_SIGNING
+#define SMBC_OPT_MAX PROTO_OPT_MAX_PROTOCOL
/*
* Flags values
diff --git a/usr/src/lib/libshell/common/data/solaris_cmdlist.h b/usr/src/lib/libshell/common/data/solaris_cmdlist.h
index f394e79aa7..ba724a15b1 100644
--- a/usr/src/lib/libshell/common/data/solaris_cmdlist.h
+++ b/usr/src/lib/libshell/common/data/solaris_cmdlist.h
@@ -84,7 +84,7 @@ ASTCMDLIST(chgrp)
ASTCMDLIST(chmod)
ASTCMDLIST(chown)
// XPG4CMDLIST(chown)
-BINCMDLIST(chown)
+// BINCMDLIST(chown)
ASTCMDLIST(cksum)
BINCMDLIST(cksum)
GNUCMDLIST(cksum)
diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com
index 160494aff1..be5ad05c42 100644
--- a/usr/src/lib/libsmbfs/Makefile.com
+++ b/usr/src/lib/libsmbfs/Makefile.com
@@ -24,7 +24,7 @@
# Use is subject to license terms.
# Copyright 2015 Igor Kozhukhov <ikozhukhov@gmail.com>
#
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
# Copyright (c) 2018, Joyent, Inc.
@@ -57,21 +57,16 @@ OBJ_LIB=\
nb.o \
nb_name.o \
nb_net.o \
- nb_ssn.o \
nbns_rq.o \
- negprot.o \
newvc.o \
nls.o \
ntlm.o \
ntlmssp.o \
print.o \
- rap.o \
rcfile.o \
- rq.o \
- signing.o \
+ rc_scf.o \
spnego.o \
spnegoparse.o \
- ssnsetup.o \
ssp.o \
subr.o \
ui-sun.o \
@@ -95,7 +90,7 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
CSTD= $(CSTD_GNU99)
-LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap
+LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap -lscf -luuid
# normal warnings...
CFLAGS += $(CCVERBOSE)
@@ -111,23 +106,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/cflib.h b/usr/src/lib/libsmbfs/cflib.h
index 0e8d6b57ee..85db96fcfd 100644
--- a/usr/src/lib/libsmbfs/cflib.h
+++ b/usr/src/lib/libsmbfs/cflib.h
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _CFLIB_H_
@@ -85,6 +87,8 @@ int cf_getopt(int, char * const *, const char *);
void cf_opt_lock(void);
void cf_opt_unlock(void);
+char *cf_get_client_uuid(void);
+
int rc_getstringptr(struct rcfile *, const char *, const char *, char **);
int rc_getstring(struct rcfile *, const char *, const char *, size_t, char *);
int rc_getint(struct rcfile *, const char *, const char *, int *);
diff --git a/usr/src/lib/libsmbfs/netsmb/smb_lib.h b/usr/src/lib/libsmbfs/netsmb/smb_lib.h
index c1dc6886ac..ae71332e97 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 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_LIB_H_
@@ -103,28 +103,21 @@ struct smb_ctx {
struct addrinfo *ct_addrinfo; /* IP addresses of the server */
struct nb_ctx *ct_nb; /* NetBIOS info. */
char *ct_locname; /* local (machine) name */
- smb_iod_ssn_t ct_iod_ssn;
- /* smbioc_oshare_t ct_sh; XXX */
int ct_minauth;
int ct_shtype_req; /* share type wanted */
char *ct_origshare;
char *ct_home;
char *ct_rpath; /* remote file name */
- /* Connection setup SMB stuff. */
- /* Strings from the SMB negotiate response. */
- char *ct_srv_OS;
- char *ct_srv_LM;
- uint32_t ct_clnt_caps;
+ /* See ssp.c */
+ void *ct_ssp_ctx;
+ smbioc_ssn_work_t ct_work;
+ smb_iod_ssn_t ct_iod_ssn;
/* NTLM auth. stuff */
uchar_t ct_clnonce[NTLM_CHAL_SZ];
uchar_t ct_srv_chal[NTLM_CHAL_SZ];
char ct_password[SMBIOC_MAX_NAME];
-
- /* See ssp.c */
- void *ct_ssp_ctx;
- smbioc_ssn_work_t ct_work;
};
@@ -133,25 +126,20 @@ struct smb_ctx {
*/
#define ct_ssn ct_iod_ssn.iod_ossn
#define ct_vopt ct_iod_ssn.iod_ossn.ssn_vopt
+#define ct_minver ct_iod_ssn.iod_ossn.ssn_minver
+#define ct_maxver ct_iod_ssn.iod_ossn.ssn_maxver
#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
-#define ct_sopt ct_work.wk_sopt
-#define ct_iods ct_work.wk_iods
-#define ct_tran_fd ct_work.wk_iods.is_tran_fd
-#define ct_hflags ct_work.wk_iods.is_hflags
-#define ct_hflags2 ct_work.wk_iods.is_hflags2
-#define ct_vcflags ct_work.wk_iods.is_vcflags
-#define ct_ssn_key ct_work.wk_iods.is_ssn_key
-#define ct_mac_seqno ct_work.wk_iods.is_next_seq
-#define ct_mackeylen ct_work.wk_iods.is_u_maclen
-#define ct_mackey ct_work.wk_iods.is_u_mackey.lp_ptr
+#define ct_vcflags ct_work.wk_vcflags
+#define ct_ssnkey_len ct_work.wk_u_ssnkey_len
+#define ct_ssnkey_buf ct_work.wk_u_ssnkey_buf.lp_ptr
/*
@@ -169,9 +157,7 @@ struct smb_ctx {
#define SMBCF_BROWSEOK 0x00200000 /* browser dialogue may be used */
#define SMBCF_AUTHREQ 0x00400000 /* auth. dialog requested */
#define SMBCF_KCSAVE 0x00800000 /* add to keychain requested */
-#define SMBCF_XXX 0x01000000 /* mount-all, a very bad thing */
-#define SMBCF_SSNACTIVE 0x02000000 /* session setup succeeded */
-#define SMBCF_KCDOMAIN 0x04000000 /* use domain in KC lookup */
+#define SMBCF_KCDOMAIN 0x01000000 /* use domain in KC lookup */
/*
@@ -181,6 +167,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 *);
@@ -208,6 +196,9 @@ int smb_iod_work(struct smb_ctx *);
int smb_open_rcfile(char *);
void smb_close_rcfile(void);
+int smb_cf_minauth_from_str(char *);
+int smb_cf_version_from_str(char *);
+
void smb_simplecrypt(char *dst, const char *src);
int smb_simpledecrypt(char *dst, const char *src);
diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
index b1f4b1e198..7b87b571ff 100644
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMBFS_API_H
@@ -48,7 +49,7 @@ extern "C" {
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113
+#define EBADRPC 113
#endif
#ifndef EAUTH
#define EAUTH 114
@@ -122,6 +123,8 @@ int smb_ctx_setauthflags(struct smb_ctx *, int);
int smb_ctx_setcharset(struct smb_ctx *, const char *);
int smb_ctx_setfullserver(struct smb_ctx *, const char *);
int smb_ctx_setsigning(struct smb_ctx *, int ena, int req);
+int smb_ctx_setminver(struct smb_ctx *, int ver);
+int smb_ctx_setmaxver(struct smb_ctx *, int ver);
int smb_ctx_setnbflags(struct smb_ctx *, int ena, int bcast);
int smb_ctx_setscope(struct smb_ctx *, const char *);
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
index d7cc9ebbd7..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip
@@ -1 +1 @@
-CIFS CLIENT SOFTWARE
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
diff --git a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
index aa3d6ad7e1..35fdfd0404 100644
--- a/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip
@@ -1 +1 @@
-PORTIONS OF LIBSMBFS IN CIFS CLIENT
+PORTIONS OF LIBSMBFS IN SMB CLIENT
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/connect.c b/usr/src/lib/libsmbfs/smb/connect.c
index c2ccc3361d..c231fe0e8a 100644
--- a/usr/src/lib/libsmbfs/smb/connect.c
+++ b/usr/src/lib/libsmbfs/smb/connect.c
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -50,336 +51,89 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <uuid/uuid.h>
#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
#include <netsmb/netbios.h>
#include <netsmb/nb_lib.h>
#include <netsmb/smb_dev.h>
+#include <cflib.h>
+
#include "charsets.h"
#include "private.h"
-
-/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
-static int smb_tcpsndbuf = 0x20000;
-static int smb_tcprcvbuf = 0x20000;
-static int smb_connect_timeout = 30; /* seconds */
-int smb_recv_timeout = 30; /* seconds */
-
-int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
-int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
-int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
-
-/*
- * Internal set sockopt for int-sized options.
- * Borrowed from: libnsl/rpc/ti_opts.c
- */
-static int
-smb_setopt_int(int fd, int level, int name, int val)
-{
- struct t_optmgmt oreq, ores;
- struct {
- struct t_opthdr oh;
- int ival;
- } opts;
-
- /* opt header */
- opts.oh.len = sizeof (opts);
- opts.oh.level = level;
- opts.oh.name = name;
- opts.oh.status = 0;
- opts.ival = val;
-
- oreq.flags = T_NEGOTIATE;
- oreq.opt.buf = (void *)&opts;
- oreq.opt.len = sizeof (opts);
-
- ores.flags = 0;
- ores.opt.buf = NULL;
- ores.opt.maxlen = 0;
-
- if (t_optmgmt(fd, &oreq, &ores) < 0) {
- DPRINT("t_opgmgnt, t_errno = %d", t_errno);
- if (t_errno == TSYSERR)
- return (errno);
- return (EPROTO);
- }
- if (ores.flags != T_SUCCESS) {
- DPRINT("flags 0x%x, status 0x%x",
- (int)ores.flags, (int)opts.oh.status);
- return (EPROTO);
- }
-
- return (0);
-}
+#include "smb_crypt.h"
static int
-smb_setopts(int fd)
-{
- int err;
-
- /*
- * Set various socket/TCP options.
- * Failures here are not fatal -
- * just log a complaint.
- *
- * We don't need these two:
- * SO_RCVTIMEO, SO_SNDTIMEO
- */
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
- if (err) {
- DPRINT("set SO_SNDBUF, err %d", err);
- }
-
- err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
- if (err) {
- DPRINT("set SO_RCVBUF, err %d", err);
- }
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *mbc1, struct mbdata *mbc2);
- err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
- if (err) {
- DPRINT("set SO_KEEPALIVE, err %d", err);
- }
+int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
- err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
- if (err) {
- DPRINT("set TCP_NODELAY, err %d", err);
- }
-
- /* Set the connect timeout (in milliseconds). */
- err = smb_setopt_int(fd, IPPROTO_TCP,
- TCP_CONN_ABORT_THRESHOLD,
- smb_connect_timeout * 1000);
- if (err) {
- DPRINT("set connect timeout, err %d", err);
- }
- return (0);
-}
-
-
-int
-conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+const char *
+smb_iod_state_name(enum smbiod_state st)
{
- struct sockaddr_in6 sin6;
- char *dev = "/dev/tcp6";
- char paddrbuf[INET6_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
-
- if (sa->sa_family != AF_INET6) {
- DPRINT("bad af %d", sa->sa_family);
- return (EINVAL);
- }
- bcopy(sa, &sin6, sizeof (sin6));
- sin6.sin6_port = htons(port);
-
- DPRINT("tcp6: %s (%d)",
- inet_ntop(AF_INET6, &sin6.sin6_addr,
- paddrbuf, sizeof (paddrbuf)), port);
+ const char *n = "(?)";
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
- err = errno;
- perror(dev);
- return (err);
- }
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
- }
- sndcall.addr.maxlen = sizeof (sin6);
- sndcall.addr.len = sizeof (sin6);
- sndcall.addr.buf = (void *) &sin6;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
-
- DPRINT("tcp6: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
-
-errout:
- close(fd);
- return (err);
-}
-
-/*
- * This is used for both SMB over TCP (port 445)
- * and NetBIOS - see conn_nbt().
- */
-int
-conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
-{
- struct sockaddr_in sin;
- char *dev = "/dev/tcp";
- char paddrbuf[INET_ADDRSTRLEN];
- struct t_call sndcall;
- int fd, err;
-
- if (sa->sa_family != AF_INET) {
- DPRINT("bad af %d", sa->sa_family);
- return (EINVAL);
- }
- bcopy(sa, &sin, sizeof (sin));
- sin.sin_port = htons(port);
-
- DPRINT("tcp4: %s (%d)",
- inet_ntop(AF_INET, &sin.sin_addr,
- paddrbuf, sizeof (paddrbuf)), port);
-
- fd = t_open(dev, O_RDWR, NULL);
- if (fd < 0) {
- /* Assume t_errno = TSYSERR */
- err = errno;
- perror(dev);
- return (err);
- }
- if ((err = smb_setopts(fd)) != 0)
- goto errout;
- if (t_bind(fd, NULL, NULL) < 0) {
- DPRINT("t_bind t_errno %d", t_errno);
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- goto errout;
- }
- sndcall.addr.maxlen = sizeof (sin);
- sndcall.addr.len = sizeof (sin);
- sndcall.addr.buf = (void *) &sin;
- sndcall.opt.len = 0;
- sndcall.udata.len = 0;
- if (t_connect(fd, &sndcall, NULL) < 0) {
- err = get_xti_err(fd);
- DPRINT("connect, err %d", err);
- goto errout;
- }
-
- DPRINT("tcp4: connected, fd=%d", fd);
- ctx->ct_tran_fd = fd;
- return (0);
-
-errout:
- close(fd);
- return (err);
-}
-
-/*
- * Open a NetBIOS connection (session, port 139)
- *
- * The optional name parameter, if passed, means
- * we found the sockaddr via NetBIOS name lookup,
- * and can just use that for our session request.
- * Otherwise (if name is NULL), we're connecting
- * by IP address, and need to come up with the
- * NetBIOS name by other means.
- */
-int
-conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
-{
- struct sockaddr_in sin;
- struct sockaddr *sa;
- char server[NB_NAMELEN];
- char workgroup[NB_NAMELEN];
- int err, nberr, port;
-
- bcopy(saarg, &sin, sizeof (sin));
- sa = (struct sockaddr *)&sin;
-
- switch (sin.sin_family) {
- case AF_NETBIOS: /* our fake AF */
- sin.sin_family = AF_INET;
+ switch (st) {
+ case SMBIOD_ST_UNINIT:
+ n = "UNINIT!";
break;
- case AF_INET:
+ case SMBIOD_ST_IDLE:
+ n = "IDLE";
+ break;
+ case SMBIOD_ST_RECONNECT:
+ n = "RECONNECT";
+ break;
+ case SMBIOD_ST_RCFAILED:
+ n = "RCFAILED";
+ break;
+ case SMBIOD_ST_CONNECTED:
+ n = "CONNECTED";
+ break;
+ case SMBIOD_ST_NEGOTIATED:
+ n = "NEGOTIATED";
+ break;
+ case SMBIOD_ST_AUTHCONT:
+ n = "AUTHCONT";
+ break;
+ case SMBIOD_ST_AUTHFAIL:
+ n = "AUTHFAIL";
+ break;
+ case SMBIOD_ST_AUTHOK:
+ n = "AUTHOK";
+ break;
+ case SMBIOD_ST_VCACTIVE:
+ n = "VCACTIVE";
+ break;
+ case SMBIOD_ST_DEAD:
+ n = "DEAD";
break;
- default:
- DPRINT("bad af %d", sin.sin_family);
- return (EINVAL);
- }
- port = IPPORT_NETBIOS_SSN;
-
- /*
- * If we have a NetBIOS name, just use it.
- * This is the path taken when we've done a
- * NetBIOS name lookup on this name to get
- * the IP address in the passed sa. Otherwise,
- * we're connecting by IP address, and need to
- * figure out what NetBIOS name to use.
- */
- if (name) {
- strlcpy(server, name, sizeof (server));
- DPRINT("given name: %s", server);
- } else {
- /*
- *
- * Try a NetBIOS node status query,
- * which searches for a type=[20] name.
- * If that doesn't work, just use the
- * (fake) "*SMBSERVER" name.
- */
- DPRINT("try node status");
- server[0] = '\0';
- nberr = nbns_getnodestatus(ctx->ct_nb,
- &sin.sin_addr, server, workgroup);
- if (nberr == 0 && server[0] != '\0') {
- /* Found the name. Save for reconnect. */
- DPRINT("found name: %s", server);
- strlcpy(ctx->ct_srvname, server,
- sizeof (ctx->ct_srvname));
- } else {
- DPRINT("getnodestatus, nberr %d", nberr);
- strlcpy(server, "*SMBSERVER", sizeof (server));
- }
- }
-
- /*
- * Establish the TCP connection.
- * Careful to close it on errors.
- */
- if ((err = conn_tcp4(ctx, sa, port)) != 0) {
- DPRINT("TCP connect: err=%d", err);
- goto out;
}
- /* Connected. Do NetBIOS session request. */
- err = nb_ssn_request(ctx, server);
- if (err)
- DPRINT("ssn_rq, err %d", err);
-
-out:
- if (err) {
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
- }
- return (err);
+ return (n);
}
/*
* Make a new connection, or reconnect.
+ *
+ * This is called first from the door service thread in smbiod
+ * (so that can report success or failure to the door client)
+ * and thereafter it's called when we need to reconnect after a
+ * network outage (or whatever might cause connection loss).
*/
int
smb_iod_connect(smb_ctx_t *ctx)
{
- struct sockaddr *sa;
- int err, err2;
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ char *uuid_str;
+ int err;
struct mbdata blob;
+ char *nego_buf = NULL;
+ uint32_t nego_len;
memset(&blob, 0, sizeof (blob));
@@ -393,15 +147,6 @@ smb_iod_connect(smb_ctx_t *ctx)
dump_ctx("smb_iod_connect", ctx);
/*
- * This may be a reconnect, so
- * cleanup if necessary.
- */
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
-
- /*
* Get local machine name.
* Full name - not a NetBIOS name.
*/
@@ -415,114 +160,235 @@ smb_iod_connect(smb_ctx_t *ctx)
}
/*
+ * Get local machine uuid.
+ */
+ uuid_str = cf_get_client_uuid();
+ if (uuid_str == NULL) {
+ err = EINVAL;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "can't get local UUID"), err);
+ return (err);
+ }
+ (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid);
+ free(uuid_str);
+ uuid_str = NULL;
+
+ /*
* We're called with each IP address
* already copied into ct_srvaddr.
*/
ctx->ct_flags |= SMBCF_RESOLVED;
- sa = &ctx->ct_srvaddr.sa;
- switch (sa->sa_family) {
-
- case AF_INET6:
- err = conn_tcp6(ctx, sa, IPPORT_SMB);
- break;
-
- case AF_INET:
- err = conn_tcp4(ctx, sa, IPPORT_SMB);
- /*
- * If port 445 was not listening, try port 139.
- * Note: Not doing NetBIOS name lookup here.
- * We already have the IP address.
- */
- switch (err) {
- case ECONNRESET:
- case ECONNREFUSED:
- err2 = conn_nbt(ctx, sa, NULL);
- if (err2 == 0)
- err = 0;
- }
- break;
-
- case AF_NETBIOS:
- /* Like AF_INET, but use NetBIOS ssn. */
- err = conn_nbt(ctx, sa, ctx->ct_srvname);
- break;
-
- default:
- DPRINT("skipped family %d", sa->sa_family);
- err = EPROTONOSUPPORT;
- break;
- }
-
-
- if (err) {
- DPRINT("connect, err=%d", err);
+ /*
+ * Ask the drvier to connect.
+ */
+ DPRINT("Try ioctl connect...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: connect failed"),
+ err, ossn->ssn_srvname);
return (err);
}
+ DPRINT("Connect OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
/*
- * Do SMB Negotiate Protocol.
+ * Setup a buffer to recv the nego. hint.
*/
- err = smb_negprot(ctx, &blob);
+ nego_len = 4096;
+ err = mb_init_sz(&blob, nego_len);
if (err)
goto out;
+ nego_buf = blob.mb_top->m_data;
+ work->wk_u_auth_rbuf.lp_ptr = nego_buf;
+ work->wk_u_auth_rlen = nego_len;
/*
- * Empty user name means an explicit request for
- * NULL session setup, which is a special case.
- * If negotiate determined that we want to do
- * SMB signing, we have to turn that off for a
- * NULL session. [MS-SMB 3.3.5.3].
+ * Ask the driver for SMB negotiate
*/
- if (ctx->ct_user[0] == '\0') {
- /* Null user should have null domain too. */
- ctx->ct_domain[0] = '\0';
- ctx->ct_authflags = SMB_AT_ANON;
- ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
- ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
+ DPRINT("Try ioctl negotiate...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_NEGOTIATE, work) < 0) {
+ err = errno;
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: negotiate failed"),
+ err, ossn->ssn_srvname);
+ goto out;
+ }
+ DPRINT("Negotiate OK, new state=%s",
+ smb_iod_state_name(work->wk_out_state));
+
+ nego_len = work->wk_u_auth_rlen;
+ blob.mb_top->m_len = nego_len;
+
+ if (smb_debug) {
+ DPRINT("Sec. blob: %d", nego_len);
+ smb_hexdump(nego_buf, nego_len);
}
/*
* Do SMB Session Setup (authenticate)
- *
- * If the server negotiated extended security,
- * run the SPNEGO state machine, otherwise do
- * one of the old-style variants.
+ * Always "extended security" now (SPNEGO)
*/
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- err = smb_ssnsetup_spnego(ctx, &blob);
- } else {
- /*
- * Server did NOT negotiate extended security.
- * Try NTLMv2, NTLMv1, or ANON (if enabled).
- */
- if (ctx->ct_authflags & SMB_AT_NTLM2) {
- err = smb_ssnsetup_ntlm2(ctx);
- } else if (ctx->ct_authflags & SMB_AT_NTLM1) {
- err = smb_ssnsetup_ntlm1(ctx);
- } else if (ctx->ct_authflags & SMB_AT_ANON) {
- err = smb_ssnsetup_null(ctx);
- } else {
+ DPRINT("Do session setup...");
+ err = smb_ssnsetup_spnego(ctx, &blob);
+ if (err != 0) {
+ DPRINT("Session setup err=%d", err);
+ goto out;
+ }
+
+ /*
+ * Success! We return zero now, and our caller (normally
+ * the smbiod program) will then call smb_iod_work in a
+ * new thread to service this VC as long as necessary.
+ */
+ DPRINT("Session setup OK");
+
+out:
+ mb_done(&blob);
+
+ return (err);
+}
+
+/*
+ * smb_ssnsetup_spnego
+ *
+ * This does an SMB session setup sequence using SPNEGO.
+ * The state changes seen during this sequence are there
+ * just to help track what's going on.
+ */
+int
+smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
+{
+ struct mbdata send_mb, recv_mb;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ int err;
+
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_mb, sizeof (recv_mb));
+
+ err = ssp_ctx_create_client(ctx, hint_mb);
+ if (err)
+ goto out;
+
+ /* NULL input indicates first call. */
+ err = ssp_ctx_next_token(ctx, NULL, &send_mb);
+ if (err) {
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
+ }
+ for (;;) {
+ err = smb__ssnsetup(ctx, &send_mb, &recv_mb);
+ DPRINT("smb__ssnsetup rc=%d, new state=%s", err,
+ smb_iod_state_name(work->wk_out_state));
+
+ if (err == 0) {
+ /*
+ * Session setup complete w/ success.
+ * Should have state AUTHOK
+ */
+ if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
+ DPRINT("Wrong state (expected AUTHOK)");
+ }
+ break;
+ }
+
+ if (err != EINPROGRESS) {
/*
- * Don't return EAUTH, because a new
- * password prompt will not help.
+ * Session setup complete w/ failure.
+ * Should have state AUTHFAIL
*/
- DPRINT("No NTLM authflags");
- err = ENOTSUP;
+ if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) {
+ DPRINT("Wrong state (expected AUTHFAIL)");
+ }
+ goto out;
+ }
+
+ /*
+ * err == EINPROGRESS
+ * Session setup continuing.
+ * Should have state AUTHCONT
+ */
+ if (work->wk_out_state != SMBIOD_ST_AUTHCONT) {
+ DPRINT("Wrong state (expected AUTHCONT)");
+ }
+
+ /* middle calls get both in, out */
+ err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
+ if (err) {
+ DPRINT("smb__ssnsetup, ssp next, err=%d", err);
+ goto out;
}
}
+ /*
+ * Only get here via break in the err==0 case above,
+ * so we're finalizing a successful session setup.
+ *
+ * NULL output token here indicates the final call.
+ */
+ (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
+
+ /*
+ * The session key is in ctx->ct_ssnkey_buf
+ * (a.k.a. ct_work.wk_u_ssn_key_buf)
+ */
+
out:
- mb_done(&blob);
+ /* Done with ctx->ct_ssp_ctx */
+ ssp_ctx_destroy(ctx);
- if (err) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- } else {
- /* Tell library code we have a session. */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
- DPRINT("tran_fd = %d", ctx->ct_tran_fd);
+ return (err);
+}
+
+int smb_max_authtok_sz = 0x10000;
+
+/*
+ * Session Setup function, calling the nsmb driver.
+ *
+ * Args
+ * send_mb: [in] outgoing blob data to send
+ * recv_mb: [out] received blob data buffer
+ */
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+ struct mbdata *send_mb, struct mbdata *recv_mb)
+{
+ smbioc_ossn_t *ossn = &ctx->ct_ssn;
+ smbioc_ssn_work_t *work = &ctx->ct_work;
+ mbuf_t *m;
+ int err;
+
+ /* Setup receive buffer for the auth data. */
+ err = mb_init_sz(recv_mb, smb_max_authtok_sz);
+ if (err != 0)
+ return (err);
+ m = recv_mb->mb_top;
+ work->wk_u_auth_rbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_rlen = m->m_maxlen;
+
+ /* ... and the auth data to send. */
+ m = send_mb->mb_top;
+ work->wk_u_auth_wbuf.lp_ptr = m->m_data;
+ work->wk_u_auth_wlen = m->m_len;
+
+ DPRINT("Session setup ioctl...");
+ if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) {
+ err = errno;
+ if (err != 0 && err != EINPROGRESS) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: session setup "),
+ err, ossn->ssn_srvname);
+ }
}
+ DPRINT("Session setup ret %d", err);
+
+ /* Free the auth data we sent. */
+ mb_done(send_mb);
+
+ /* Setup length of received auth data */
+ m = recv_mb->mb_top;
+ m->m_len = work->wk_u_auth_rlen;
return (err);
}
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index 9455a92344..3aa67fd5f5 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 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -148,10 +148,6 @@ dump_ctx_flags(int flags)
printf("AUTHREQ ");
if (flags & SMBCF_KCSAVE)
printf("KCSAVE ");
- if (flags & SMBCF_XXX)
- printf("XXX ");
- if (flags & SMBCF_SSNACTIVE)
- printf("SSNACTIVE ");
if (flags & SMBCF_KCDOMAIN)
printf("KCDOMAIN ");
printf("\n");
@@ -169,6 +165,8 @@ dump_iod_ssn(smb_iod_ssn_t *is)
ssn->ssn_domain, ssn->ssn_user);
printf(" ct_vopt=0x%x, ct_owner=%d\n",
ssn->ssn_vopt, ssn->ssn_owner);
+ printf(" ct_minver=0x%x, ct_maxver=0x%x\n",
+ ssn->ssn_minver, ssn->ssn_maxver);
printf(" ct_authflags=0x%x\n", is->iod_authflags);
printf(" ct_nthash:");
@@ -254,16 +252,16 @@ smb_ctx_init(struct smb_ctx *ctx)
ctx->ct_dev_fd = -1;
ctx->ct_door_fd = -1;
- ctx->ct_tran_fd = -1;
ctx->ct_parsedlevel = SMBL_NONE;
ctx->ct_minlevel = SMBL_NONE;
ctx->ct_maxlevel = SMBL_PATH;
/* Fill in defaults */
- ctx->ct_vopt = SMBVOPT_EXT_SEC;
+ ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
ctx->ct_owner = SMBM_ANY_OWNER;
ctx->ct_authflags = SMB_AT_DEFAULT;
ctx->ct_minauth = SMB_AT_MINAUTH;
+ ctx->ct_maxver = SMB2_DIALECT_MAX;
/*
* Default domain, user, ...
@@ -333,7 +331,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,17 +401,13 @@ 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) {
close(ctx->ct_door_fd);
ctx->ct_door_fd = -1;
}
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
- }
if (ctx->ct_srvaddr_s) {
free(ctx->ct_srvaddr_s);
ctx->ct_srvaddr_s = NULL;
@@ -441,17 +440,9 @@ smb_ctx_done(struct smb_ctx *ctx)
free(ctx->ct_rpath);
ctx->ct_rpath = NULL;
}
- if (ctx->ct_srv_OS) {
- free(ctx->ct_srv_OS);
- ctx->ct_srv_OS = NULL;
- }
- if (ctx->ct_srv_LM) {
- free(ctx->ct_srv_LM);
- ctx->ct_srv_LM = NULL;
- }
- if (ctx->ct_mackey) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
+ if (ctx->ct_ssnkey_buf) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
}
@@ -868,6 +859,37 @@ smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
return (0);
}
+/*
+ * Handle .nsmbrc "minver" option.
+ * Must be <= maxver
+ */
+int
+smb_ctx_setminver(struct smb_ctx *ctx, int ver)
+{
+ if (ver < 0 || ver > ctx->ct_maxver)
+ return (EINVAL);
+ ctx->ct_minver = (uint16_t)ver;
+ return (0);
+}
+
+/*
+ * Handle .nsmbrc "maxver" option.
+ * Must be >= minver
+ *
+ * Any "too high" value is just clamped, so the caller
+ * doesn't need to know what's the highest we support.
+ */
+int
+smb_ctx_setmaxver(struct smb_ctx *ctx, int ver)
+{
+ if (ver < 1 || ver < ctx->ct_minver)
+ return (EINVAL);
+ if (ver > SMB2_DIALECT_MAX)
+ ver = SMB2_DIALECT_MAX;
+ ctx->ct_maxver = (uint16_t)ver;
+ return (0);
+}
+
static int
smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
{
@@ -899,12 +921,11 @@ smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
}
/*
- * Suport a securty options arg, i.e. -S noext,lm,ntlm
+ * Suport a securty options arg, i.e. -S lm,ntlm
* for testing various type of authenticators.
*/
static struct nv
sectype_table[] = {
- /* noext - handled below */
{ "anon", SMB_AT_ANON },
{ "lm", SMB_AT_LM1 },
{ "ntlm", SMB_AT_NTLM1 },
@@ -930,13 +951,6 @@ smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
if (nlen == 0)
break;
- if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
- /* Don't offer extended security. */
- ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
- p += nlen;
- continue;
- }
-
/* This is rarely called, so not optimized. */
for (nv = sectype_table; nv->name; nv++) {
tlen = strlen(nv->name);
@@ -1117,6 +1131,19 @@ smb_ctx_resolve(struct smb_ctx *ctx)
assert(ctx->ct_addrinfo != NULL);
/*
+ * Empty user name means an explicit request for
+ * NULL session setup, which is a special case.
+ * (No SMB signing, per [MS-SMB] 3.3.5.3)
+ */
+ if (ctx->ct_user[0] == '\0') {
+ /* Null user should have null domain too. */
+ ctx->ct_domain[0] = '\0';
+ ctx->ct_authflags = SMB_AT_ANON;
+ ctx->ct_vopt |= SMBVOPT_ANONYMOUS;
+ ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
+ }
+
+ /*
* If we have a user name but no password,
* check for a keychain entry.
* XXX: Only for auth NTLM?
@@ -1127,13 +1154,18 @@ smb_ctx_resolve(struct smb_ctx *ctx)
* If we don't have a p/w yet,
* try the keychain.
*/
- if (ctx->ct_password[0] == '\0')
- (void) smb_get_keychain(ctx);
+ if (ctx->ct_password[0] == '\0' &&
+ smb_get_keychain(ctx) == 0) {
+ strlcpy(ctx->ct_password, "$HASH",
+ sizeof (ctx->ct_password));
+ }
+
/*
* Mask out disallowed auth types.
*/
ctx->ct_authflags &= ctx->ct_minauth;
}
+
if (ctx->ct_authflags == 0) {
smb_error(dgettext(TEXT_DOMAIN,
"no valid auth. types"), 0);
@@ -1147,6 +1179,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 +1200,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,9 +1220,8 @@ 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;
}
fd = smb_open_driver();
@@ -1187,12 +1235,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 +1269,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 +1329,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 +1360,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 +1378,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);
@@ -1343,6 +1400,35 @@ minauth_table[] = {
{ NULL }
};
+int
+smb_cf_minauth_from_str(char *str)
+{
+ struct nv *nvp;
+
+ for (nvp = minauth_table; nvp->name; nvp++)
+ if (strcmp(nvp->name, str) == 0)
+ return (nvp->value);
+ return (-1);
+}
+
+
+static struct nv
+smbver_table[] = {
+ { "2.1", SMB2_DIALECT_0210 },
+ { "1", 1 },
+ { NULL, 0 }
+};
+
+int
+smb_cf_version_from_str(char *str)
+{
+ struct nv *nvp;
+
+ for (nvp = smbver_table; nvp->name; nvp++)
+ if (strcmp(nvp->name, str) == 0)
+ return (nvp->value);
+ return (-1);
+}
/*
* level values:
@@ -1355,7 +1441,9 @@ static int
smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
{
char *p;
+ int ival;
int error;
+ int minver, maxver;
#ifdef KICONV_SUPPORT
if (level > 0) {
@@ -1373,19 +1461,79 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
if (level <= 1) {
/* Section is: [default] or [server] */
+ /*
+ * Handle min_protocol, max_protocol
+ * (SMB protocol versions)
+ */
+ minver = -1;
+ rc_getstringptr(smb_rc, sname, "min_protocol", &p);
+ if (p != NULL) {
+ minver = smb_cf_version_from_str(p);
+ if (minver == -1) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min_protocol value \"%s\" specified in the section %s"),
+ 0, p, sname);
+ }
+ }
+ maxver = -1;
+ rc_getstringptr(smb_rc, sname, "max_protocol", &p);
+ if (p != NULL) {
+ maxver = smb_cf_version_from_str(p);
+ if (maxver == -1) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid max_protocol value \"%s\" specified in the section %s"),
+ 0, p, sname);
+ }
+ }
+
+ /*
+ * If setting both min/max protocol,
+ * validate against each other
+ */
+ if (minver != -1 && maxver != -1) {
+ if (minver > maxver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_minver = minver;
+ ctx->ct_maxver = maxver;
+ }
+ }
+
+ /*
+ * Setting just min or max, validate against
+ * current settings
+ */
+ if (minver != -1) {
+ if (minver > ctx->ct_maxver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_minver = minver;
+ }
+ }
+ if (maxver != -1) {
+ if (maxver < ctx->ct_minver) {
+ smb_error(dgettext(TEXT_DOMAIN,
+"invalid min/max protocol combination in the section %s"),
+ 0, sname);
+ } else {
+ ctx->ct_maxver = maxver;
+ }
+ }
+
rc_getstringptr(smb_rc, sname, "minauth", &p);
if (p) {
/*
* "minauth" was set in this section; override
* the current minimum authentication setting.
*/
- struct nv *nvp;
- for (nvp = minauth_table; nvp->name; nvp++)
- if (strcmp(p, nvp->name) == 0)
- break;
- if (nvp->name)
- ctx->ct_minauth = nvp->value;
- else {
+ ival = smb_cf_minauth_from_str(p);
+ if (ival != -1) {
+ ctx->ct_minauth = ival;
+ } else {
/*
* Unknown minimum authentication level.
*/
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
index 8ca9d2cee1..3d2a431142 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -62,10 +63,16 @@
#include "private.h"
+/*
+ * It's not actually necessary to call the CLOSEFH ioctl, but doing it
+ * makes debugging a little easier. If we were to skip the ioctl,
+ * nsmb_close would cleanup the handle, here or in process exit.
+ */
int
smb_fh_close(int fd)
{
- return (close(fd));
+ (void) nsmb_ioctl(fd, SMBIOC_CLOSEFH, NULL);
+ return (nsmb_close(fd));
}
int
@@ -96,7 +103,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 +118,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 +127,7 @@ smb_fh_ntcreate(
errout:
if (new_fd != -1)
- close(new_fd);
+ nsmb_close(new_fd);
errno = err;
return (-1);
}
@@ -210,11 +217,10 @@ smb_fh_read(int fd, off64_t offset, size_t count,
struct smbioc_rw rwrq;
bzero(&rwrq, sizeof (rwrq));
- rwrq.ioc_fh = -1; /* tell driver to supply this */
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);
@@ -227,11 +233,10 @@ smb_fh_write(int fd, off64_t offset, size_t count,
struct smbioc_rw rwrq;
bzero(&rwrq, sizeof (rwrq));
- rwrq.ioc_fh = -1; /* tell driver to supply this */
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);
@@ -251,21 +256,23 @@ smb_fh_xactnp(int fd,
int *rdlen, char *rdata, /* receive */
int *more)
{
- int err, rparamcnt;
- uint16_t setup[2];
-
- setup[0] = TRANS_TRANSACT_NAMED_PIPE;
- setup[1] = 0xFFFF; /* driver replaces this */
- rparamcnt = 0;
+ smbioc_xnp_t ioc;
- err = smb_t2_request(fd, 2, setup, "\\PIPE\\",
- 0, NULL, /* TX paramcnt, params */
- tdlen, (void *)tdata,
- &rparamcnt, NULL, /* no RX params */
- rdlen, rdata, more);
+ /* this gets copyin & copyout */
+ bzero(&ioc, sizeof (ioc));
+ ioc.ioc_tdlen = tdlen;
+ ioc.ioc_rdlen = *rdlen;
+ ioc.ioc_more = 0;
+ ioc.ioc_tdata = (char *)tdata;
+ ioc.ioc_rdata = rdata;
- if (err)
+ if (nsmb_ioctl(fd, SMBIOC_XACTNP, &ioc) == -1) {
*rdlen = 0;
+ return (-1);
+ }
+
+ *rdlen = ioc.ioc_rdlen;
+ *more = ioc.ioc_more;
- return (err);
+ return (0);
}
diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c
index 63c6cce242..0e781f7099 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 2018 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);
@@ -119,7 +121,6 @@ smb_ctx_findvc(struct smb_ctx *ctx)
if (err == 0) {
/* re-use an existing VC */
- ctx->ct_flags |= SMBCF_SSNACTIVE;
return (0);
}
}
@@ -137,7 +138,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/getaddr.c b/usr/src/lib/libsmbfs/smb/getaddr.c
index 67e61567a1..7c01b0d7c9 100644
--- a/usr/src/lib/libsmbfs/smb/getaddr.c
+++ b/usr/src/lib/libsmbfs/smb/getaddr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -57,6 +58,8 @@
#include "charsets.h"
#include "private.h"
+static char smb_port[16] = "445";
+
void
dump_addrinfo(struct addrinfo *ai)
{
@@ -118,7 +121,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
struct nb_ctx *nbc = ctx->ct_nb;
struct addrinfo hints, *res;
char *srvaddr_str;
- int gaierr, gaierr2;
+ int gaierr;
if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0')
return (EAI_NONAME);
@@ -154,19 +157,26 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- gaierr = getaddrinfo(srvaddr_str, NULL, &hints, &res);
+ gaierr = getaddrinfo(srvaddr_str, smb_port, &hints, &res);
if (gaierr == 0) {
ctx->ct_addrinfo = res;
return (0);
}
/*
+ * If we really want to support NetBIOS, we should add
+ * an AF_NETBIOS entry to the address list here.
+ * For now, let's just skip NetBIOS.
+ * (Can we just kill NetBIOS? Please? :)
+ */
+#if 0 /* XXX Just kill NetBIOS? */
+ /*
* If regular IP name lookup failed, try NetBIOS,
* but only if given a valid NetBIOS name and if
* NetBIOS name lookup is enabled.
*/
if (nbc->nb_flags & NBCF_NS_ENABLE) {
- gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
+ int gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
if (gaierr2 == 0) {
if (res->ai_canonname)
strlcpy(ctx->ct_srvname,
@@ -176,6 +186,7 @@ smb_ctx_getaddr(struct smb_ctx *ctx)
return (0);
}
}
+#endif
/*
* Return the original error from getaddrinfo
diff --git a/usr/src/lib/libsmbfs/smb/iod_wk.c b/usr/src/lib/libsmbfs/smb/iod_wk.c
index 53f3c515be..38e9d5e0de 100644
--- a/usr/src/lib/libsmbfs/smb/iod_wk.c
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c
@@ -20,9 +20,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -59,22 +60,21 @@
#include "private.h"
/*
- * Be the reader thread for this VC.
+ * The user agent (smbiod) calls smb_iod_connect for the first
+ * connection to some server, and if that succeeds, will start a
+ * thread running this function, passing the smb_ctx_t
+ *
+ * This thread now enters the driver and stays there, reading
+ * network responses as long as the connection is alive.
*/
int
smb_iod_work(smb_ctx_t *ctx)
{
smbioc_ssn_work_t *work = &ctx->ct_work;
- int vcst, err = 0;
+ int err = 0;
DPRINT("server: %s", ctx->ct_srvname);
- /* Calle should have opened these */
- if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) {
- err = EINVAL;
- goto out;
- }
-
/*
* This is the reader / reconnect loop.
*
@@ -84,34 +84,35 @@ smb_iod_work(smb_ctx_t *ctx)
*
* XXX: Add some syslog calls in here?
*/
- vcst = SMBIOD_ST_VCACTIVE;
for (;;) {
- switch (vcst) {
+ DPRINT("state: %s",
+ smb_iod_state_name(work->wk_out_state));
+
+ switch (work->wk_out_state) {
case SMBIOD_ST_IDLE:
/*
* Wait for driver requests to arrive
* for this VC, then return here.
* Next state is normally RECONNECT.
*/
- DPRINT("state: idle");
- if (ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_IDLE, &vcst) == -1) {
+ DPRINT("Call _ioc_idle...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_IDLE, work) == -1) {
err = errno;
DPRINT("ioc_idle: err %d", err);
goto out;
}
+ DPRINT("Ret. from _ioc_idle");
continue;
case SMBIOD_ST_RECONNECT:
- DPRINT("state: reconnect");
+ DPRINT("Call _iod_connect...");
err = smb_iod_connect(ctx);
- if (err == 0) {
- vcst = SMBIOD_ST_VCACTIVE;
+ if (err == 0)
continue;
- }
- DPRINT("_iod_connect: err %d", err);
+ DPRINT("iod_connect: err %d", err);
/*
* If the error was EAUTH, retry is
* not likely to succeed either, so
@@ -119,64 +120,57 @@ smb_iod_work(smb_ctx_t *ctx)
* will need to run smbutil to get
* a new thread with new auth info.
*/
- if (err == EAUTH)
+ if (err == EAUTH) {
+ DPRINT("iod_connect: EAUTH (give up)");
goto out;
- vcst = SMBIOD_ST_RCFAILED;
- continue;
-
- case SMBIOD_ST_RCFAILED:
- DPRINT("state: rcfailed");
+ }
/*
- * Reconnect failed. Kill off any
- * requests waiting in the driver,
- * then get ready to try again.
- * Next state is normally IDLE.
+ * Reconnect failed. Notify any requests
+ * that we're not connected, and delay.
+ * Next state will be IDLE or RECONNECT.
*/
- if (ioctl(ctx->ct_dev_fd,
- SMBIOC_IOD_RCFAIL, &vcst) == -1) {
+ DPRINT("Call _iod_rcfail...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
+ SMBIOC_IOD_RCFAIL, work) == -1) {
err = errno;
- DPRINT("ioc_rcfail: err %d", err);
+ DPRINT("iod_rcfail: err %d", err);
goto out;
}
continue;
- case SMBIOD_ST_VCACTIVE:
- DPRINT("state: active");
- if (ioctl(ctx->ct_dev_fd,
+ case SMBIOD_ST_AUTHOK:
+ /*
+ * This is where we enter the driver and
+ * stay there. While the connection is up
+ * the VC will have SMBIOD_ST_VCACTIVE
+ */
+ DPRINT("Call _iod_work...");
+ if (nsmb_ioctl(ctx->ct_dev_fd,
SMBIOC_IOD_WORK, work) == -1) {
err = errno;
- DPRINT("ioc_work: err %d", err);
+ DPRINT("iod_work: err %d", err);
goto out;
}
- vcst = work->wk_out_state;
- /*
- * Go ahead and close the transport now,
- * rather than wait until reconnect to
- * this server.
- */
- close(ctx->ct_tran_fd);
- ctx->ct_tran_fd = -1;
+ DPRINT("Ret. from _ioc_work");
continue;
case SMBIOD_ST_DEAD:
- DPRINT("state: dead");
+ DPRINT("got state=DEAD");
err = 0;
goto out;
default:
- DPRINT("state: BAD(%d)", vcst);
+ DPRINT("Unexpected state: %d (%s)",
+ work->wk_out_state,
+ smb_iod_state_name(work->wk_out_state));
err = EFAULT;
goto out;
}
}
out:
- if (ctx->ct_tran_fd != -1) {
- close(ctx->ct_tran_fd);
- 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/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c
index 208ec6d0a4..421a0bda37 100644
--- a/usr/src/lib/libsmbfs/smb/krb5ssp.c
+++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c
@@ -32,6 +32,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -90,7 +91,7 @@ extern MECH_OID g_stcMechOIDList [];
typedef struct krb5ssp_state {
/* Filled in by krb5ssp_init_client */
krb5_context ss_krb5ctx; /* krb5 context (ptr) */
- krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
+ krb5_ccache ss_krb5cc; /* credentials cache (ptr) */
krb5_principal ss_krb5clp; /* client principal (ptr) */
/* Filled in by krb5ssp_get_tkt */
krb5_auth_context ss_auth; /* auth ctx. w/ server (ptr) */
@@ -107,8 +108,8 @@ krb5ssp_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
ulong_t len;
ulong_t bloblen = tktlen;
uchar_t krbapreq[2] = { KRB_AP_REQ, 0 };
- uchar_t *blob = NULL; /* result */
- uchar_t *b;
+ uchar_t *blob = NULL; /* result */
+ uchar_t *b;
bloblen += sizeof (krbapreq);
bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
@@ -168,7 +169,7 @@ krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server,
krb5_data outdata = {0};
krb5_error_code kerr = 0;
const char *fn = NULL;
- uchar_t *tkt;
+ uchar_t *tkt;
/* Should have these from krb5ssp_init_client. */
if (kctx == NULL || kcc == NULL) {
@@ -252,9 +253,9 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
int err;
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
- uchar_t *tkt = NULL;
+ uchar_t *tkt = NULL;
ulong_t tktlen;
- uchar_t *gtok = NULL; /* gssapi token */
+ uchar_t *gtok = NULL; /* gssapi token */
ulong_t gtoklen; /* gssapi token length */
char *prin = ctx->ct_srvname;
@@ -268,9 +269,6 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
if ((err = mb_put_mem(out_mb, gtok, gtoklen, MB_MSYSTEM)) != 0)
goto out;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN)
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
-
out:
if (gtok)
free(gtok);
@@ -383,7 +381,7 @@ krb5ssp_final(struct ssp_ctx *sp)
struct smb_ctx *ctx = sp->smb_ctx;
krb5ssp_state_t *ss = sp->sp_private;
krb5_keyblock *ssn_key = NULL;
- int err, len;
+ int err;
/*
* Save the session key, used for SMB signing
@@ -398,35 +396,32 @@ krb5ssp_final(struct ssp_ctx *sp)
err = EAUTH;
goto out;
}
- memset(ctx->ct_ssn_key, 0, SMBIOC_HASH_SZ);
- if ((len = ssn_key->length) > SMBIOC_HASH_SZ)
- len = SMBIOC_HASH_SZ;
- memcpy(ctx->ct_ssn_key, ssn_key->contents, len);
+
+ /* Sanity check the length */
+ if (ssn_key->length > 1024) {
+ DPRINT("session key too long");
+ err = EAUTH;
+ goto out;
+ }
/*
- * Set the MAC key on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = ssn_key->length;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ssn_key->contents,
- ctx->ct_mackeylen);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
+ }
+ ctx->ct_ssnkey_buf = malloc(ssn_key->length);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
}
+ ctx->ct_ssnkey_len = ssn_key->length;
+ memcpy(ctx->ct_ssnkey_buf, ssn_key->contents, ctx->ct_ssnkey_len);
err = 0;
out:
- if (ssn_key)
+ if (ssn_key != NULL)
krb5_free_keyblock(ss->ss_krb5ctx, ssn_key);
return (err);
@@ -508,7 +503,7 @@ krb5ssp_init_client(struct ssp_ctx *sp)
krb5ssp_state_t *ss;
krb5_error_code kerr;
krb5_context kctx = NULL;
- krb5_ccache kcc = NULL;
+ krb5_ccache kcc = NULL;
krb5_principal kprin = NULL;
if ((sp->smb_ctx->ct_authflags & SMB_AT_KRB5) == 0) {
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..a94b3bc6e1 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 2018 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,12 @@ SYMBOL_VERSION SUNWprivate {
nls_str_toloc;
nls_str_upper;
+ nsmb_close { FLAGS = NODIRECT };
+ nsmb_ioctl { FLAGS = NODIRECT };
+
+ smb_cf_minauth_from_str;
+ smb_cf_version_from_str;
+
smb_close_rcfile;
smb_ctx_alloc;
@@ -72,6 +83,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;
@@ -82,6 +94,8 @@ SYMBOL_VERSION SUNWprivate {
smb_ctx_setauthflags;
smb_ctx_setdomain;
smb_ctx_setfullserver;
+ smb_ctx_setminver;
+ smb_ctx_setmaxver;
smb_ctx_setnbflags;
smb_ctx_setpassword;
smb_ctx_setpwhash;
@@ -108,25 +122,16 @@ 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;
smb_simpledecrypt;
smb_strerror;
-#
-# Functions to support the Remote Access Protocol (RAP)
- smb_rap_create;
- smb_rap_done;
- smb_rap_error;
- smb_rap_getNparam;
- smb_rap_request;
- smb_rap_setNparam;
- smb_rap_setPparam;
-#
smb_verbose { FLAGS = NODIRECT }; # data
#
# Functions to support Access Control Lists (ACLs)
diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c
deleted file mode 100644
index 319e250296..0000000000
--- a/usr/src/lib/libsmbfs/smb/nb_ssn.c
+++ /dev/null
@@ -1,336 +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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/*
- * NetBIOS session service functions
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-
-#include <netsmb/netbios.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-#include <netsmb/mchain.h>
-
-#include "private.h"
-#include "charsets.h"
-
-static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
-static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
-static int nb_ssn_pollin(struct smb_ctx *, int);
-
-/*
- * Send a data message.
- */
-int
-smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
-}
-
-/*
- * Send a NetBIOS message, after
- * prepending the 4-byte header.
- */
-static int
-nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
- int mtype, int mlen)
-{
- mbuf_t *m;
- uint32_t hdr, hdrbuf;
- int err;
-
- m = mbp->mb_top;
- if (m == NULL)
- return (EINVAL);
-
- /*
- * Prepend the NetBIOS header.
- * Our mbufs leave space for this.
- */
- hdr = (mtype << 24) | mlen;
- hdrbuf = htonl(hdr);
- m->m_data -= 4;
- m->m_len += 4;
- bcopy(&hdrbuf, m->m_data, 4);
-
- /*
- * Get contiguous data (so TCP won't fragment)
- * Note: replaces mb_top.
- */
- err = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (err)
- return (err);
- m = mbp->mb_top;
-
- /*
- * Send it.
- */
- if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
- if (t_errno == TSYSERR)
- err = errno;
- else
- err = EPROTO;
- DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
- return (err);
- }
-
- return (0);
-}
-
-/*
- * Receive a data message. Discard anything else.
- * Caller must deal with EAGAIN, EINTR.
- */
-int
-smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
-{
- int err, mtype, mlen;
- err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
- if (err)
- return (err);
- if (mtype != NB_SSN_MESSAGE) {
- DPRINT("discard type 0x%x", mtype);
- mb_done(mbp);
- return (EAGAIN);
- }
- if (mlen == 0) {
- DPRINT("zero length");
- mb_done(mbp);
- return (EAGAIN);
- }
-
- return (0);
-}
-
-/*
- * Receive a NetBIOS message, any type.
- * Give caller type and length.
- */
-static int
-nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
- int *mtype, int *mlen)
-{
- char *buf;
- uint32_t hdr, hdrbuf;
- int cnt, len, err, moreflag;
- int fd = ctx->ct_tran_fd;
- int tmo = smb_recv_timeout * 1000;
-
- /*
- * Start by getting the header
- * (four bytes)
- */
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- moreflag = 0;
- cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
-
- if (cnt != sizeof (hdrbuf)) {
- DPRINT("hdr cnt %d", cnt);
- return (EPROTO);
- }
-
- /*
- * Decode the header, get the length.
- */
- hdr = ntohl(hdrbuf);
- *mtype = (hdr >> 24) & 0xff;
- *mlen = hdr & 0xffffff;
-
- if (mlen == 0)
- return (0);
-
- /*
- * Get a message buffer, read the payload
- */
- if ((err = mb_init_sz(mb, *mlen)) != 0)
- return (err);
- buf = mb->mb_top->m_data;
- len = *mlen;
- while (len > 0) {
- if (!moreflag) {
- if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
- DPRINT("pollin err %d", err);
- return (err);
- }
- }
-
- moreflag = 0;
- cnt = t_rcv(fd, buf, len, &moreflag);
- if (cnt < 0) {
- err = get_xti_err(fd);
- DPRINT("t_errno %d err %d", t_errno, err);
- return (err);
- }
- buf += cnt;
- len -= cnt;
- }
- mb->mb_top->m_len = *mlen;
- mb->mb_count = *mlen;
-
- return (0);
-}
-
-int
-get_xti_err(int fd)
-{
- int look;
- if (t_errno == TSYSERR)
- return (errno);
-
- if (t_errno == TLOOK) {
- look = t_look(fd);
- switch (look) {
- case T_DISCONNECT:
- (void) t_rcvdis(fd, NULL);
- (void) t_snddis(fd, NULL);
- return (ECONNRESET);
- case T_ORDREL:
- /* Received orderly release indication */
- (void) t_rcvrel(fd);
- /* Send orderly release indicator */
- (void) t_sndrel(fd);
- return (ECONNRESET);
- }
- }
- return (EPROTO);
-}
-
-/*
- * Wait for data we can receive.
- * Timeout is mSec., as for poll(2)
- */
-static int
-nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
-{
- struct pollfd pfd[1];
- int cnt, err;
-
- pfd[0].fd = ctx->ct_tran_fd;
- pfd[0].events = POLLIN | POLLPRI;
- pfd[0].revents = 0;
- cnt = poll(pfd, 1, tmo);
- switch (cnt) {
- case 0:
- err = ETIME;
- break;
- case -1:
- err = errno;
- break;
- default:
- err = 0;
- break;
- }
- return (err);
-}
-
-/*
- * Send a NetBIOS session request and
- * wait for the response.
- */
-int
-nb_ssn_request(struct smb_ctx *ctx, char *srvname)
-{
- struct mbdata req, res;
- struct nb_name lcl, srv;
- int err, mtype, mlen;
- char *ucwks;
-
- bzero(&req, sizeof (req));
- bzero(&res, sizeof (res));
-
- if ((err = mb_init(&req)) != 0)
- goto errout;
-
- ucwks = utf8_str_toupper(ctx->ct_locname);
- if (ucwks == NULL) {
- err = ENOMEM;
- goto errout;
- }
-
- /* Local NB name. */
- snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
- lcl.nn_type = NBT_WKSTA;
- lcl.nn_scope = ctx->ct_nb->nb_scope;
-
- /* Server NB name */
- snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
- srv.nn_type = NBT_SERVER;
- srv.nn_scope = ctx->ct_nb->nb_scope;
-
- /*
- * Build the request. Header is prepended later.
- */
- if ((err = nb_name_encode(&req, &srv)) != 0)
- goto errout;
- if ((err = nb_name_encode(&req, &lcl)) != 0)
- goto errout;
-
- /*
- * Send it, wait for the reply.
- */
- err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
- if (err) {
- DPRINT("send, err %d", err);
- goto errout;
- }
- err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
- if (err) {
- DPRINT("recv, err %d", err);
- goto errout;
- }
-
- if (mtype != NB_SSN_POSRESP) {
- DPRINT("recv, mtype 0x%x", mtype);
- err = ECONNREFUSED;
- goto errout;
- }
-
- return (0);
-
-errout:
- mb_done(&res);
- mb_done(&req);
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c
deleted file mode 100644
index 770b742c44..0000000000
--- a/usr/src/lib/libsmbfs/smb/negprot.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Negotiate Protocol, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#include <sys/fcntl.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/netbios.h>
-#include <netsmb/nb_lib.h>
-#include <netsmb/smb_dev.h>
-
-#include "charsets.h"
-#include "smb_crypt.h"
-#include "private.h"
-
-/*
- * SMB dialects that we know about.
- */
-struct smb_dialect {
- int d_id;
- const char *d_name;
-};
-static struct smb_dialect smb_dialects[] = {
- {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
- {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
- {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
- {SMB_DIALECT_LANMAN2_1, "LANMAN2.1"},
- {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
- {-1, NULL}
-};
-
-#define SMB_DIALECT_MAX \
- (sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
-
-static const uint32_t smb_clnt_caps_mask =
- SMB_CAP_UNICODE |
- SMB_CAP_LARGE_FILES |
- SMB_CAP_NT_SMBS |
- SMB_CAP_STATUS32 |
- SMB_CAP_EXT_SECURITY;
-
-/*
- * SMB Negotiate Protocol
- * Based on code from the driver: smb_smb.c
- *
- * If using Extended Security, oblob (output)
- * will hold the initial security "hint".
- */
-int
-smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
-{
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp;
- struct mbdata *mbp;
- struct smb_dialect *dp;
- int err, len;
- uint8_t wc, eklen;
- uint16_t dindex, bc;
- int will_sign = 0;
-
- /*
- * Initialize: vc_hflags and vc_hflags2.
- * Note: ctx->ct_hflags* are copied into the
- * (per request) rqp->rq_hflags* by smb_rq_init.
- *
- * Like Windows, set FLAGS2_UNICODE in our first request,
- * even though technically we don't yet know whether the
- * server supports Unicode. Will clear this flag below
- * if we find out it doesn't. Need to do this because
- * some servers reject all non-Unicode requests.
- */
- ctx->ct_hflags =
- SMB_FLAGS_CASELESS |
- SMB_FLAGS_CANONICAL_PATHNAMES;
- ctx->ct_hflags2 =
- SMB_FLAGS2_KNOWS_LONG_NAMES |
- SMB_FLAGS2_KNOWS_EAS |
- /* SMB_FLAGS2_IS_LONG_NAME |? */
- /* EXT_SEC (see below) */
- SMB_FLAGS2_ERR_STATUS |
- SMB_FLAGS2_UNICODE;
-
- /*
- * Sould we offer extended security?
- * We'll turn this back off below if
- * the server doesn't support it.
- */
- if (ctx->ct_vopt & SMBVOPT_EXT_SEC)
- ctx->ct_hflags2 |= SMB_FLAGS2_EXT_SEC;
-
- /*
- * The initial UID needs to be zero,
- * or Windows XP says "bad user".
- * The initial TID is all ones, but
- * we don't use it or store it here
- * because the driver handles that.
- */
- is->is_smbuid = 0;
-
- /*
- * In case we're reconnecting,
- * free previous stuff.
- */
- ctx->ct_mac_seqno = 0;
- if (ctx->ct_mackey != NULL) {
- free(ctx->ct_mackey);
- ctx->ct_mackey = NULL;
- ctx->ct_mackeylen = 0;
- }
-
- sv = &ctx->ct_sopt;
- bzero(sv, sizeof (struct smb_sopt));
-
- err = smb_rq_init(ctx, SMB_COM_NEGOTIATE, &rqp);
- if (err)
- return (err);
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_rq;
- mb_put_uint8(mbp, 0); /* word count */
- smb_rq_bstart(rqp);
- for (dp = smb_dialects; dp->d_id != -1; dp++) {
- mb_put_uint8(mbp, SMB_DT_DIALECT);
- mb_put_astring(mbp, dp->d_name);
- }
- smb_rq_bend(rqp);
-
- /*
- * This does the OTW call
- */
- err = smb_rq_internal(ctx, rqp);
- if (err) {
- DPRINT("call failed, err %d", err);
- goto errout;
- }
- if (rqp->rq_status != 0) {
- DPRINT("nt status 0x%x", rqp->rq_status);
- err = EBADRPC;
- goto errout;
- }
-
- /*
- * Decode the response
- *
- * Comments to right show names as described in
- * The Microsoft SMB Protocol spec. [MS-SMB]
- * section 2.2.3
- */
- mbp = &rqp->rq_rp;
- (void) md_get_uint8(mbp, &wc);
- err = md_get_uint16le(mbp, &dindex);
- if (err || dindex > SMB_DIALECT_MAX) {
- DPRINT("err %d dindex %d", err, (int)dindex);
- goto errout;
- }
- dp = smb_dialects + dindex;
- sv->sv_proto = dp->d_id;
- DPRINT("Dialect %s", dp->d_name);
- if (dp->d_id < SMB_DIALECT_NTLM0_12) {
- /* XXX: User-visible warning too? */
- DPRINT("old dialect %s", dp->d_name);
- goto errout;
- }
- if (wc != 17) {
- DPRINT("bad wc %d", (int)wc);
- goto errout;
- }
- md_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */
- md_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */
- md_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */
- md_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */
- md_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */
- md_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */
- md_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */
- md_get_mem(mbp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
- md_get_uint16le(mbp, (uint16_t *)&sv->sv_tz);
- md_get_uint8(mbp, &eklen); /* EncryptionKeyLength */
- err = md_get_uint16le(mbp, &bc); /* ByteCount */
- if (err)
- goto errout;
-
- /* BEGIN CSTYLED */
- /*
- * Will we do SMB signing? Or block the connection?
- * The table below describes this logic. References:
- * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
- * http://msdn.microsoft.com/en-us/library/cc212511.aspx
- * http://msdn.microsoft.com/en-us/library/cc212929.aspx
- *
- * Srv/Cli | Required | Enabled | If Required | Disabled
- * ------------+----------+------------+-------------+-----------
- * Required | Signed | Signed | Signed | Blocked [1]
- * ------------+----------+------------+-------------+-----------
- * Enabled | Signed | Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * If Required | Signed | Not Signed | Not Signed | Not Signed
- * ------------+----------+------------+-------------+-----------
- * Disabled | Blocked | Not Signed | Not Signed | Not Signed
- *
- * [1] Like Windows 2003 and later, we don't really implement
- * the "Disabled" setting. Instead we implement "If Required",
- * so we always sign if the server requires signing.
- */
- /* END CSTYLED */
-
- if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
- /*
- * Server requires signing. We will sign,
- * even if local setting is "disabled".
- */
- will_sign = 1;
- } else if (sv->sv_sm & SMB_SM_SIGS) {
- /*
- * Server enables signing (client's option).
- * If enabled locally, do signing.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED)
- will_sign = 1;
- /* else not signing. */
- } else {
- /*
- * Server does not support signing.
- * If we "require" it, bail now.
- */
- if (ctx->ct_vopt & SMBVOPT_SIGNING_REQUIRED) {
- DPRINT("Client requires signing "
- "but server has it disabled.");
- err = EBADRPC;
- goto errout;
- }
- }
-
- if (will_sign) {
- ctx->ct_vcflags |= SMBV_WILL_SIGN;
- }
- DPRINT("Security signatures: %d", will_sign);
-
- /* See comment above re. FLAGS2_UNICODE */
- if (sv->sv_caps & SMB_CAP_UNICODE)
- ctx->ct_vcflags |= SMBV_UNICODE;
- else
- ctx->ct_hflags2 &= ~SMB_FLAGS2_UNICODE;
-
- if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
- /*
- * They don't do NT error codes.
- *
- * If we send requests with
- * SMB_FLAGS2_ERR_STATUS set in
- * Flags2, Windows 98, at least,
- * appears to send replies with that
- * bit set even though it sends back
- * DOS error codes. (They probably
- * just use the request header as
- * a template for the reply header,
- * and don't bother clearing that bit.)
- *
- * Therefore, we clear that bit in
- * our vc_hflags2 field.
- */
- ctx->ct_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
- }
- if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
- sv->sv_maxtx < 4096 &&
- (sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
- ctx->ct_vcflags |= SMBV_WIN95;
- DPRINT("Win95 detected");
- }
-
- /*
- * The rest of the message varies depending on
- * whether we've negotiated "extended security".
- *
- * With extended security, we have:
- * Server_GUID (length 16)
- * Security_BLOB
- * Otherwise we have:
- * EncryptionKey (length is eklen)
- * PrimaryDomain
- */
- if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
- struct mbuf *m;
- DPRINT("Ext.Security: yes");
-
- /*
- * Skip the server GUID.
- */
- err = md_get_mem(mbp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
- if (err)
- goto errout;
- /*
- * Remainder is the security blob.
- * Note: eklen "must be ignored" [MS-SMB]
- */
- len = (int)bc - SMB_GUIDLEN;
- if (len < 0)
- goto errout;
-
- /*
- * Get the (optional) SPNEGO "hint".
- */
- err = md_get_mbuf(mbp, len, &m);
- if (err)
- goto errout;
- mb_initm(oblob, m);
- oblob->mb_count = len;
- } else {
- DPRINT("Ext.Security: no");
- ctx->ct_hflags2 &= ~SMB_FLAGS2_EXT_SEC;
-
- /*
- * Save the "Encryption Key" (the challenge).
- *
- * Sanity check: make sure the sec. blob length
- * isn't bigger than the byte count.
- */
- if (bc < eklen || eklen < NTLM_CHAL_SZ) {
- err = EBADRPC;
- goto errout;
- }
- err = md_get_mem(mbp, ctx->ct_srv_chal,
- NTLM_CHAL_SZ, MB_MSYSTEM);
- /*
- * Server domain follows (ignored)
- * Note: NOT aligned(2) - unusual!
- */
- }
-
- smb_rq_done(rqp);
-
- /*
- * A few sanity checks on what we received,
- * becuse we will send these in ssnsetup.
- *
- * Maximum outstanding requests (we care),
- * and Max. VCs (we only use one). Also,
- * MaxBufferSize lower limit per spec.
- */
- if (sv->sv_maxmux < 1)
- sv->sv_maxmux = 1;
- if (sv->sv_maxvcs < 1)
- sv->sv_maxvcs = 1;
- if (sv->sv_maxtx < 1024)
- sv->sv_maxtx = 1024;
-
- /*
- * Maximum transfer size.
- * Sanity checks:
- *
- * Let's be conservative about an upper limit here.
- * Win2k uses 16644 (and others) so 32k should be a
- * reasonable sanity limit for this value.
- *
- * Note that this limit does NOT affect READX/WRITEX
- * with CAP_LARGE_..., which we nearly always use.
- */
- is->is_txmax = sv->sv_maxtx;
- if (is->is_txmax > 0x8000)
- is->is_txmax = 0x8000;
-
- /*
- * Max read/write sizes, WITHOUT overhead.
- * This is just the payload size, so we must
- * leave room for the SMB headers, etc.
- * This is just the ct_txmax value, but
- * reduced and rounded down. Tricky bit:
- *
- * Servers typically give us a value that's
- * some nice "round" number, i.e 0x4000 plus
- * some overhead, i.e. Win2k: 16644==0x4104
- * Subtract for the SMB header (32) and the
- * SMB command word and byte vectors (34?),
- * then round down to a 512 byte multiple.
- */
- len = is->is_txmax - 68;
- len &= 0xFE00;
- /* XXX: Not sure yet which of these to keep. */
- is->is_rwmax = len;
- is->is_rxmax = len;
- is->is_wxmax = len;
-
- /*
- * Most of the "capability" bits we offer in session setup
- * are just copied from those offered by the server.
- */
- ctx->ct_clnt_caps = sv->sv_caps & smb_clnt_caps_mask;
-
- /* Get the client nonce. */
- (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
-
- return (0);
-
-errout:
- smb_rq_done(rqp);
- if (err == 0)
- err = EBADRPC;
- return (err);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c
index 9f08a2eaca..44b26f54e6 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.c
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c
@@ -34,7 +34,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -184,7 +184,8 @@ ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash)
*/
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -229,7 +230,7 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -245,7 +246,8 @@ ntlm_put_v1_responses(struct smb_ctx *ctx,
*/
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
MD5_CTX context;
uchar_t challenges[2 * NTLM_CHAL_SZ];
@@ -299,7 +301,7 @@ ntlm_put_v1x_responses(struct smb_ctx *ctx,
/*
* Compute the session key
*/
- ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+ ntlm_v1_session_key(ssn_key, ctx->ct_nthash);
return (err);
}
@@ -477,7 +479,8 @@ ntlm_v2_session_key(uchar_t *ssn_key,
*/
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssn_key)
{
uchar_t *lmresp, *ntresp;
int err;
@@ -547,7 +550,7 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
/*
* Compute the session key
*/
- ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp);
+ ntlm_v2_session_key(ssn_key, v2hash, ntresp);
out:
if (err) {
@@ -650,37 +653,13 @@ out:
}
/*
- * Build the MAC key (for SMB signing)
- */
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp)
-{
- struct mbuf *m;
- size_t len;
- char *p;
-
- /*
- * MAC_key = concat(session_key, nt_response)
- */
- m = ntresp_mbp->mb_top;
- len = NTLM_HASH_SZ + m->m_len;
- if ((p = malloc(len)) == NULL)
- return (ENOMEM);
- ctx->ct_mackeylen = len;
- ctx->ct_mackey = p;
- memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
- memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
-
- return (0);
-}
-
-/*
* Helper for ntlmssp_put_type3 - Build the "key exchange key"
* used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
* HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
*/
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey)
{
uchar_t data[NTLM_HASH_SZ];
uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *);
@@ -690,6 +669,6 @@ ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey)
memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ);
/* HMAC_MD5(SessionBaseKey, concat(...)) */
- HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ,
+ HMACT64(kxkey, ssn_key, NTLM_HASH_SZ,
data, NTLM_HASH_SZ);
}
diff --git a/usr/src/lib/libsmbfs/smb/ntlm.h b/usr/src/lib/libsmbfs/smb/ntlm.h
index 447033b516..d0c093689a 100644
--- a/usr/src/lib/libsmbfs/smb/ntlm.h
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h
@@ -22,7 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NTLM_H
@@ -38,7 +39,7 @@
* NTLM_HASH_SZ: 16 bytes (see smb_lib.h)
* NTLM_CHAL_SZ: 8 bytes (see smb_lib.h)
*/
-#define NTLM_V1_RESP_SZ 24 /* response size */
+#define NTLM_V1_RESP_SZ 24 /* response size */
#define NAMETYPE_EOL 0x0000 /* end of list of names */
#define NAMETYPE_MACHINE_NB 0x0001 /* NetBIOS machine name */
@@ -57,20 +58,21 @@ ntlm_build_target_info(struct smb_ctx *, struct mbuf *, struct mbdata *);
int
ntlm_put_v1_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v1x_responses(struct smb_ctx *ctx,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
int
ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
- struct mbdata *lm_mbp, struct mbdata *nt_mbp);
-
-int
-ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp);
+ struct mbdata *lm_mbp, struct mbdata *nt_mbp,
+ uchar_t *ssnkey);
void
-ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey);
+ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp,
+ uchar_t *ssn_key, uchar_t *kxkey);
#endif /* _NTLM_H */
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c
index f39fa594ec..5ae583114d 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -67,13 +67,14 @@
#include "ntlmssp.h"
/* A shorter alias for a crazy long name from [MS-NLMP] */
-#define NTLMSSP_NEGOTIATE_NTLM2 \
+#define NTLMSSP_NEGOTIATE_ESS \
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
typedef struct ntlmssp_state {
uint32_t ss_flags;
char *ss_target_name; /* Primary domain or server name */
struct mbuf *ss_target_info;
+ uchar_t ss_ssnkey[NTLM_HASH_SZ];
uchar_t ss_kxkey[NTLM_HASH_SZ];
} ntlmssp_state_t;
@@ -90,8 +91,7 @@ struct sec_buf {
static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
static int
-ntlm_rand_ssn_key(struct smb_ctx *ctx,
- ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
+ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
/*
* Get a "security buffer" (header part)
@@ -249,16 +249,14 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
NTLMSSP_NEGOTIATE_SEAL |
/* NTLMSSP_NEGOTIATE_LM_KEY (never) */
NTLMSSP_NEGOTIATE_NTLM |
- /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
- NTLMSSP_NEGOTIATE_NTLM2 |
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
+ NTLMSSP_NEGOTIATE_ESS |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_56;
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
+ if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0)
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
@@ -447,15 +445,20 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
/*
* We're setting up a NULL session, meaning
* the lm_mbc, nt_mbc parts remain empty.
- * Let's add the "anon" flag (hint).
- * As there is no session key, disable the
- * fancy session key stuff.
+ * Let's add the "anon" flag (hint), and
+ * as we have no OWF hashes, we can't use
+ * "extended session security" (_ESS).
+ * The SessionBaseKey is all zeros, so
+ * the KeyExchangeKey is too. Otherwise
+ * this is like NTLMv2/LMv2
*/
- hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
- ssp_st->ss_flags &= ~(
- NTLMSSP_NEGOTIATE_NTLM2 |
- NTLMSSP_NEGOTIATE_KEY_EXCH);
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
+ ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS;
+ hdr.h_flags = ssp_st->ss_flags;
err = 0;
+ /* KeyExchangeKey = SessionBaseKey = (zeros) */
+ memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ);
+ memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ);
} else if (ctx->ct_authflags & SMB_AT_NTLM2) {
/*
* Doing NTLMv2/LMv2
@@ -465,47 +468,49 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
if (err)
goto out;
err = ntlm_put_v2_responses(ctx, &ti_mbc,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
-
- } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ /* KeyExchangeKey = SessionBaseKey (v2) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
+ } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) {
/*
* Doing NTLM ("v1x") which is NTLM with
* "Extended Session Security"
*/
err = ntlm_put_v1x_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* Compute the "Key exchange key". */
- ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);
+ /*
+ * "v1x computes the KeyExchangeKey from both the
+ * server and client nonce and (v1) SessionBaseKey.
+ */
+ ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey,
+ ssp_st->ss_kxkey);
} else {
/*
* Doing plain old NTLM (and LM if enabled)
*/
err = ntlm_put_v1_responses(ctx,
- &lm_mbc, &nt_mbc);
+ &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
if (err)
goto out;
- /* The "key exg. key" is the session base key */
- memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+ /* KeyExchangeKey = SessionBaseKey (v1) */
+ memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
}
/*
- * Compute the "Exported Session Key" and (possibly)
- * the "Encrypted Random Sesion Key".
- * [MS-NLMP 3.1.5.1.2]
+ * Compute the "ExportedSessionKey" and (possibly) the
+ * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2]
*/
if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
- err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc);
+ err = ntlm_rand_ssn_key(ssp_st, &ek_mbc);
if (err)
goto out;
} else {
/* ExportedSessionKey is the KeyExchangeKey */
- memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
+ memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ);
/* EncryptedRandomSessionKey remains NULL */
}
@@ -590,7 +595,6 @@ out:
*/
static int
ntlm_rand_ssn_key(
- struct smb_ctx *ctx,
ntlmssp_state_t *ssp_st,
struct mbdata *ek_mbp)
{
@@ -603,12 +607,12 @@ ntlm_rand_ssn_key(
encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
/* Set "ExportedSessionKey to NONCE(16) */
- (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ);
+ (void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ);
/* Set "EncryptedRandomSessionKey" to RC4(...) */
err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
ssp_st->ss_kxkey, NTLM_HASH_SZ,
- ctx->ct_ssn_key, NTLM_HASH_SZ);
+ ssp_st->ss_ssnkey, NTLM_HASH_SZ);
return (err);
}
@@ -617,34 +621,29 @@ ntlm_rand_ssn_key(
* ntlmssp_final
*
* Called after successful authentication.
- * Setup the MAC key for signing.
+ * Save the session key.
*/
int
ntlmssp_final(struct ssp_ctx *sp)
{
struct smb_ctx *ctx = sp->smb_ctx;
+ ntlmssp_state_t *ssp_st = sp->sp_private;
int err = 0;
/*
- * MAC_key is just the session key, but
- * Only on the first successful auth.
+ * Update/save the session key.
*/
- if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
- (ctx->ct_mackey == NULL)) {
- ctx->ct_mackeylen = NTLM_HASH_SZ;
- ctx->ct_mackey = malloc(ctx->ct_mackeylen);
- if (ctx->ct_mackey == NULL) {
- ctx->ct_mackeylen = 0;
- err = ENOMEM;
- goto out;
- }
- memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
- /*
- * Apparently, the server used seq. no. zero
- * for our previous message, so next is two.
- */
- ctx->ct_mac_seqno = 2;
+ if (ctx->ct_ssnkey_buf != NULL) {
+ free(ctx->ct_ssnkey_buf);
+ ctx->ct_ssnkey_buf = NULL;
}
+ ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ);
+ if (ctx->ct_ssnkey_buf == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ ctx->ct_ssnkey_len = NTLM_HASH_SZ;
+ memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
out:
return (err);
@@ -728,13 +727,17 @@ int
ntlmssp_init_client(struct ssp_ctx *sp)
{
ntlmssp_state_t *ssp_st;
+ smb_ctx_t *ctx = sp->smb_ctx;
- if ((sp->smb_ctx->ct_authflags &
+ if ((ctx->ct_authflags &
(SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
DPRINT("No NTLM authflags");
return (EINVAL);
}
+ /* Get the client nonce. */
+ (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
+
ssp_st = calloc(1, sizeof (*ssp_st));
if (ssp_st == NULL)
return (ENOMEM);
diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c
index c59bef81b4..698dd8359f 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 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
@@ -54,12 +57,24 @@
#include "private.h"
+/*
+ * Replacing invalid characters in print job titles:
+ *
+ * The spec. is unclear about what characters are allowed in a
+ * print job title (used with NtCreate) so out of caution this
+ * makes sure the title contains none of the characters that
+ * are known to be illegal in a file name component.
+ */
+static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
+
int
smb_open_printer(struct smb_ctx *ctx, const char *title,
int setuplen, int mode)
{
smbioc_printjob_t ioc;
- int err, tlen, new_fd;
+ char *p;
+ int err, tlen;
+ int new_fd = -1;
int32_t from_fd;
tlen = strlen(title);
@@ -75,7 +90,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 +103,15 @@ 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) {
+ /*
+ * The title is used in NtCreate so sanitize by
+ * replacing any illegal chars with spaces.
+ */
+ for (p = ioc.ioc_title; *p != '\0'; p++)
+ if (strchr(invalid_chars, *p) != NULL)
+ *p = ' ';
+
+ if (nsmb_ioctl(new_fd, SMBIOC_PRINTJOB, &ioc) == -1) {
err = errno;
goto errout;
}
@@ -96,7 +119,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/private.h b/usr/src/lib/libsmbfs/smb/private.h
index febca40126..d877cafa1d 100644
--- a/usr/src/lib/libsmbfs/smb/private.h
+++ b/usr/src/lib/libsmbfs/smb/private.h
@@ -31,9 +31,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _PRIVATE_H
@@ -61,60 +62,6 @@ extern void dprint(const char *, const char *, ...)
#endif
/*
- * Flags bits in ct_vcflags (copied from smb_conn.h)
- * Pass these to the driver?
- */
-#define SMBV_RECONNECTING 0x0002 /* conn in process of reconnection */
-#define SMBV_LONGNAMES 0x0004 /* conn configured to use long names */
-#define SMBV_ENCRYPT 0x0008 /* server demands encrypted password */
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
-#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
-#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
-#define SMBV_WILL_SIGN 0x0100 /* negotiated signing */
-
-/*
- * request handling structures
- */
-struct smb_rq {
- struct smb_ctx *rq_ctx;
- struct mbdata rq_rq;
- struct mbdata rq_rp;
- int rq_rpbufsz;
- uint8_t rq_cmd;
- uint8_t rq_hflags;
- uint16_t rq_hflags2;
- uint32_t rq_status;
- uint16_t rq_uid;
- uint16_t rq_tid;
- uint16_t rq_mid;
- uint32_t rq_seqno;
- /* See rq_[bw]{start,end} functions */
- char *rq_wcntp;
- int rq_wcbase;
- char *rq_bcntp;
- int rq_bcbase;
-};
-typedef struct smb_rq smb_rq_t;
-
-#define smb_rq_getrequest(rqp) (&(rqp)->rq_rq)
-#define smb_rq_getreply(rqp) (&(rqp)->rq_rp)
-
-int smb_rq_init(struct smb_ctx *, uchar_t, struct smb_rq **);
-void smb_rq_done(struct smb_rq *);
-void smb_rq_bstart(struct smb_rq *);
-void smb_rq_bend(struct smb_rq *);
-void smb_rq_wstart(struct smb_rq *);
-void smb_rq_wend(struct smb_rq *);
-int smb_rq_simple(struct smb_rq *);
-int smb_rq_dmem(struct mbdata *, const char *, size_t);
-int smb_rq_internal(struct smb_ctx *, struct smb_rq *);
-void smb_rq_sign(struct smb_rq *);
-int smb_rq_verify(struct smb_rq *);
-int smb_t2_request(int, int, uint16_t *, const char *,
- int, void *, int, void *, int *, void *, int *, void *, int *);
-
-/*
* This library extends the mchain.h function set a little.
*/
int m_getm(struct mbuf *, int, struct mbuf **);
@@ -174,16 +121,7 @@ int smb_ctx_getaddr(struct smb_ctx *ctx);
int smb_ctx_gethandle(struct smb_ctx *ctx);
int smb_iod_start(struct smb_ctx *);
-
-int smb_ssn_send(struct smb_ctx *, struct mbdata *);
-int smb_ssn_recv(struct smb_ctx *, struct mbdata *);
-
-int smb_negprot(struct smb_ctx *, struct mbdata *);
-
-int smb_ssnsetup_null(struct smb_ctx *);
-int smb_ssnsetup_ntlm1(struct smb_ctx *);
-int smb_ssnsetup_ntlm2(struct smb_ctx *);
-int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
+const char *smb_iod_state_name(enum smbiod_state st);
void smb_time_local2server(struct timeval *, int, long *);
void smb_time_server2local(ulong_t, int, struct timeval *);
diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c
deleted file mode 100644
index 546ee46f05..0000000000
--- a/usr/src/lib/libsmbfs/smb/rap.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
- *
- * This is very simple implementation of RAP protocol.
- */
-
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-#include <sys/isa_defs.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <libintl.h>
-#include <sysexits.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb_lib.h>
-#include <netsmb/smb_rap.h>
-#include "private.h"
-
-static int
-smb_rap_parserqparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'L':
- case 'T':
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- len = 4;
- break;
- case 'b':
- case 'F':
- len = 1;
- break;
- case 'r':
- case 's':
- len = 0;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpparam(const char *s, char **next, int *rlen)
-{
- char *np;
- int len = 0;
-
- switch (*s++) {
- case 'e':
- case 'h':
- len = 2;
- break;
- case 'i':
- len = 4;
- break;
- case 'g':
- len = 1;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_parserpdata(const char *s, char **next, int *rlen)
-{
- char *np;
- int len;
-
- switch (*s++) {
- case 'B':
- len = 1;
- break;
- case 'W':
- len = 2;
- break;
- case 'D':
- case 'O':
- case 'z':
- len = 4;
- break;
- default:
- return (EINVAL);
- }
- if (isdigit(*s)) {
- len *= strtoul(s, &np, 10);
- s = np;
- }
- *rlen = len;
- *(const char **)next = s;
- return (0);
-}
-
-static int
-smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
-{
- int len = strlen(value) + 1;
-
- bcopy(value, rap->r_npbuf, len);
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-/*
- * Marshal RAP request parameters.
- * Note: value is in host order.
- */
-static int
-smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
-{
- int len = 0;
- uint_t uv = (uint_t)value;
- uint32_t *lp;
- uint16_t *sp;
- char *p;
-
- switch (ptype) {
- case 'L':
- case 'W':
- /* LINTED */
- sp = (uint16_t *)rap->r_npbuf;
- *sp = htoles(uv);
- len = sizeof (*sp);
- break;
- case 'D':
- /* LINTED */
- lp = (uint32_t *)rap->r_npbuf;
- *lp = htolel(uv);
- len = sizeof (*lp);
- break;
- case 'b':
- p = rap->r_npbuf;
- memset(p, uv, plen);
- len = plen;
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += len;
- rap->r_plen += len;
- return (0);
-}
-
-int
-smb_rap_create(int fn, const char *param, const char *data,
- struct smb_rap **rapp)
-{
- struct smb_rap *rap;
- char *p;
- int plen = 0, len = 0;
-
- rap = malloc(sizeof (*rap));
- if (rap == NULL)
- return (ENOMEM);
- bzero(rap, sizeof (*rap));
- p = rap->r_sparam = rap->r_nparam = strdup(param);
- rap->r_sdata = rap->r_ndata = strdup(data);
-
- /*
- * Calculate length of request parameter block
- */
- len = 2 + strlen(param) + 1 + strlen(data) + 1;
- while (*p) {
- if (smb_rap_parserqparam(p, &p, &plen) != 0)
- break;
- len += plen;
- }
- rap->r_pbuf = rap->r_npbuf = malloc(len);
- if (rap->r_pbuf == NULL)
- return (ENOMEM);
- (void) smb_rap_rqparam(rap, 'W', 1, fn);
- (void) smb_rap_rqparam_z(rap, rap->r_sparam);
- (void) smb_rap_rqparam_z(rap, rap->r_sdata);
- *rapp = rap;
- return (0);
-}
-
-void
-smb_rap_done(struct smb_rap *rap)
-{
- if (rap->r_sparam)
- free(rap->r_sparam);
- if (rap->r_sdata)
- free(rap->r_sdata);
- if (rap->r_pbuf)
- free(rap->r_pbuf);
-#ifdef NOTYETDEFINED
- if (rap->r_npbuf)
- free(rap->r_npbuf);
- if (rap->r_dbuf)
- free(rap->r_dbuf);
- if (rap->r_rcvbuf)
- free(rap->r_rcvbuf);
-#endif
- free(rap);
-}
-
-int
-smb_rap_setNparam(struct smb_rap *rap, int value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'L':
- rap->r_rcvbuflen = value;
- /* FALLTHROUGH */
- case 'W':
- case 'D':
- case 'b':
- error = smb_rap_rqparam(rap, ptype, plen, value);
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_setPparam(struct smb_rap *rap, void *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
-
- error = smb_rap_parserqparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'r':
- rap->r_rcvbuf = value;
- break;
- default:
- return (EINVAL);
- }
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_getNparam(struct smb_rap *rap, long *value)
-{
- char *p = rap->r_nparam;
- char ptype = *p;
- int error, plen;
- uint16_t *te;
-
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error)
- return (error);
- switch (ptype) {
- case 'h':
- /* LINTED */
- te = (uint16_t *)rap->r_npbuf;
- *value = letohs(*te);
- break;
- default:
- return (EINVAL);
- }
- rap->r_npbuf += plen;
- rap->r_nparam = p;
- return (0);
-}
-
-int
-smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
-{
- uint16_t *rp, conv, *tmp;
- uint32_t *p32;
- char *dp, *p = rap->r_nparam;
- char ptype;
- int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
-
- rdatacnt = rap->r_rcvbuflen;
- rparamcnt = rap->r_plen;
- error = smb_t2_request(ctx->ct_dev_fd,
- 0, NULL, "\\PIPE\\LANMAN",
- rap->r_plen, rap->r_pbuf, /* int tparamcnt,void *tparam */
- 0, NULL, /* int tdatacnt, void *tdata */
- &rparamcnt, rap->r_pbuf, /* rparamcnt, void *rparam */
- &rdatacnt, rap->r_rcvbuf, /* int *rdatacnt, void *rdata */
- &buffer_oflow);
- if (error)
- return (error);
-
- /* LINTED */
- rp = (uint16_t *)rap->r_pbuf;
-
- /*
- * Note: First is a "LanMan API" error code.
- * See: usr/src/uts/common/smbsrv/lmerr.h
- */
- if (rparamcnt < 2)
- return (EBADRPC);
- rap->r_result = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- if (rap->r_result != 0) {
- /*
- * Could also return zero and let the caller
- * come get r_result via smb_rap_error(),
- * but in case they dont...
- */
- return (rap->r_result | SMB_RAP_ERROR);
- }
-
- if (rparamcnt < 2)
- return (EBADRPC);
- conv = letohs(*rp);
- rp++; rparamcnt -= 2;
-
- rap->r_npbuf = (char *)rp;
- rap->r_entries = entries = 0;
- /* Save the returned data length */
- rap->r_rcvbuflen = rdatacnt;
- done = 0;
-
- while (!done && *p) {
- ptype = *p;
- switch (ptype) {
- case 'e':
- if (rparamcnt < 2)
- return (EBADRPC);
- /* LINTED */
- tmp = (uint16_t *)rap->r_npbuf;
- rap->r_entries = entries = letohs(*tmp);
- rap->r_npbuf += 2;
- rparamcnt -= 2;
- p++;
- break;
- default:
- done = 1;
- }
-#if 0 /* commented out in Darwin. Why? */
- error = smb_rap_parserpparam(p, &p, &plen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply parameter mismatch %s"), 0, p);
- return (EBADRPC);
- }
-#endif
- }
- rap->r_nparam = p;
- /*
- * In general, unpacking entries we may need to relocate
- * entries for proper aligning. For now use them as is.
- */
- dp = rap->r_rcvbuf;
- while (entries--) {
- p = rap->r_sdata;
- while (*p) {
- ptype = *p;
- error = smb_rap_parserpdata(p, &p, &dlen);
- if (error) {
- smb_error(dgettext(TEXT_DOMAIN,
- "reply data mismatch %s"), 0, p);
- return (EBADRPC);
- }
- if (rdatacnt < dlen)
- return (EBADRPC);
- switch (ptype) {
- case 'z':
- /* LINTED */
- p32 = (uint32_t *)dp;
- *p32 = (letohl(*p32) & 0xffff) - conv;
- break;
- }
- dp += dlen;
- rdatacnt -= dlen;
- }
- }
- return (error);
-}
-
-int
-smb_rap_error(struct smb_rap *rap, int error)
-{
- if (error)
- return (error);
- if (rap->r_result == 0)
- return (0);
- return (rap->r_result | SMB_RAP_ERROR);
-}
diff --git a/usr/src/lib/libsmbfs/smb/rc_scf.c b/usr/src/lib/libsmbfs/smb/rc_scf.c
new file mode 100644
index 0000000000..477982c0c8
--- /dev/null
+++ b/usr/src/lib/libsmbfs/smb/rc_scf.c
@@ -0,0 +1,231 @@
+/*
+ * 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 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Support functions for getting things libsmbfs needs
+ * from the SMF configuration (using libscf).
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libscf.h>
+
+#include <cflib.h>
+#include "rcfile_priv.h"
+
+#define IDMAP_SERVICE_FMRI "svc:/system/idmap"
+#define IDMAP_PG_NAME "config"
+#define MACHINE_UUID "machine_uuid"
+
+#define SMBC_DEFAULT_INSTANCE_FMRI "svc:/network/smb/client:default"
+
+scf_handle_t *_scf_handle_create_and_bind(scf_version_t ver);
+
+/*
+ * Get the "machine_uuid" from idmap, as a string (allocated)
+ */
+char *
+cf_get_client_uuid(void)
+{
+ char val_buf[64];
+ char *ret = NULL;
+
+ scf_handle_t *h = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *val = NULL;
+
+ if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
+ goto out;
+
+ if ((svc = scf_service_create(h)) == NULL ||
+ (pg = scf_pg_create(h)) == NULL ||
+ (prop = scf_property_create(h)) == NULL ||
+ (val = scf_value_create(h)) == NULL)
+ goto out;
+
+ if (scf_handle_decode_fmri(h, IDMAP_SERVICE_FMRI,
+ NULL, svc, NULL, NULL, NULL, 0) == -1)
+ goto out;
+
+
+ if (scf_service_get_pg(svc, IDMAP_PG_NAME, pg) != 0)
+ goto out;
+ if (scf_pg_get_property(pg, MACHINE_UUID, prop) != 0)
+ goto out;
+ if (scf_property_get_value(prop, val) != 0)
+ goto out;
+ if (scf_value_get_as_string(val, val_buf, sizeof (val_buf)) < 0)
+ goto out;
+
+ ret = strdup(val_buf);
+
+out:
+ scf_value_destroy(val);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_service_destroy(svc);
+
+ if (h != NULL)
+ scf_handle_destroy(h);
+
+ return (ret);
+}
+
+/*
+ * Get the output of "sharectl get smbfs" into a file, without an
+ * actual fork/exec of sharectl.
+ *
+ * Each section of the smbfs settings are represented as an SMF
+ * property group with an "S-" prefix and a UUID, and the section
+ * name itself a property which can have a more flexible name than
+ * a property group name can have.
+ */
+int
+rc_scf_get_sharectl(FILE *fp)
+{
+ char sect_name[256];
+ char prop_name[256];
+ char val_buf[1024];
+
+ scf_handle_t *h = NULL;
+ scf_service_t *svc = NULL;
+ scf_instance_t *inst = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *val = NULL;
+ scf_iter_t *pgiter = NULL;
+ scf_iter_t *propiter = NULL;
+ scf_iter_t *valiter = NULL;
+ int ret = -1;
+
+ if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
+ goto out;
+
+ if ((svc = scf_service_create(h)) == NULL ||
+ (inst = scf_instance_create(h)) == NULL ||
+ (pgiter = scf_iter_create(h)) == NULL ||
+ (propiter = scf_iter_create(h)) == NULL ||
+ (valiter = scf_iter_create(h)) == NULL ||
+ (pg = scf_pg_create(h)) == NULL ||
+ (prop = scf_property_create(h)) == NULL ||
+ (val = scf_value_create(h)) == NULL)
+ goto out;
+
+ if (scf_handle_decode_fmri(h, SMBC_DEFAULT_INSTANCE_FMRI,
+ NULL, svc, inst, NULL, NULL, 0) == -1)
+ goto out;
+
+ if (scf_iter_instance_pgs_composed(pgiter, inst, NULL) == -1)
+ goto out;
+ while ((ret = scf_iter_next_pg(pgiter, pg)) == 1) {
+ /*
+ * Using prop_name array for pg name temporarily.
+ * Skip any property groups names other than "S-*".
+ */
+ if (scf_pg_get_name(pg, prop_name, sizeof (prop_name)) < 0)
+ continue;
+ if (strncmp(prop_name, "S-", 2) != 0)
+ continue;
+
+ /*
+ * Get the "section" name, which is a property of
+ * this property group.
+ */
+ if (scf_pg_get_property(pg, "section", prop) != 0)
+ continue;
+ if (scf_property_get_value(prop, val) != 0)
+ continue;
+ if (scf_value_get_as_string(val, sect_name,
+ sizeof (sect_name)) < 0)
+ continue;
+
+ /*
+ * Have an S-* property group with a "section" name.
+ * Print the section start.
+ */
+ fprintf(fp, "[%s]\n", sect_name);
+
+ /*
+ * Now print the remaining properties in this PG,
+ * but skip the special "section" (name) prop.
+ */
+ if (scf_iter_pg_properties(propiter, pg) == -1)
+ goto out;
+ while ((ret = scf_iter_next_property(propiter, prop)) == 1) {
+
+ if (scf_property_get_name(prop, prop_name,
+ sizeof (prop_name)) < 0)
+ continue;
+
+ /* Skip the "section" prop. now */
+ if (strcmp(prop_name, "section") == 0)
+ continue;
+
+ if (scf_property_get_value(prop, val) != 0)
+ continue;
+
+ if (scf_value_get_as_string(val, val_buf,
+ sizeof (val_buf)) < 0)
+ continue;
+
+ fprintf(fp, "%s=%s\n", prop_name, val_buf);
+ }
+ }
+ ret = 0;
+
+out:
+ fflush(fp);
+
+ scf_value_destroy(val);
+ scf_property_destroy(prop);
+ scf_pg_destroy(pg);
+ scf_iter_destroy(valiter);
+ scf_iter_destroy(propiter);
+ scf_iter_destroy(pgiter);
+ scf_instance_destroy(inst);
+ scf_service_destroy(svc);
+
+ if (h != NULL)
+ scf_handle_destroy(h);
+
+ return (ret);
+}
+
+/*
+ * Simple test wrapper. Compile with:
+ * cc -o rc_scf_test -I.. -DTEST_MAIN rc_scf.c -lscf
+ */
+#ifdef TEST_MAIN
+int
+main(int argc, char **arv)
+{
+ char *s;
+ int rc;
+
+ rc = rc_scf_get_sharectl(stdout);
+ printf("# rc=%d\n", rc);
+ return (0);
+}
+#endif /* TEST_MAIN */
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c
index 22ca0fc420..d7ee2d15af 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 2018 Nexenta Systems, Inc. All rights reserved.
+ */
#include <fcntl.h>
#include <sys/types.h>
@@ -57,7 +60,6 @@
#define SMB_CFG_FILE "/etc/nsmb.conf"
#define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf"
#endif
-#define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs"
extern int smb_debug;
@@ -147,37 +149,77 @@ rc_merge(const char *filename, struct rcfile **rcfile)
}
/*
- * Like rc_open, but does popen of command:
- * sharectl get smbfs
+ * Like rc_open, but creates a temporary file and
+ * reads the sharectl settings into it.
+ * The file is deleted when we close it.
*/
static int
-rc_popen_cmd(const char *command, struct rcfile **rcfile)
+rc_open_sharectl(struct rcfile **rcfile)
{
- struct rcfile *rcp;
- FILE *f;
+ static char template[24] = "/tmp/smbfsXXXXXX";
+ struct rcfile *rcp = NULL;
+ FILE *fp = NULL;
+ int err;
+ int fd = -1;
assert(MUTEX_HELD(&rcfile_mutex));
- f = popen(command, "r");
- if (f == NULL)
- return (errno);
- insecure_nsmbrc = 0;
+ fd = mkstemp(template);
+ if (fd < 0) {
+ err = errno;
+ goto errout;
+ }
+
+ fp = fdopen(fd, "w+");
+ if (fp == NULL) {
+ err = errno;
+ close(fd);
+ goto errout;
+ }
+ fd = -1; /* The fp owns this fd now. */
+
+ /*
+ * Get smbfs sharectl settings into the file.
+ */
+ if ((err = rc_scf_get_sharectl(fp)) != 0)
+ goto errout;
rcp = malloc(sizeof (struct rcfile));
if (rcp == NULL) {
- fclose(f);
- return (ENOMEM);
+ err = ENOMEM;
+ goto errout;
}
bzero(rcp, sizeof (struct rcfile));
- rcp->rf_name = strdup(command);
- rcp->rf_f = f;
+
+ rcp->rf_name = strdup(template);
+ if (rcp->rf_name == NULL) {
+ err = ENOMEM;
+ goto errout;
+ }
+ rcp->rf_f = fp;
+ rcp->rf_flags = RCFILE_DELETE_ON_CLOSE;
+
SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+ insecure_nsmbrc = 0;
rc_parse(rcp);
*rcfile = rcp;
/* fclose(f) in rc_close */
return (0);
+
+errout:
+ if (rcp != NULL)
+ free(rcp);
+ if (fp != NULL) {
+ fclose(fp);
+ fd = -1;
+ }
+ if (fd != -1)
+ close(fd);
+
+ return (err);
}
+
static int
rc_close(struct rcfile *rcp)
{
@@ -186,6 +228,9 @@ rc_close(struct rcfile *rcp)
mutex_lock(&rcfile_mutex);
fclose(rcp->rf_f);
+ if (rcp->rf_flags & RCFILE_DELETE_ON_CLOSE)
+ (void) unlink(rcp->rf_name);
+
for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
n = p;
p = SLIST_NEXT(p, rs_next);
@@ -343,11 +388,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 +529,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);
@@ -661,8 +705,8 @@ smb_open_rcfile(char *home)
fn = SMB_CFG_FILE;
error = rc_open(fn, &smb_rc);
#else
- fn = SMBFS_SHARECTL_CMD;
- error = rc_popen_cmd(fn, &smb_rc);
+ fn = "(sharectl get smbfs)";
+ error = rc_open_sharectl(&smb_rc);
#endif
if (error != 0 && error != ENOENT) {
/* Error from fopen. strerror is OK. */
diff --git a/usr/src/lib/libsmbfs/smb/rcfile_priv.h b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
index ef9e31d7fc..b239c77a67 100644
--- a/usr/src/lib/libsmbfs/smb/rcfile_priv.h
+++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h
@@ -30,9 +30,26 @@
* SUCH DAMAGE.
*/
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _RCFILE_PRIV_H
+#define _RCFILE_PRIV_H
+
+/*
+ * Private RC file support.
+ */
+
+#include <sys/queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct rckey {
SLIST_ENTRY(rckey) rk_next;
- char *rk_name;
+ char *rk_name;
char *rk_value;
};
@@ -52,3 +69,12 @@ struct rcfile {
#define RCFILE_HOME_NSMBRC 1
#define RCFILE_IS_INSECURE 2
+#define RCFILE_DELETE_ON_CLOSE 4
+
+int rc_scf_get_sharectl(FILE *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RCFILE_PRIV_H */
diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c
deleted file mode 100644
index c4e929eff9..0000000000
--- a/usr/src/lib/libsmbfs/smb/rq.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2000, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <libintl.h>
-
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-#include "private.h"
-
-#define MIN_REPLY_SIZE 4096
-
-static uint32_t smb_map_doserr(uint8_t, uint16_t);
-
-/*
- * Create and initialize a request structure, for either an
- * "internal" request (one that does not use the driver) or
- * a regular "driver" request, that uses driver ioctls.
- *
- * The two kinds are built a little differently:
- * Driver requests are composed starting with the
- * first word of the "variable word vector" section.
- * The driver prepends the SMB header and word count.
- * The driver also needs an output buffer to receive
- * the response, filled in via copyout in the ioctl.
- *
- * Internal requests are composed entirely in this library.
- * Space for the SMB header is reserved here, and later
- * filled in by smb_rq_internal before the send/receive.
- */
-int
-smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
-{
- struct smb_rq *rqp;
-
- rqp = malloc(sizeof (*rqp));
- if (rqp == NULL)
- goto errout;
- bzero(rqp, sizeof (*rqp));
- rqp->rq_cmd = cmd;
- rqp->rq_ctx = ctx;
-
- /*
- * Setup the request buffer.
- * Do the reply buffer later.
- */
- if (mb_init(&rqp->rq_rq))
- goto errout;
-
- /* Space for the SMB header. (filled in later) */
- mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM);
-
- /*
- * Copy the ctx flags here, so the caller can
- * update the req flags before the OTW call.
- */
- rqp->rq_hflags = ctx->ct_hflags;
- rqp->rq_hflags2 = ctx->ct_hflags2;
-
- *rqpp = rqp;
- return (0);
-
-errout:
- if (rqp) {
- smb_rq_done(rqp);
- free(rqp);
- }
- return (ENOMEM);
-}
-
-void
-smb_rq_done(struct smb_rq *rqp)
-{
- mb_done(&rqp->rq_rp);
- mb_done(&rqp->rq_rq);
- free(rqp);
-}
-
-/*
- * Reserve space for the word count, which is filled in later by
- * smb_rq_wend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the word count happens to be 8-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_wstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 1, &rqp->rq_wcntp);
- rqp->rq_wcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the word count, in the space reserved by
- * smb_rq_wstart().
- */
-void
-smb_rq_wend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int wcnt;
-
- if (rqp->rq_wcntp == NULL) {
- DPRINT("no wcount ptr\n");
- return;
- }
- wcnt = mbp->mb_count - rqp->rq_wcbase;
- if (wcnt > 0x1ff)
- DPRINT("word count too large (%d)\n", wcnt);
- if (wcnt & 1)
- DPRINT("odd word count\n");
- wcnt >>= 1;
-
- /*
- * Fill in the word count (8-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- */
- *rqp->rq_wcntp = (char)wcnt;
-}
-
-/*
- * Reserve space for the byte count, which is filled in later by
- * smb_rq_bend(). Also initialize the counter that it uses
- * to figure out what value to fill in.
- *
- * Note that the byte count happens to be 16-bits,
- * which can lead to confusion.
- */
-void
-smb_rq_bstart(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
-
- (void) mb_fit(mbp, 2, &rqp->rq_bcntp);
- rqp->rq_bcbase = mbp->mb_count;
-}
-
-/*
- * Fill in the byte count, in the space reserved by
- * smb_rq_bstart().
- */
-void
-smb_rq_bend(struct smb_rq *rqp)
-{
- struct mbdata *mbp = &rqp->rq_rq;
- int bcnt;
-
- if (rqp->rq_bcntp == NULL) {
- DPRINT("no bcount ptr\n");
- return;
- }
- bcnt = mbp->mb_count - rqp->rq_bcbase;
- if (bcnt > 0xffff)
- DPRINT("byte count too large (%d)\n", bcnt);
- /*
- * Fill in the byte count (16-bits).
- * Also store it in the rq, in case
- * we're using the ioctl path.
- *
- * The pointer is char * type due to
- * typical off-by-one alignment.
- */
- rqp->rq_bcntp[0] = bcnt & 0xFF;
- rqp->rq_bcntp[1] = (bcnt >> 8);
-}
-
-int
-smb_rq_simple(struct smb_rq *rqp)
-{
- struct smbioc_rq krq;
- struct mbdata *mbp;
- mbuf_t *m;
- char *data;
- uint32_t len;
- size_t rpbufsz;
- int error;
-
- bzero(&krq, sizeof (krq));
- krq.ioc_cmd = rqp->rq_cmd;
-
- /*
- * Make the SMB request body contiguous,
- * and fill in the ioctl request.
- */
- mbp = smb_rq_getrequest(rqp);
- error = m_lineup(mbp->mb_top, &mbp->mb_top);
- if (error)
- return (error);
-
- data = mtod(mbp->mb_top, char *);
- len = m_totlen(mbp->mb_top);
-
- /*
- * _rq_init left space for the SMB header,
- * which makes mb_count the offset from
- * the beginning of the header (useful).
- * However, in this code path the driver
- * prepends the header, so we skip it.
- */
- krq.ioc_tbufsz = len - SMB_HDRLEN;
- krq.ioc_tbuf = data + SMB_HDRLEN;
-
- /*
- * Setup a buffer to hold the reply,
- * at least MIN_REPLY_SIZE, or larger
- * if the caller increased rq_rpbufsz.
- */
- mbp = smb_rq_getreply(rqp);
- rpbufsz = rqp->rq_rpbufsz;
- if (rpbufsz < MIN_REPLY_SIZE)
- rpbufsz = MIN_REPLY_SIZE;
- if ((error = m_get(rpbufsz, &m)) != 0)
- return (error);
- mb_initm(mbp, m);
- krq.ioc_rbufsz = rpbufsz;
- krq.ioc_rbuf = mtod(m, char *);
-
- /*
- * Call the driver
- */
- if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
- return (errno);
-
- /*
- * Initialize returned mbdata.
- * SMB header already parsed.
- */
- m->m_len = krq.ioc_rbufsz;
-
- return (0);
-}
-
-
-int
-smb_t2_request(int dev_fd, int setupcount, uint16_t *setup,
- const char *name,
- int tparamcnt, void *tparam,
- int tdatacnt, void *tdata,
- int *rparamcnt, void *rparam,
- int *rdatacnt, void *rdata,
- int *buffer_oflow)
-{
- smbioc_t2rq_t *krq;
- int i;
-
- krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
- bzero(krq, sizeof (*krq));
-
- if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
- /* Bogus setup count, or too many setup words */
- return (EINVAL);
- }
- for (i = 0; i < setupcount; i++)
- krq->ioc_setup[i] = setup[i];
- krq->ioc_setupcnt = setupcount;
- strcpy(krq->ioc_name, name);
- krq->ioc_tparamcnt = tparamcnt;
- krq->ioc_tparam = tparam;
- krq->ioc_tdatacnt = tdatacnt;
- krq->ioc_tdata = tdata;
-
- krq->ioc_rparamcnt = *rparamcnt;
- krq->ioc_rdatacnt = *rdatacnt;
- krq->ioc_rparam = rparam;
- krq->ioc_rdata = rdata;
-
- if (ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) {
- return (errno);
- }
-
- *rparamcnt = krq->ioc_rparamcnt;
- *rdatacnt = krq->ioc_rdatacnt;
- *buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
- (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
- free(krq);
-
- return (0);
-}
-
-
-/*
- * Do an over-the-wire call without using the nsmb driver.
- * This is all "internal" to this library, and used only
- * for connection setup (negotiate protocol, etc.)
- */
-int
-smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
-{
- static const uint8_t ffsmb[4] = SMB_SIGNATURE;
- struct smb_iods *is = &ctx->ct_iods;
- uint32_t sigbuf[2];
- struct mbdata mbtmp, *mbp;
- int err, save_mlen;
- uint8_t ctmp;
-
- rqp->rq_uid = is->is_smbuid;
- rqp->rq_tid = SMB_TID_UNKNOWN;
- rqp->rq_mid = is->is_next_mid++;
-
- /*
- * Fill in the NBT and SMB headers
- * Using mbtmp so we can rewind without
- * affecting the passed request mbdata.
- */
- bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
- mbp = &mbtmp;
- mbp->mb_cur = mbp->mb_top;
- mbp->mb_pos = mbp->mb_cur->m_data;
- mbp->mb_count = 0;
- /* Have to save and restore m_len */
- save_mlen = mbp->mb_cur->m_len;
- mbp->mb_cur->m_len = 0;
-
- /*
- * rewind done; fill it in
- */
- mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM);
- mb_put_uint8(mbp, rqp->rq_cmd);
- mb_put_uint32le(mbp, 0); /* status */
- mb_put_uint8(mbp, rqp->rq_hflags);
- mb_put_uint16le(mbp, rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- mb_put_mem(mbp, NULL, 12, MB_MZERO);
- mb_put_uint16le(mbp, rqp->rq_tid);
- mb_put_uint16le(mbp, 0); /* pid_lo */
- mb_put_uint16le(mbp, rqp->rq_uid);
- mb_put_uint16le(mbp, rqp->rq_mid);
-
- /* Restore original m_len */
- mbp->mb_cur->m_len = save_mlen;
-
- /*
- * Sign the message, if flags2 indicates.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- smb_rq_sign(rqp);
- }
-
- /*
- * Send it, wait for the reply.
- */
- if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
- return (err);
-
- if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
- return (err);
-
- /*
- * Should have an SMB header, at least.
- */
- mbp = &rqp->rq_rp;
- if (mbp->mb_cur->m_len < SMB_HDRLEN) {
- DPRINT("len < 32");
- return (EBADRPC);
- }
-
- /*
- * If the request was signed, validate the
- * signature on the response.
- */
- if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- err = smb_rq_verify(rqp);
- if (err) {
- DPRINT("bad signature");
- return (err);
- }
- }
-
- /*
- * Decode the SMB header.
- */
- md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
- if (0 != bcmp(sigbuf, ffsmb, 4)) {
- DPRINT("not SMB");
- return (EBADRPC);
- }
- md_get_uint8(mbp, &ctmp); /* SMB cmd */
- md_get_uint32le(mbp, &rqp->rq_status);
- md_get_uint8(mbp, &rqp->rq_hflags);
- md_get_uint16le(mbp, &rqp->rq_hflags2);
- /* pid_hi(2), signature(8), reserved(2) */
- md_get_mem(mbp, NULL, 12, MB_MSYSTEM);
- md_get_uint16le(mbp, &rqp->rq_tid);
- md_get_uint16le(mbp, NULL); /* pid_lo */
- md_get_uint16le(mbp, &rqp->rq_uid);
- md_get_uint16le(mbp, &rqp->rq_mid);
-
- /*
- * Figure out the status return.
- * Caller looks at rq_status.
- */
- if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
- uint16_t serr;
- uint8_t class;
-
- class = rqp->rq_status & 0xff;
- serr = rqp->rq_status >> 16;
- rqp->rq_status = smb_map_doserr(class, serr);
- }
-
- return (0);
-}
-
-/*
- * Map old DOS errors (etc.) to NT status codes.
- * We probably don't need this anymore, since
- * the oldest server we talk to is NT. But if
- * later find we do need this, add support here
- * for the DOS errors we care about.
- */
-static uint32_t
-smb_map_doserr(uint8_t class, uint16_t serr)
-{
- if (class == 0 && serr == 0)
- return (0);
-
- DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
- return (NT_STATUS_UNSUCCESSFUL);
-}
diff --git a/usr/src/lib/libsmbfs/smb/signing.c b/usr/src/lib/libsmbfs/smb/signing.c
deleted file mode 100644
index 0e9c826bbd..0000000000
--- a/usr/src/lib/libsmbfs/smb/signing.c
+++ /dev/null
@@ -1,263 +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.
- */
-
-/*
- * Signing support, using libmd
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-
-#include <sys/types.h>
-#include <sys/md5.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/smb.h>
-#include <netsmb/smb_lib.h>
-
-#include "private.h"
-
-#define SMBSIGOFF 14 /* SMB signature offset */
-#define SMBSIGLEN 8 /* SMB signature length */
-
-/*
- * Set this to a small number to debug sequence numbers
- * that seem to get out of step.
- */
-#ifdef DEBUG
-int nsmb_signing_fudge = 4;
-#endif
-
-/*
- * Compute MD5 digest of packet data, using the stored MAC key.
- *
- * See similar code in the driver:
- * uts/common/fs/smbclnt/netsmb/smb_signing.c
- * and on the server side:
- * uts/common/fs/smbsrv/smb_signing.c
- */
-static int
-smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m,
- uint32_t seqno, uchar_t *signature)
-{
- MD5_CTX md5;
- uchar_t digest[MD5_DIGEST_LENGTH];
-
- /*
- * This union is a little bit of trickery to:
- * (1) get the sequence number int aligned, and
- * (2) reduce the number of digest calls, at the
- * cost of a copying 32 bytes instead of 8.
- * Both sides of this union are 2+32 bytes.
- */
- union {
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t raw[SMB_HDRLEN]; /* header length (32) */
- } r;
- struct {
- uint8_t skip[2]; /* not used - just alignment */
- uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
- uint32_t sig[2]; /* MAC signature, aligned! */
- uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
- } s;
- } smbhdr;
-
- if (m->m_len < SMB_HDRLEN)
- return (EIO);
- if (ctx->ct_mackey == NULL)
- return (EINVAL);
-
- /*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
- */
- bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN);
- smbhdr.s.sig[0] = htolel(seqno);
- smbhdr.s.sig[1] = 0;
-
- /*
- * Compute the MAC: MD5(concat(Key, message))
- */
- MD5Init(&md5);
-
- /* Digest the MAC Key */
- MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen);
-
- /* Digest the (copied) SMB header */
- MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN);
-
- /* Digest the rest of the first mbuf */
- if (m->m_len > SMB_HDRLEN) {
- MD5Update(&md5, m->m_data + SMB_HDRLEN,
- m->m_len - SMB_HDRLEN);
- }
- m = m->m_next;
-
- /* Digest rest of the SMB message. */
- while (m) {
- MD5Update(&md5, m->m_data, m->m_len);
- m = m->m_next;
- }
-
- /* Final */
- MD5Final(digest, &md5);
-
- /*
- * Finally, store the signature.
- * (first 8 bytes of the digest)
- */
- if (signature)
- bcopy(digest, signature, SMBSIGLEN);
-
- return (0);
-}
-
-/*
- * Sign a request with HMAC-MD5.
- */
-void
-smb_rq_sign(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rq.mb_top;
- uint8_t *sigloc;
- int err;
-
- /*
- * Our mblk allocation ensures this,
- * but just in case...
- */
- if (m->m_len < SMB_HDRLEN)
- return;
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
-
- if (ctx->ct_mackey == NULL) {
- /*
- * Signing is required, but we have no key yet
- * fill in with the magic fake signing value.
- * This happens with SPNEGO, NTLMSSP, ...
- */
- bcopy("BSRSPLY", sigloc, 8);
- return;
- }
-
- /*
- * This will compute the MAC and store it
- * directly into the message at sigloc.
- */
- rqp->rq_seqno = ctx->ct_mac_seqno;
- ctx->ct_mac_seqno += 2;
- err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- bzero(sigloc, SMBSIGLEN);
- }
-}
-
-/*
- * Verify reply signature.
- */
-int
-smb_rq_verify(struct smb_rq *rqp)
-{
- struct smb_ctx *ctx = rqp->rq_ctx;
- mbuf_t *m = rqp->rq_rp.mb_top;
- uint8_t sigbuf[SMBSIGLEN];
- uint8_t *sigloc;
- uint32_t rseqno;
- int err, fudge;
-
- /*
- * Note ct_mackey and ct_mackeylen gets initialized by
- * smb_smb_ssnsetup. It's normal to have a null MAC key
- * during extended security session setup.
- */
- if (ctx->ct_mackey == NULL)
- return (0);
-
- /*
- * Let caller deal with empty reply or short messages by
- * returning zero. Caller will fail later, in parsing.
- */
- if (m == NULL) {
- DPRINT("empty reply");
- return (0);
- }
- if (m->m_len < SMB_HDRLEN) {
- DPRINT("short reply");
- return (0);
- }
-
- sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
- rseqno = rqp->rq_seqno + 1;
-
- DPRINT("rq_rseqno = 0x%x", rseqno);
-
- err = smb_compute_MAC(ctx, m, rseqno, sigbuf);
- if (err) {
- DPRINT("compute MAC, err %d", err);
- /*
- * If we can't compute a MAC, then there's
- * no point trying other seqno values.
- */
- return (EBADRPC);
- }
-
- /*
- * Compare the computed signature with the
- * one found in the message (at sigloc)
- */
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- return (0);
-
- DPRINT("BAD signature, MID=0x%x", rqp->rq_mid);
-
-#ifdef DEBUG
- /*
- * For diag purposes, we check whether the client/server idea
- * of the sequence # has gotten a bit out of sync.
- */
- for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
- (void) smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
- break;
- (void) smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf);
- if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
- fudge = -fudge;
- break;
- }
- }
- if (fudge <= nsmb_signing_fudge) {
- DPRINT("rseqno=%d, but %d would have worked",
- rseqno, rseqno + fudge);
- }
-#endif
- return (EBADRPC);
-}
diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c
deleted file mode 100644
index da7640241c..0000000000
--- a/usr/src/lib/libsmbfs/smb/ssnsetup.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2000-2001 Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- */
-
-/*
- * SMB Session Setup, and related.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-#include <netdb.h>
-#include <libintl.h>
-#include <xti.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/byteorder.h>
-#include <sys/socket.h>
-#include <sys/fcntl.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <netsmb/mchain.h>
-#include <netsmb/netbios.h>
-#include <netsmb/smb_dev.h>
-#include <netsmb/smb.h>
-
-#include <netsmb/smb_lib.h>
-#include <netsmb/nb_lib.h>
-
-#include "private.h"
-#include "charsets.h"
-#include "ntlm.h"
-#include "smb_crypt.h"
-
-
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp);
-
-/*
- * Session Setup: NULL session (anonymous)
- */
-int
-smb_ssnsetup_null(struct smb_ctx *ctx)
-{
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- return (err);
-}
-
-
-/*
- * SMB Session Setup, using NTLMv1 (and maybe LMv1)
- */
-int
-smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
-
- /* Put the LM,NTLM responses (as mbdata). */
- err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-/*
- * SMB Session Setup, using NTLMv2 (and LMv2)
- */
-int
-smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
-{
- struct mbdata lm_mbc, nt_mbc, ti_mbc;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
- /* Should not get here with... */
- err = EINVAL;
- goto out;
- }
-
- /* Make mb_done calls at out safe. */
- bzero(&lm_mbc, sizeof (lm_mbc));
- bzero(&nt_mbc, sizeof (nt_mbc));
- bzero(&ti_mbc, sizeof (ti_mbc));
-
- /* Build the NTLMv2 "target info" blob (as mbdata) */
- err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
- if (err)
- goto out;
-
- /* Put the LMv2, NTLMv2 responses (as mbdata). */
- err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
- if (err)
- goto out;
-
- if ((ctx->ct_vcflags & SMBV_WILL_SIGN) != 0 &&
- (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
- err = ntlm_build_mac_key(ctx, &nt_mbc);
- if (err)
- goto out;
- /* OK, start signing! */
- ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
- }
-
- err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
- if (err)
- goto out;
-
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
- if (ntstatus != 0)
- err = EAUTH;
-
-out:
- mb_done(&ti_mbc);
- mb_done(&lm_mbc);
- mb_done(&nt_mbc);
-
- return (err);
-}
-
-int
-smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
-{
- struct mbdata send_mb, recv_mb;
- int err;
- uint32_t ntstatus;
- uint16_t action = 0;
-
- err = ssp_ctx_create_client(ctx, hint_mb);
- if (err)
- goto out;
-
- bzero(&send_mb, sizeof (send_mb));
- bzero(&recv_mb, sizeof (recv_mb));
-
- /* NULL input indicates first call. */
- err = ssp_ctx_next_token(ctx, NULL, &send_mb);
- if (err)
- goto out;
-
- for (;;) {
- err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
- &ntstatus, &action);
- if (err)
- goto out;
- if (ntstatus == 0)
- break; /* normal loop termination */
- if (ntstatus != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- err = EAUTH;
- goto out;
- }
-
- /* middle calls get both in, out */
- err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
- if (err)
- goto out;
- }
- DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
-
- /* NULL output indicates last call. */
- (void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
-
-out:
- ssp_ctx_destroy(ctx);
-
- return (err);
-}
-
-/*
- * Session Setup function used for all the forms we support.
- * To allow this sharing, the crypto stuff is computed by
- * callers and passed in as mbdata chains. Also, the args
- * have different meanings for extended security vs. old.
- * Some may be used as either IN or OUT parameters.
- *
- * For NTLM (v1, v2), all parameters are inputs
- * mbc1: [in] LM password hash
- * mbc2: [in] NT password hash
- * For Extended security (spnego)
- * mbc1: [in] outgoing blob data
- * mbc2: [out] received blob data
- * For both forms, these are optional:
- * statusp: [out] NT status
- * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
- */
-static int
-smb__ssnsetup(struct smb_ctx *ctx,
- struct mbdata *mbc1, struct mbdata *mbc2,
- uint32_t *statusp, uint16_t *actionp)
-{
- static const char NativeOS[] = "Solaris";
- static const char LanMan[] = "NETSMB";
- struct smb_sopt *sv = &ctx->ct_sopt;
- struct smb_iods *is = &ctx->ct_iods;
- struct smb_rq *rqp = NULL;
- struct mbdata *mbp;
- struct mbuf *m;
- int err, uc;
- uint32_t caps;
- uint16_t bc, len1, len2, sblen;
- uint8_t wc;
-
- caps = ctx->ct_clnt_caps;
- uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
-
- err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
- if (err)
- goto out;
-
- /*
- * Build the SMB request.
- */
- mbp = &rqp->rq_rq;
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
- mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
- mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
- mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
- mb_put_uint16le(mbp, 1); /* 4: VcNumber */
- mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
-
- if (caps & SMB_CAP_EXT_SECURITY) {
- len1 = mbc1 ? mbc1->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 7: Sec. Blob Len */
- mb_put_uint32le(mbp, 0); /* 8,9: reserved */
- mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
- smb_rq_wend(rqp); /* 12: Byte Count */
- smb_rq_bstart(rqp);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */
- mbc1->mb_top = NULL; /* consumed */
- }
- /* mbc2 is required below */
- if (mbc2 == NULL) {
- err = EINVAL;
- goto out;
- }
- } else {
- len1 = mbc1 ? mbc1->mb_count : 0;
- len2 = mbc2 ? mbc2->mb_count : 0;
- mb_put_uint16le(mbp, len1); /* 7: LM pass. len */
- mb_put_uint16le(mbp, len2); /* 8: NT pass. len */
- mb_put_uint32le(mbp, 0); /* 9,10: reserved */
- mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */
- smb_rq_wend(rqp); /* 13: Byte Count */
- smb_rq_bstart(rqp);
- if (mbc1 && mbc1->mb_top) {
- mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */
- mbc1->mb_top = NULL; /* consumed */
- }
- if (mbc2 && mbc2->mb_top) {
- mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */
- mbc2->mb_top = NULL; /* consumed */
- }
- mb_put_string(mbp, ctx->ct_user, uc);
- mb_put_string(mbp, ctx->ct_domain, uc);
- }
- mb_put_string(mbp, NativeOS, uc);
- mb_put_string(mbp, LanMan, uc);
- smb_rq_bend(rqp);
-
- err = smb_rq_internal(ctx, rqp);
- if (err)
- goto out;
-
- if (statusp)
- *statusp = rqp->rq_status;
-
- /*
- * If we have a real error, the response probably has
- * no more data, so don't try to parse any more.
- * Note: err=0, means rq_status is valid.
- */
- if (rqp->rq_status != 0 &&
- rqp->rq_status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
- goto out;
- }
-
- /*
- * Parse the reply
- */
- uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
- is->is_smbuid = rqp->rq_uid;
- mbp = &rqp->rq_rp;
-
- err = md_get_uint8(mbp, &wc);
- if (err)
- goto out;
-
- err = EBADRPC; /* for any problems in this section */
- if (caps & SMB_CAP_EXT_SECURITY) {
- if (wc != 4)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- md_get_uint16le(mbp, &sblen); /* sec. blob len */
- md_get_uint16le(mbp, &bc); /* byte count */
- /*
- * Get the security blob, after
- * sanity-checking the length.
- */
- if (sblen == 0 || bc < sblen)
- goto out;
- err = md_get_mbuf(mbp, sblen, &m);
- if (err)
- goto out;
- mb_initm(mbc2, m);
- mbc2->mb_count = sblen;
- } else {
- if (wc != 3)
- goto out;
- md_get_uint16le(mbp, NULL); /* secondary cmd */
- md_get_uint16le(mbp, NULL); /* andxoffset */
- md_get_uint16le(mbp, actionp); /* action */
- err = md_get_uint16le(mbp, &bc); /* byte count */
- if (err)
- goto out;
- }
-
- /*
- * Native OS, LANMGR, & Domain follow here.
- * Parse these strings and store for later.
- * If unicode, they should be aligned.
- *
- * Note that with Extended security, we may use
- * multiple calls to this function. Only parse
- * these strings on the last one (status == 0).
- * Ditto for the CAP_LARGE work-around.
- */
- if (rqp->rq_status != 0)
- goto out;
-
- /* Ignore any parsing errors for these strings. */
- err = md_get_string(mbp, &ctx->ct_srv_OS, uc);
- DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
- err = md_get_string(mbp, &ctx->ct_srv_LM, uc);
- DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
- /*
- * There's sometimes a server domain folloing
- * at this point, but we don't need it.
- */
-
- /* Success! (See Ignore any ... above) */
- err = 0;
-
- /*
- * MS-SMB 2.2.4.5 clarifies that when SMB signing is enabled,
- * the client should NOT use "large read/write" even though
- * the server might offer those capabilities.
- */
- if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
- DPRINT("signing, so disable CAP_LARGE_(r/w)");
- ctx->ct_sopt.sv_caps &=
- ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
- }
-
-out:
- if (rqp)
- smb_rq_done(rqp);
-
- return (err);
-}
diff --git a/usr/src/lib/libstmfproxy/common/stmftransport.c b/usr/src/lib/libstmfproxy/common/stmftransport.c
index eb392a2480..2d81769223 100644
--- a/usr/src/lib/libstmfproxy/common/stmftransport.c
+++ b/usr/src/lib/libstmfproxy/common/stmftransport.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -121,7 +125,7 @@ pt_socket_connect(int server_node, char *server)
sh = malloc(sizeof (*sh));
sh->sockfd = new_sfd;
serv_out:
- close(sfd);
+ (void) close(sfd);
} else {
struct hostent *hp;
@@ -151,7 +155,7 @@ serv_out:
while (connect(sfd, (struct sockaddr *)&sin,
sizeof (sin)) < 0) {
- close(sfd);
+ (void) close(sfd);
if (errno == ECONNREFUSED) {
/* get a fresh socket and retry */
sfd = socket(AF_INET, SOCK_STREAM, 0);
@@ -160,7 +164,7 @@ serv_out:
"socket() call failed: %d", errno);
return (NULL);
}
- sleep(2);
+ (void) sleep(2);
} else {
syslog(LOG_DAEMON|LOG_CRIT,
"Cannot connect %s - %d", server, errno);
diff --git a/usr/src/lib/libumem/Makefile.com b/usr/src/lib/libumem/Makefile.com
index b98977ed88..70bbb164a7 100644
--- a/usr/src/lib/libumem/Makefile.com
+++ b/usr/src/lib/libumem/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright (c) 2019, Joyent, Inc.
#
#
@@ -51,11 +51,15 @@ OBJECTS_library = \
umem_agent_support.o \
umem_fail.o \
umem_fork.o \
+ umem_genasm.o \
umem_update_thread.o \
vmem_mmap.o \
vmem_sbrk.o
-SRCS_library = $(OBJECTS_library:%.o=../common/%.c)
+SRCS_common_library = \
+ $(ISASRCDIR)/umem_genasm.c
+
+SRCS_library = $(OBJECTS_library:%.o=../common/%.c) $(SRC_common_library)
# Files specific to the standalone version of libumem
OBJECTS_standalone = \
@@ -67,12 +71,10 @@ SRCS_standalone = $(OBJECTS_standalone:%.o=../common/%.c)
# Architecture-dependent files common to both versions of libumem
OBJECTS_common_isadep = \
- asm_subr.o \
- umem_genasm.o
+ asm_subr.o
SRCS_common_isadep = \
- $(ISASRCDIR)/asm_subr.s \
- $(ISASRCDIR)/umem_genasm.c
+ $(ISASRCDIR)/asm_subr.s
# Architecture-independent files common to both versions of libumem
OBJECTS_common_common = \
@@ -96,7 +98,6 @@ include ../../Makefile.rootfs
SRCS = \
$(SRCS_$(CURTYPE)) \
- $(SRCS_common_isadep) \
$(SRCS_common_common)
SRCDIR = ../common
@@ -127,11 +128,6 @@ ASFLAGS_standalone = -DUMEM_STANDALONE
ASFLAGS_library =
ASFLAGS += -P $(ASFLAGS_$(CURTYPE)) -D_ASM
-CERRWARN += -_gcc=-Wno-switch
-CERRWARN += -_gcc=-Wno-uninitialized
-
-SMOFF += deref_check
-
$(LINTLIB) := SRCS = ../common/$(LINTSRC)
# We want the thread-specific errno in the library, but we don't want it in
diff --git a/usr/src/lib/libumem/amd64/umem_genasm.c b/usr/src/lib/libumem/amd64/umem_genasm.c
index ba68cb2d37..6f0c72ab34 100644
--- a/usr/src/lib/libumem/amd64/umem_genasm.c
+++ b/usr/src/lib/libumem/amd64/umem_genasm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019 Joyent, Inc. All rights reserved.
*/
/*
@@ -62,12 +62,18 @@
* Each block of assembly has psuedocode that describes its purpose.
*/
-#include <atomic.h>
+/*
+ * umem_base must be first.
+ */
+#include "umem_base.h"
+
#include <inttypes.h>
-#include <sys/types.h>
#include <strings.h>
#include <umem_impl.h>
-#include "umem_base.h"
+#include <atomic.h>
+#include <sys/mman.h>
+#include <errno.h>
+
const int umem_genasm_supported = 1;
static uintptr_t umem_genasm_mptr = (uintptr_t)&_malloc;
@@ -543,20 +549,57 @@ genasm_free(void *base, size_t len, int nents, int *umem_alloc_sizes)
return (0);
}
-/*ARGSUSED*/
-int
+boolean_t
umem_genasm(int *cp, umem_cache_t **caches, int nc)
{
int nents, i;
uint8_t *mptr;
uint8_t *fptr;
uint64_t v, *vptr;
+ size_t mplen, fplen;
+ uintptr_t mpbase, fpbase;
+ boolean_t ret = B_FALSE;
mptr = (void *)((uintptr_t)umem_genasm_mptr + 5);
fptr = (void *)((uintptr_t)umem_genasm_fptr + 5);
if (umem_genasm_mptr == 0 || umem_genasm_msize == 0 ||
- umem_genasm_fptr == 0 || umem_genasm_fsize == 0)
- return (1);
+ umem_genasm_fptr == 0 || umem_genasm_fsize == 0) {
+ return (B_FALSE);
+ }
+
+ mplen = P2ROUNDUP(umem_genasm_msize, pagesize);
+ mpbase = P2ALIGN((uintptr_t)umem_genasm_mptr, pagesize);
+ fplen = P2ROUNDUP(umem_genasm_fsize, pagesize);
+ fpbase = P2ALIGN((uintptr_t)umem_genasm_mptr, pagesize);
+
+ /*
+ * If the values straddle a page boundary, then we might need to
+ * actually remap two pages.
+ */
+ if (P2ALIGN(umem_genasm_msize + (uintptr_t)umem_genasm_mptr,
+ pagesize) != mpbase) {
+ mplen += pagesize;
+ }
+
+ if (P2ALIGN(umem_genasm_fsize + (uintptr_t)umem_genasm_fptr,
+ pagesize) != fpbase) {
+ fplen += pagesize;
+ }
+
+ if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_WRITE |
+ PROT_EXEC) != 0) {
+ return (B_FALSE);
+ }
+
+ if (mprotect((void *)fpbase, fplen, PROT_READ | PROT_WRITE |
+ PROT_EXEC) != 0) {
+ if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_EXEC) !=
+ 0) {
+ umem_panic("genasm failed to restore memory "
+ "protection: %d", errno);
+ }
+ return (B_FALSE);
+ }
/*
* The total number of caches that we can service is the minimum of:
@@ -573,17 +616,24 @@ umem_genasm(int *cp, umem_cache_t **caches, int nc)
if (nc < nents)
nents = nc;
- /* Based on our constraints, this is not an error */
- if (nents == 0 || umem_ptc_size == 0)
- return (0);
+ /*
+ * If the number of per-thread caches has been set to zero or the
+ * per-thread cache size has been set to zero, don't bother trying to
+ * write any assembly and just use the default malloc and free. When we
+ * return, indicate that there is no PTC support.
+ */
+ if (nents == 0 || umem_ptc_size == 0) {
+ goto out;
+ }
/* Take into account the jump */
- if (genasm_malloc(mptr, umem_genasm_msize, nents, cp) != 0)
- return (1);
-
- if (genasm_free(fptr, umem_genasm_fsize, nents, cp) != 0)
- return (1);
+ if (genasm_malloc(mptr, umem_genasm_msize, nents, cp) != 0) {
+ goto out;
+ }
+ if (genasm_free(fptr, umem_genasm_fsize, nents, cp) != 0) {
+ goto out;
+ }
/* nop out the jump with a multibyte jump */
vptr = (void *)umem_genasm_mptr;
@@ -598,5 +648,17 @@ umem_genasm(int *cp, umem_cache_t **caches, int nc)
for (i = 0; i < nents; i++)
caches[i]->cache_flags |= UMF_PTC;
- return (0);
+ ret = B_TRUE;
+out:
+ if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_EXEC) != 0) {
+ umem_panic("genasm failed to restore memory protection: %d",
+ errno);
+ }
+
+ if (mprotect((void *)fpbase, fplen, PROT_READ | PROT_EXEC) != 0) {
+ umem_panic("genasm failed to restore memory protection: %d",
+ errno);
+ }
+
+ return (ret);
}
diff --git a/usr/src/lib/libumem/common/envvar.c b/usr/src/lib/libumem/common/envvar.c
index 6c57d9553e..25758aa2e7 100644
--- a/usr/src/lib/libumem/common/envvar.c
+++ b/usr/src/lib/libumem/common/envvar.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright (c) 2012 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019 Joyent, Inc.
* Copyright (c) 2015 by Delphix. All rights reserved.
*/
@@ -539,6 +539,13 @@ process_item(const umem_env_item_t *item, const char *item_arg)
case ITEM_SIZE:
arg_required = 1;
break;
+
+ default:
+ /*
+ * These are flags that aren't supported, so they'll error out
+ * below.
+ */
+ break;
}
switch (item->item_type) {
diff --git a/usr/src/lib/libumem/common/mapfile-vers b/usr/src/lib/libumem/common/mapfile-vers
index 888a1570f2..e95e666885 100644
--- a/usr/src/lib/libumem/common/mapfile-vers
+++ b/usr/src/lib/libumem/common/mapfile-vers
@@ -20,7 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+# Copyright (c) 2019, Joyent, Inc.
#
#
@@ -41,7 +41,7 @@ $mapfile_version 2
$if _x86
LOAD_SEGMENT umem {
- FLAGS = READ WRITE EXECUTE;
+ FLAGS = READ EXECUTE;
ASSIGN_SECTION {
IS_NAME = .text;
FILE_BASENAME = asm_subr.o
diff --git a/usr/src/lib/libumem/common/umem.c b/usr/src/lib/libumem/common/umem.c
index dbc738a049..7f31529852 100644
--- a/usr/src/lib/libumem/common/umem.c
+++ b/usr/src/lib/libumem/common/umem.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019 Joyent, Inc.
* Copyright (c) 2015 by Delphix. All rights reserved.
*/
@@ -1338,12 +1338,13 @@ static void *
umem_log_enter(umem_log_header_t *lhp, void *data, size_t size)
{
void *logspace;
- umem_cpu_log_header_t *clhp =
- &lhp->lh_cpu[CPU(umem_cpu_mask)->cpu_number];
+ umem_cpu_log_header_t *clhp;
if (lhp == NULL || umem_logging == 0)
return (NULL);
+ clhp = &lhp->lh_cpu[CPU(umem_cpu_mask)->cpu_number];
+
(void) mutex_lock(&clhp->clh_lock);
clhp->clh_hits++;
if (size > clhp->clh_avail) {
@@ -2843,8 +2844,9 @@ umem_cache_create(
}
ASSERT(!(cp->cache_flags & UMF_AUDIT));
} else {
- size_t chunks, bestfit, waste, slabsize;
+ size_t chunks, waste, slabsize;
size_t minwaste = LONG_MAX;
+ size_t bestfit = SIZE_MAX;
for (chunks = 1; chunks <= UMEM_VOID_FRACTION; chunks++) {
slabsize = P2ROUNDUP(chunksize * chunks,
@@ -2865,6 +2867,10 @@ umem_cache_create(
}
if (cflags & UMC_QCACHE)
bestfit = MAX(1 << highbit(3 * vmp->vm_qcache_max), 64);
+ if (bestfit == SIZE_MAX) {
+ errno = ENOMEM;
+ goto fail;
+ }
cp->cache_slabsize = bestfit;
cp->cache_mincolor = 0;
cp->cache_maxcolor = bestfit % chunksize;
@@ -3215,12 +3221,16 @@ umem_cache_init(void)
umem_tmem_off = _tmem_get_base();
_tmem_set_cleanup(umem_cache_tmem_cleanup);
+#ifndef UMEM_STANDALONE
if (umem_genasm_supported && !(umem_flags & UMF_DEBUG) &&
!(umem_flags & UMF_NOMAGAZINE) &&
umem_ptc_size > 0) {
umem_ptc_enabled = umem_genasm(umem_alloc_sizes,
- umem_alloc_caches, i) == 0 ? 1 : 0;
+ umem_alloc_caches, i) ? 1 : 0;
}
+#else
+ umem_ptc_enabled = 0;
+#endif
/*
* Initialization cannot fail at this point. Make the caches
diff --git a/usr/src/lib/libumem/common/umem_base.h b/usr/src/lib/libumem/common/umem_base.h
index c845331fbc..d8f6f4fd4a 100644
--- a/usr/src/lib/libumem/common/umem_base.h
+++ b/usr/src/lib/libumem/common/umem_base.h
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#ifndef _UMEM_BASE_H
@@ -147,7 +147,7 @@ void umem_process_envvars(void);
* umem_genasm.c: private interfaces
*/
extern const int umem_genasm_supported;
-extern int umem_genasm(int *, umem_cache_t **, int);
+extern boolean_t umem_genasm(int *, umem_cache_t **, int);
/*
* malloc.c: traditional malloc/free interface for genasm
diff --git a/usr/src/lib/libumem/common/vmem.c b/usr/src/lib/libumem/common/vmem.c
index c868e42977..a04a538e69 100644
--- a/usr/src/lib/libumem/common/vmem.c
+++ b/usr/src/lib/libumem/common/vmem.c
@@ -22,7 +22,8 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2012 Joyent, Inc. All rights reserved.
+ * Copyright 2019, Joyent, Inc.
+ * Copyright (c) 2017 by Delphix. All rights reserved.
*/
/*
@@ -458,12 +459,12 @@ vmem_span_create(vmem_t *vmp, void *vaddr, size_t size, uint8_t import)
span = vmem_seg_create(vmp, knext->vs_aprev, start, end);
span->vs_type = VMEM_SPAN;
+ span->vs_import = import;
VMEM_INSERT(knext->vs_kprev, span, k);
newseg = vmem_seg_create(vmp, span, start, end);
vmem_freelist_insert(vmp, newseg);
- newseg->vs_import = import;
if (import)
vmp->vm_kstat.vk_mem_import += size;
vmp->vm_kstat.vk_mem_total += size;
@@ -483,7 +484,7 @@ vmem_span_destroy(vmem_t *vmp, vmem_seg_t *vsp)
ASSERT(MUTEX_HELD(&vmp->vm_lock));
ASSERT(span->vs_type == VMEM_SPAN);
- if (vsp->vs_import)
+ if (span->vs_import)
vmp->vm_kstat.vk_mem_import -= size;
vmp->vm_kstat.vk_mem_total -= size;
@@ -686,7 +687,8 @@ vmem_advance(vmem_t *vmp, vmem_seg_t *walker, vmem_seg_t *afterme)
* vsp could represent a complete imported span,
* in which case we must return it to the source.
*/
- if (vsp != NULL && vsp->vs_import && vmp->vm_source_free != NULL &&
+ if (vsp != NULL && vsp->vs_aprev->vs_import &&
+ vmp->vm_source_free != NULL &&
vsp->vs_aprev->vs_type == VMEM_SPAN &&
vsp->vs_anext->vs_type == VMEM_SPAN) {
void *vaddr = (void *)vsp->vs_start;
@@ -813,11 +815,11 @@ vmem_nextfit_alloc(vmem_t *vmp, size_t size, int vmflag)
*/
void *
vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase,
- size_t nocross, void *minaddr, void *maxaddr, int vmflag)
+ size_t nocross, void *minaddr, void *maxaddr, int vmflag)
{
vmem_seg_t *vsp;
vmem_seg_t *vbest = NULL;
- uintptr_t addr, taddr, start, end;
+ uintptr_t addr = 0, taddr, start, end;
void *vaddr;
int hb, flist, resv;
uint32_t mtbf;
@@ -979,6 +981,9 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase,
(void) pthread_setcancelstate(cancel_state, NULL);
}
if (vbest != NULL) {
+ if (addr == 0) {
+ umem_panic("vmem_xalloc(): addr == 0");
+ }
ASSERT(vbest->vs_type == VMEM_FREE);
ASSERT(vbest->vs_knext != vbest);
(void) vmem_seg_alloc(vmp, vbest, addr, size);
@@ -1040,7 +1045,7 @@ vmem_xfree(vmem_t *vmp, void *vaddr, size_t size)
/*
* If the entire span is free, return it to the source.
*/
- if (vsp->vs_import && vmp->vm_source_free != NULL &&
+ if (vsp->vs_aprev->vs_import && vmp->vm_source_free != NULL &&
vsp->vs_aprev->vs_type == VMEM_SPAN &&
vsp->vs_anext->vs_type == VMEM_SPAN) {
vaddr = (void *)vsp->vs_start;
@@ -1364,7 +1369,7 @@ _vmem_extend_alloc(vmem_t *vmp, void *vaddr, size_t size, size_t alloc,
*/
void
vmem_walk(vmem_t *vmp, int typemask,
- void (*func)(void *, void *, size_t), void *arg)
+ void (*func)(void *, void *, size_t), void *arg)
{
vmem_seg_t *vsp;
vmem_seg_t *seg0 = &vmp->vm_seg0;
@@ -1428,8 +1433,8 @@ vmem_size(vmem_t *vmp, int typemask)
*/
vmem_t *
vmem_create(const char *name, void *base, size_t size, size_t quantum,
- vmem_alloc_t *afunc, vmem_free_t *ffunc, vmem_t *source,
- size_t qcache_max, int vmflag)
+ vmem_alloc_t *afunc, vmem_free_t *ffunc, vmem_t *source,
+ size_t qcache_max, int vmflag)
{
int i;
size_t nqcache;
diff --git a/usr/src/lib/libumem/i386/umem_genasm.c b/usr/src/lib/libumem/i386/umem_genasm.c
index 530a83e486..7c0753bf81 100644
--- a/usr/src/lib/libumem/i386/umem_genasm.c
+++ b/usr/src/lib/libumem/i386/umem_genasm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019 Joyent, Inc. All rights reserved.
*/
/*
@@ -60,12 +60,17 @@
* Each block of assembly has psuedocode that describes its purpose.
*/
+/*
+ * umem_base must be first.
+ */
+#include "umem_base.h"
+
#include <inttypes.h>
#include <strings.h>
#include <umem_impl.h>
-#include "umem_base.h"
-
#include <atomic.h>
+#include <sys/mman.h>
+#include <errno.h>
const int umem_genasm_supported = 1;
static uintptr_t umem_genasm_mptr = (uintptr_t)&_malloc;
@@ -536,19 +541,57 @@ genasm_free(void *base, size_t len, int nents, int *umem_alloc_sizes)
return (0);
}
-int
+boolean_t
umem_genasm(int *alloc_sizes, umem_cache_t **caches, int ncaches)
{
int nents, i;
uint8_t *mptr;
uint8_t *fptr;
uint64_t v, *vptr;
+ size_t mplen, fplen;
+ uintptr_t mpbase, fpbase;
+ boolean_t ret = B_FALSE;
mptr = (void *)((uintptr_t)umem_genasm_mptr + 5);
fptr = (void *)((uintptr_t)umem_genasm_fptr + 5);
if (umem_genasm_mptr == 0 || umem_genasm_msize == 0 ||
- umem_genasm_fptr == 0 || umem_genasm_fsize == 0)
- return (1);
+ umem_genasm_fptr == 0 || umem_genasm_fsize == 0) {
+ return (B_FALSE);
+ }
+
+ mplen = P2ROUNDUP(umem_genasm_msize, pagesize);
+ mpbase = P2ALIGN((uintptr_t)umem_genasm_mptr, pagesize);
+ fplen = P2ROUNDUP(umem_genasm_fsize, pagesize);
+ fpbase = P2ALIGN((uintptr_t)umem_genasm_mptr, pagesize);
+
+ /*
+ * If the values straddle a page boundary, then we might need to
+ * actually remap two pages.
+ */
+ if (P2ALIGN(umem_genasm_msize + (uintptr_t)umem_genasm_mptr,
+ pagesize) != mpbase) {
+ mplen += pagesize;
+ }
+
+ if (P2ALIGN(umem_genasm_fsize + (uintptr_t)umem_genasm_fptr,
+ pagesize) != fpbase) {
+ fplen += pagesize;
+ }
+
+ if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_WRITE |
+ PROT_EXEC) != 0) {
+ return (B_FALSE);
+ }
+
+ if (mprotect((void *)fpbase, fplen, PROT_READ | PROT_WRITE |
+ PROT_EXEC) != 0) {
+ if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_EXEC) !=
+ 0) {
+ umem_panic("genasm failed to restore memory "
+ "protection: %d", errno);
+ }
+ return (B_FALSE);
+ }
/*
* The total number of caches that we can service is the minimum of:
@@ -565,18 +608,26 @@ umem_genasm(int *alloc_sizes, umem_cache_t **caches, int ncaches)
if (ncaches < nents)
nents = ncaches;
- /* Based on our constraints, this is not an error */
- if (nents == 0 || umem_ptc_size == 0)
- return (0);
+ /*
+ * If the number of per-thread caches has been set to zero or the
+ * per-thread cache size has been set to zero, don't bother trying to
+ * write any assembly and just use the default malloc and free. When we
+ * return, indicate that there is no PTC support.
+ */
+ if (nents == 0 || umem_ptc_size == 0) {
+ goto out;
+ }
/* Take into account the jump */
if (genasm_malloc(mptr, umem_genasm_msize, nents,
- alloc_sizes) != 0)
- return (1);
+ alloc_sizes) != 0) {
+ goto out;
+ }
if (genasm_free(fptr, umem_genasm_fsize, nents,
- alloc_sizes) != 0)
- return (1);
+ alloc_sizes) != 0) {
+ goto out;
+ }
/* nop out the jump with a multibyte jump */
vptr = (void *)umem_genasm_mptr;
@@ -591,5 +642,17 @@ umem_genasm(int *alloc_sizes, umem_cache_t **caches, int ncaches)
for (i = 0; i < nents; i++)
caches[i]->cache_flags |= UMF_PTC;
- return (0);
+ ret = B_TRUE;
+out:
+ if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_EXEC) != 0) {
+ umem_panic("genasm failed to restore memory protection: %d",
+ errno);
+ }
+
+ if (mprotect((void *)fpbase, fplen, PROT_READ | PROT_EXEC) != 0) {
+ umem_panic("genasm failed to restore memory protection: %d",
+ errno);
+ }
+
+ return (ret);
}
diff --git a/usr/src/lib/libumem/sparc/umem_genasm.c b/usr/src/lib/libumem/sparc/umem_genasm.c
index 202d642b0b..95a38a0a78 100644
--- a/usr/src/lib/libumem/sparc/umem_genasm.c
+++ b/usr/src/lib/libumem/sparc/umem_genasm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019 Joyent, Inc.
*/
/*
@@ -35,9 +35,8 @@
const int umem_genasm_supported = 0;
-/*ARGSUSED*/
-int
+boolean_t
umem_genasm(int *alloc_sizes, umem_cache_t **caches, int ncaches)
{
- return (1);
+ return (B_FALSE);
}
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 92594c59a0..09ce507dc0 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -271,6 +271,8 @@ extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
extern int zpool_reguid(zpool_handle_t *);
extern int zpool_reopen(zpool_handle_t *);
+extern int zpool_sync_one(zpool_handle_t *, void *);
+
extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
vdev_state_t *);
extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t);
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index 6cce9e22aa..eab6a920f0 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -3514,6 +3514,27 @@ zpool_reopen(zpool_handle_t *zhp)
return (zpool_standard_error(hdl, errno, msg));
}
+/* call into libzfs_core to execute the sync IOCTL per pool */
+int
+zpool_sync_one(zpool_handle_t *zhp, void *data)
+{
+ int ret;
+ libzfs_handle_t *hdl = zpool_get_handle(zhp);
+ const char *pool_name = zpool_get_name(zhp);
+ boolean_t *force = data;
+ nvlist_t *innvl = fnvlist_alloc();
+
+ fnvlist_add_boolean_value(innvl, "force", *force);
+ if ((ret = lzc_sync(pool_name, innvl, NULL)) != 0) {
+ nvlist_free(innvl);
+ return (zpool_standard_error_fmt(hdl, ret,
+ dgettext(TEXT_DOMAIN, "sync '%s' failed"), pool_name));
+ }
+ nvlist_free(innvl);
+
+ return (0);
+}
+
/*
* Convert from a devid string to a path.
*/
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index 17a60e830d..fa81e6440b 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -247,6 +247,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zpool_set_prop;
zpool_skip_pool;
zpool_state_to_name;
+ zpool_sync_one;
zpool_unmount_datasets;
zpool_upgrade;
zpool_vdev_attach;
diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.c b/usr/src/lib/libzfs_core/common/libzfs_core.c
index 268f1d6a7a..79e9901bd7 100644
--- a/usr/src/lib/libzfs_core/common/libzfs_core.c
+++ b/usr/src/lib/libzfs_core/common/libzfs_core.c
@@ -24,6 +24,7 @@
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 RackTop Systems.
+ * Copyright (c) 2017 Datto Inc.
*/
/*
@@ -128,17 +129,20 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
{
zfs_cmd_t zc = { 0 };
int error = 0;
- char *packed;
- size_t size;
+ char *packed = NULL;
+ size_t size = 0;
ASSERT3S(g_refcount, >, 0);
VERIFY3S(g_fd, !=, -1);
- (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+ if (name != NULL)
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
- packed = fnvlist_pack(source, &size);
- zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
- zc.zc_nvlist_src_size = size;
+ if (source != NULL) {
+ packed = fnvlist_pack(source, &size);
+ zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
+ zc.zc_nvlist_src_size = size;
+ }
if (resultp != NULL) {
*resultp = NULL;
@@ -416,6 +420,18 @@ lzc_exists(const char *dataset)
}
/*
+ * outnvl is unused.
+ * It was added to preserve the function signature in case it is
+ * needed in the future.
+ */
+/*ARGSUSED*/
+int
+lzc_sync(const char *pool_name, nvlist_t *innvl, nvlist_t **outnvl)
+{
+ return (lzc_ioctl(ZFS_IOC_POOL_SYNC, pool_name, innvl, NULL));
+}
+
+/*
* Create "user holds" on snapshots. If there is a hold on a snapshot,
* the snapshot can not be destroyed. (However, it can be marked for deletion
* by lzc_destroy_snaps(defer=B_TRUE).)
@@ -515,11 +531,7 @@ lzc_release(nvlist_t *holds, nvlist_t **errlist)
int
lzc_get_holds(const char *snapname, nvlist_t **holdsp)
{
- int error;
- nvlist_t *innvl = fnvlist_alloc();
- error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp);
- fnvlist_free(innvl);
- return (error);
+ return (lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, NULL, holdsp));
}
/*
diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.h b/usr/src/lib/libzfs_core/common/libzfs_core.h
index 7dc618403e..cbc0c68af8 100644
--- a/usr/src/lib/libzfs_core/common/libzfs_core.h
+++ b/usr/src/lib/libzfs_core/common/libzfs_core.h
@@ -23,6 +23,7 @@
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 RackTop Systems.
+ * Copyright (c) 2017 Datto Inc.
*/
#ifndef _LIBZFS_CORE_H
@@ -91,6 +92,8 @@ boolean_t lzc_exists(const char *);
int lzc_rollback(const char *, char *, int);
int lzc_rollback_to(const char *, const char *);
+int lzc_sync(const char *, nvlist_t *, nvlist_t **);
+
int lzc_rename(const char *, const char *);
int lzc_destroy(const char *);
diff --git a/usr/src/lib/libzfs_core/common/mapfile-vers b/usr/src/lib/libzfs_core/common/mapfile-vers
index 3ad87ef0d8..93a7334fb1 100644
--- a/usr/src/lib/libzfs_core/common/mapfile-vers
+++ b/usr/src/lib/libzfs_core/common/mapfile-vers
@@ -21,6 +21,7 @@
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, 2017 by Delphix. All rights reserved.
# Copyright 2017 RackTop Systems.
+# Copyright 2019 Joyent, Inc.
#
# MAPFILE HEADER START
#
@@ -37,6 +38,12 @@
$mapfile_version 2
+SYMBOL_VERSION ILLUMOS_0.5 {
+ global:
+
+ lzc_sync;
+} ILLUMOS_0.4;
+
SYMBOL_VERSION ILLUMOS_0.4 {
global:
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..01da52d337
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/Makefile.com
@@ -0,0 +1,109 @@
+#
+# 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 2018 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 \
+ smb2_rq.o \
+ smb2_sign.o \
+ smb2_smb.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..27fbd87b4d
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfknsmb/common/mapfile-vers
@@ -0,0 +1,134 @@
+#
+# 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 2018 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_mbchain;
+ mb_put_mbuf;
+ mb_put_mem;
+ mb_put_padbyte;
+ mb_put_uint16le;
+ mb_put_uint32le;
+ mb_put_uint64le;
+ mb_put_uint8;
+ mb_put_uio;
+ 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_debugmsg { FLAGS = NODIRECT };
+ smb_dev2share;
+ smb_errmsg { FLAGS = NODIRECT };
+ smb_fh_close;
+ smb_fh_create;
+ smb_fh_hold;
+ smb_fh_opened;
+ smb_fh_rele;
+ smb_get_dstring;
+ 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_timo_append;
+ smb_timo_open;
+ smb_timo_read;
+ smb_timo_write;
+
+ smb2_rq_simple;
+ smb2_rq_simple_timed;
+ smb2_smb_close;
+ smb2_smb_ntcreate;
+
+ 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..abc12a9464
--- /dev/null
+++ b/usr/src/lib/smbclnt/libfksmbfs/Makefile.com
@@ -0,0 +1,139 @@
+#
+# 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 2018 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_smb1.o \
+ smbfs_smb2.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)
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
index 7524e2db55..b6b669cd27 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -36,7 +36,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/smbinfo.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/ntlocale.h>
#include <smbsrv/string.h>
#include <lsalib.h>
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
index 956fbbad15..942650545f 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -41,7 +41,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libsmbns.h>
#include <smbsrv/libmlsvc.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/smbinfo.h>
#include <smbsrv/netrauth.h>
#include <libsmbrdr.h>
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
index 8b0c4e3fbd..edf6952a8d 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -37,7 +37,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <lsalib.h>
#include <samlib.h>
@@ -47,8 +47,8 @@
#define letohl(x) ((uint32_t)(x))
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
/* little-endian values on big-endian (swap) */
-#define letohl(x) BSWAP_32(x)
-#define htolel(x) BSWAP_32(x)
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
#endif /* (BYTE_ORDER == LITTLE_ENDIAN) */
/*
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
index dd15469c15..38dc21b712 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -48,7 +48,7 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/smbinfo.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
#include <smbsrv/smb_sid.h>
#include <samlib.h>
diff --git a/usr/src/man/man1/chgrp.1 b/usr/src/man/man1/chgrp.1
index 795bc56f66..cab549e34b 100644
--- a/usr/src/man/man1/chgrp.1
+++ b/usr/src/man/man1/chgrp.1
@@ -49,7 +49,7 @@
.\" Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved
.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved
.\"
-.TH CHGRP 1 "Jul 11, 2008"
+.TH CHGRP 1 "Feb 21, 2019"
.SH NAME
chgrp \- change file group ownership
.SH SYNOPSIS
@@ -74,7 +74,6 @@ chgrp \- change file group ownership
.fi
.SH DESCRIPTION
-.sp
.LP
The \fBchgrp\fR utility will set the group ID of the file named by each
\fIfile\fR operand to the group ID specified by the \fIgroup\fR operand.
@@ -136,10 +135,9 @@ set rstchown = 0
\fB_POSIX_CHOWN_RESTRICTED\fR is enabled by default. See \fBsystem\fR(4) and
\fBfpathconf\fR(2).
.SH OPTIONS
-.sp
.LP
The following options are supported.
-.SS "/usr/bin/chgrp and /usr/xpg4/bin/chgrp"
+
.sp
.ne 2
.na
@@ -202,49 +200,34 @@ of the file hierarchy.
.sp
.ne 2
.na
-\fB\fB-s\fR\fR
-.ad
-.RS 6n
-The specified group is Windows SID. This option requires a file system that
-supports storing SIDs, such as ZFS.
-.RE
-
-.sp
-.LP
-Specifying more than one of the mutually-exclusive options \fB-H\fR, \fB-L\fR,
-or \fB-P\fR is not considered an error. The last option specified determines
-the behavior of \fBchgrp\fR.
-.SS "/usr/bin/chgrp"
-.sp
-.ne 2
-.na
\fB\fB-R\fR\fR
.ad
.RS 6n
Recursive. \fBchgrp\fR descends through the directory, and any subdirectories,
setting the specified group \fBID\fR as it proceeds. When a symbolic link is
-encountered, the group of the target file is changed, unless the \fB-h\fR or
-\fB-P\fR option is specified. However, no recursion takes place, unless the
-\fB-H\fR or \fB-L\fR option is specified.
+encountered, the group of the of the symbolic link is changed, unless the
+\fB-H\fR or \fB-L\fR option is specified. Unless the \fB-H\fR, \fB-L\fR,
+or \fB-P\fR option is specified, the \fB-P\fR option is used as the default mode.
.RE
-.SS "/usr/xpg4/bin/chgrp"
.sp
.ne 2
.na
-\fB\fB-R\fR\fR
+\fB\fB-s\fR\fR
.ad
.RS 6n
-Recursive. \fBchgrp\fR descends through the directory, and any subdirectories,
-setting the specified group \fBID\fR as it proceeds. When a symbolic link is
-encountered, the group of the target file is changed, unless the \fB-h\fR or
-\fB-P\fR option is specified. Unless the \fB-H\fR, \fB-L\fR, or \fB-P\fR option
-is specified, the \fB-L\fR option is used as the default mode.
+The specified group is Windows SID. This option requires a file system that
+supports storing SIDs, such as ZFS.
.RE
-.SH OPERANDS
.sp
.LP
+Specifying more than one of the mutually-exclusive options \fB-H\fR, \fB-L\fR,
+or \fB-P\fR is not considered an error. The last option specified determines
+the behavior of \fBchgrp\fR.
+
+.SH OPERANDS
+.LP
The following operands are supported:
.sp
.ne 2
@@ -268,18 +251,15 @@ A path name of a file whose group ID is to be modified.
.RE
.SH USAGE
-.sp
.LP
See \fBlargefile\fR(5) for the description of the behavior of \fBchgrp\fR when
encountering files greater than or equal to 2 Gbyte (2^31 bytes).
.SH ENVIRONMENT VARIABLES
-.sp
.LP
See \fBenviron\fR(5) for descriptions of the following environment variables
that affect the execution of \fBchgrp\fR: \fBLANG\fR, \fBLC_ALL\fR,
\fBLC_CTYPE\fR, \fBLC_MESSAGES\fR, and \fBNLSPATH\fR.
.SH EXIT STATUS
-.sp
.LP
The following exit values are returned:
.sp
@@ -301,7 +281,6 @@ An error occurred.
.RE
.SH FILES
-.sp
.ne 2
.na
\fB\fB/etc/group\fR\fR
@@ -311,30 +290,9 @@ group file
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
-.SS "/usr/bin/chgrp"
-.sp
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-CSI Enabled. See NOTES.
-_
-Interface Stability Committed
-_
-Standard See \fBstandards\fR(5).
-.TE
-
-.SS "/usr/xpg4/bin/chgrp"
-.sp
-
-.sp
.TS
box;
c | c
@@ -349,12 +307,14 @@ Standard See \fBstandards\fR(5).
.TE
.SH SEE ALSO
-.sp
.LP
\fBchmod\fR(1), \fBchown\fR(1), \fBid\fR(1M), \fBchown\fR(2),
\fBfpathconf\fR(2), \fBgroup\fR(4), \fBpasswd\fR(4), \fBsystem\fR(4),
\fBattributes\fR(5), \fBenviron\fR(5), \fBlargefile\fR(5), \fBstandards\fR(5)
.SH NOTES
-.sp
.LP
\fBchgrp\fR is CSI-enabled except for the \fIgroup\fR name.
+.sp
+.LP
+In the past the behavior of \fB/usr/xpg4/bin/chgrp\fR and
+\fB/usr/bin/chgrp\fR utilities was different. Now they behave the same way.
diff --git a/usr/src/man/man1/chown.1 b/usr/src/man/man1/chown.1
index f309fa3e37..6ec6a8247a 100644
--- a/usr/src/man/man1/chown.1
+++ b/usr/src/man/man1/chown.1
@@ -45,61 +45,31 @@
.\" Portions Copyright (c) 1982-2007 AT&T Knowledge Ventures
.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved
.\"
-.TH CHOWN 1 "Jul 11, 2008"
+.TH CHOWN 1 "Feb 21, 2019"
.SH NAME
chown \- change file ownership
.SH SYNOPSIS
-.SS "/usr/bin/chown"
.LP
.nf
-\fB/usr/bin/chown\fR [\fB-fhR\fR] \fIowner\fR[:\fIgroup\fR] \fIfile\fR...
+\fBchown\fR [\fB-fhR\fR] \fIowner\fR[:\fIgroup\fR] \fIfile\fR...
.fi
.LP
.nf
-\fB/usr/bin/chown\fR \fB-s\fR [\fB-fhR\fR] \fIownersid\fR[:\fIgroupsid\fR] \fIfile\fR...
+\fBchown\fR \fB-s\fR [\fB-fhR\fR] \fIownersid\fR[:\fIgroupsid\fR] \fIfile\fR...
.fi
.LP
.nf
-\fB/usr/bin/chown\fR \fB-R\fR [\fB-f\fR] [\fB-H\fR | \fB-L\fR | \fB-P\fR] \fIowner\fR[:\fIgroup\fR] \fIfile\fR...
+\fBchown\fR \fB-R\fR [\fB-f\fR] [\fB-H\fR | \fB-L\fR | \fB-P\fR] \fIowner\fR[:\fIgroup\fR] \fIfile\fR...
.fi
.LP
.nf
-\fB/usr/bin/chown\fR \fB-s\fR \fB-R\fR [\fB-f\fR] [\fB-H\fR | \fB-L\fR | \fB-P\fR] \fIownersid\fR[:\fIgroupsid\fR] \fIfile\fR...
-.fi
-
-.SS "/usr/xpg4/bin/chown"
-.LP
-.nf
-\fB/usr/xpg4/bin/chown\fR [\fB-fhR\fR] \fIowner\fR[:\fIgroup\fR] \fIfile\fR...
-.fi
-
-.LP
-.nf
-\fB/usr/xpg4/bin/chown\fR \fB-s\fR [\fB-fhR\fR] \fIownersid\fR[:\fIgroupsid\fR] \fIfile\fR...
-.fi
-
-.LP
-.nf
-\fB/usr/xpg4/bin/chown\fR \fB-R\fR [\fB-f\fR] [\fB-H\fR | \fB-L\fR | \fB-P\fR] \fIowner\fR[:\fIgroup\fR] \fIfile\fR...
-.fi
-
-.LP
-.nf
-\fB/usr/xpg4/bin/chown\fR \fB-s\fR \fB-R\fR [\fB-f\fR] [\fB-H\fR | \fB-L\fR | \fB-P\fR] \fIownersid\fR[:\fIgroupsid\fR] \fIfile\fR...
-.fi
-
-.SS "ksh93"
-.LP
-.nf
-\fBchown\fR [\fB-cflhmnvHLPRX\fR] [\fB-r\fR \fIfile\fR] \fIowner\fR[:\fIgroup\fR] \fIfile\fR...
+\fBchown\fR \fB-s\fR \fB-R\fR [\fB-f\fR] [\fB-H\fR | \fB-L\fR | \fB-P\fR] \fIownersid\fR[:\fIgroupsid\fR] \fIfile\fR...
.fi
.SH DESCRIPTION
-.SS "/usr/bin/chown and /usr/xpg4/bin/chown"
-.sp
.LP
The \fBchown\fR utility sets the user \fBID\fR of the file named by each
\fBfile\fR to the user \fBID\fR specified by \fIowner\fR, and, optionally, sets
@@ -142,22 +112,7 @@ To disable this option, include the following line in \fB/etc/system\fR:
.LP
\fB{_POSIX_CHOWN_RESTRICTED}\fR is enabled by default. See \fBsystem\fR(4) and
\fBfpathconf\fR(2).
-.SS "ksh93"
-.sp
-.LP
-The \fBchown\fR built-in in \fBksh93\fR is associated with the \fB/bin\fR and
-\fB/usr/bin\fR paths. It is invoked when \fBchown\fR is executed without a
-pathname prefix and the pathname search finds a \fB/bin/chown\fR or
-/usr/bin/chown executable.
-.sp
-.LP
-\fBchown\fR changes the ownership of each file to \fIowner\fR. \fIowner\fR can
-be specified as either a user name or a numeric user id. The group ownership of
-each file can also be changed to \fIgroup\fR by appending \fI:group\fR to the
-user name.
.SH OPTIONS
-.SS "/usr/bin/chown and /usr/xpg4/bin/chown"
-.sp
.LP
The following options are supported:
.sp
@@ -222,239 +177,33 @@ of the file hierarchy.
.sp
.ne 2
.na
-\fB\fB-s\fR\fR
-.ad
-.RS 6n
-The owner and/or group arguments are Windows SID strings. This option requires
-a file system that supports storing SIDs, such as ZFS.
-.RE
-
-.sp
-.LP
-Specifying more than one of the mutually-exclusive options \fB-H\fR, \fB-L\fR,
-or \fB-P\fR is not considered an error. The last option specified determines
-the behavior of \fBchown\fR.
-.SS "/usr/bin/chown"
-.sp
-.LP
-The following options are supported:
-.sp
-.ne 2
-.na
\fB\fB-R\fR\fR
.ad
.RS 6n
Recursive. \fBchown\fR descends through the directory, and any subdirectories,
setting the specified ownership \fBID\fR as it proceeds. When a symbolic link
-is encountered, the owner of the target file is changed, unless the \fB-h\fR or
-\fB-P\fR option is specified. However, no recursion takes place, unless the
-\fB-H\fR or \fB-L\fR option is specified.
+is encountered, the owner of the symbolic link is changed, unless the
+\fB-H\fR or \fB-L\fR option is specified. Unless the \fB-H\fR, \fB-L\fR, or \fB-P\fR
+option is specified, the \fB-P\fR option is used as the default mode.
.RE
-.SS "/usr/xpg4/bin/chown"
-.sp
-.LP
-The following options are supported:
.sp
.ne 2
.na
-\fB\fB-R\fR\fR
+\fB\fB-s\fR\fR
.ad
.RS 6n
-Recursive. \fBchown\fR descends through the directory, and any subdirectories,
-setting the specified ownership \fBID\fR as it proceeds. When a symbolic link
-is encountered, the owner of the target file is changed, unless the \fB-h\fR or
-\fB-P\fR option is specified. Unless the \fB-H\fR, \fB-L\fR, or \fB-P\fR option
-is specified, the \fB-L\fR option is used as the default mode.
+The owner and/or group arguments are Windows SID strings. This option requires
+a file system that supports storing SIDs, such as ZFS.
.RE
-.SS "ksh93"
.sp
.LP
-The following options are supported by the \fBksh93\fR built-in \fBchown\fR
-command:
-.sp
-.ne 2
-.na
-\fB\fB-c\fR\fR
-.ad
-.br
-.na
-\fB\fB--changes\fR\fR
-.ad
-.sp .6
-.RS 4n
-Describe only files whose ownership actually changes.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-f\fR\fR
-.ad
-.br
-.na
-\fB\fB--quiet | silent\fR\fR
-.ad
-.sp .6
-.RS 4n
-Do not report files whose ownership fails to change.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-l | h\fR\fR
-.ad
-.br
-.na
-\fB\fB--symlink\fR\fR
-.ad
-.sp .6
-.RS 4n
-Change the ownership of the symbolic links on systems that support this option.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-m\fR\fR
-.ad
-.br
-.na
-\fB\fB--map\fR\fR
-.ad
-.sp .6
-.RS 4n
-Interpret the first operand as a file that contains a map of:
-.sp
-.in +2
-.nf
-\fIfrom_uid\fR:\fIfrom_gid to_uid:to_gid\fR
-.fi
-.in -2
-.sp
-
-pairs. Ownership of files matching the \fIfrom\fR part of any pair is changed
-to the corresponding \fIto\fR part of the pair. The process stops at the first
-match for each file. Unmatched files are silently ignored.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-n\fR\fR
-.ad
-.br
-.na
-\fB\fB--show\fR\fR
-.ad
-.sp .6
-.RS 4n
-Show actions but do not execute.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-r\fR\fR
-.ad
-.br
-.na
-\fB\fB--reference=file\fR\fR
-.ad
-.sp .6
-.RS 4n
-Omit the explicit ownership operand and use the ownership of the file instead.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-v\fR\fR
-.ad
-.br
-.na
-\fB\fB--verbose\fR\fR
-.ad
-.sp .6
-.RS 4n
-Describe the changed permissions of all files.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-H\fR\fR
-.ad
-.br
-.na
-\fB\fB--metaphysical\fR\fR
-.ad
-.sp .6
-.RS 4n
-Follow symbolic links for command arguments. Otherwise do not follow symbolic
-links when traversing directories.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-L\fR\fR
-.ad
-.br
-.na
-\fB\fB--logical | follow\fR\fR
-.ad
-.sp .6
-.RS 4n
-Follow symbolic links when traversing directories.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-P\fR\fR
-.ad
-.br
-.na
-\fB\fB--physical | nofollow\fR\fR
-.ad
-.sp .6
-.RS 4n
-Do not follow symbolic links when traversing directories.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-R\fR\fR
-.ad
-.br
-.na
-\fB\fB--recursive\fR\fR
-.ad
-.sp .6
-.RS 4n
-Recursively change ownership of directories and their contents.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-X\fR\fR
-.ad
-.br
-.na
-\fB\fB--test\fR\fR
-.ad
-.sp .6
-.RS 4n
-Canonicalize output for testing.
-.RE
+Specifying more than one of the mutually-exclusive options \fB-H\fR, \fB-L\fR,
+or \fB-P\fR is not considered an error. The last option specified determines
+the behavior of \fBchown\fR.
.SH OPERANDS
-.sp
.LP
The following operands are supported:
.sp
@@ -486,7 +235,6 @@ A path name of a file whose user \fBID\fR is to be modified.
.RE
.SH USAGE
-.sp
.LP
See \fBlargefile\fR(5) for the description of the behavior of \fBchown\fR when
encountering files greater than or equal to 2 Gbyte ( 2^31 bytes).
@@ -507,13 +255,11 @@ example% \fBchown \(miR \(mih \fIowner\fR[:group] \fIfile\fR...\fR
.sp
.SH ENVIRONMENT VARIABLES
-.sp
.LP
See \fBenviron\fR(5) for descriptions of the following environment variables
that affect the execution of \fBchown\fR: \fBLANG\fR, \fBLC_ALL\fR,
\fBLC_CTYPE\fR, \fBLC_MESSAGES\fR, and \fBNLSPATH\fR.
.SH EXIT STATUS
-.sp
.LP
The following exit values are returned:
.sp
@@ -535,7 +281,6 @@ An error occurred.
.RE
.SH FILES
-.sp
.ne 2
.na
\fB\fB/etc/passwd\fR\fR
@@ -545,28 +290,8 @@ System password file
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
-.SS "/usr/bin/chown"
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-CSI Enabled. See NOTES.
-_
-Interface Stability Committed
-_
-Standard See \fBstandards\fR(5).
-.TE
-
-.SS "/usr/xpg4/bin/chown"
-.sp
.sp
.TS
@@ -582,31 +307,16 @@ _
Standard See \fBstandards\fR(5).
.TE
-.SS "ksh93"
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability See below.
-.TE
-
-.sp
-.LP
-The \fBksh93\fR built-in binding to \fB/bin\fR and \fB/usr/bin\fR is Volatile.
-The built-in interfaces are Uncommitted.
.SH SEE ALSO
-.sp
.LP
\fBchgrp\fR(1), \fBchmod\fR(1), \fBksh93\fR(1), \fBchown\fR(2),
\fBfpathconf\fR(2), \fBpasswd\fR(4), \fBsystem\fR(4), \fBattributes\fR(5),
\fBenviron\fR(5), \fBlargefile\fR(5), \fBstandards\fR(5)
.SH NOTES
-.sp
.LP
\fBchown\fR is \fBCSI\fR-enabled except for the \fIowner\fR and \fIgroup\fR
names.
+.sp
+.LP
+In the past the behavior of \fB/usr/xpg4/bin/chown\fR and
+\fB/usr/bin/chown\fR utilities was different. Now they behave the same way.
diff --git a/usr/src/man/man1/dis.1 b/usr/src/man/man1/dis.1
index bff3a55372..dcb12b50b6 100644
--- a/usr/src/man/man1/dis.1
+++ b/usr/src/man/man1/dis.1
@@ -44,7 +44,7 @@
.\" Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved
.\"
-.TH DIS 1 "Aug 24, 2009"
+.TH DIS 1 "Dec 19, 2018"
.SH NAME
dis \- object code disassembler
.SH SYNOPSIS
@@ -74,7 +74,7 @@ The following options are supported:
\fB\fB-C\fR\fR
.ad
.RS 15n
-Displays demangled C++ symbol names in the disassembly.
+Displays demangled symbol names in the disassembly.
.RE
.sp
diff --git a/usr/src/man/man1/dump.1 b/usr/src/man/man1/dump.1
index 50540b462d..ebe40fe09a 100644
--- a/usr/src/man/man1/dump.1
+++ b/usr/src/man/man1/dump.1
@@ -3,7 +3,7 @@
.\" 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]
-.TH DUMP 1 "Sep 6, 2002"
+.TH DUMP 1 "Dec 19, 2018"
.SH NAME
dump \- dump selected parts of an object file
.SH SYNOPSIS
@@ -65,7 +65,7 @@ Dumps the string table(s).
\fB\fB-C\fR\fR
.ad
.RS 20n
-Dumps decoded C++ symbol table names.
+Dumps decoded symbol table names.
.RE
.sp
diff --git a/usr/src/man/man1/elfdump.1 b/usr/src/man/man1/elfdump.1
index c27e7aef0b..01a9963189 100644
--- a/usr/src/man/man1/elfdump.1
+++ b/usr/src/man/man1/elfdump.1
@@ -11,7 +11,7 @@
.\" 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]
-.TH ELFDUMP 1 "Apr 3, 2009"
+.TH ELFDUMP 1 "Dec 19, 2018"
.SH NAME
elfdump \- dumps selected parts of an object file
.SH SYNOPSIS
@@ -111,7 +111,7 @@ Dumps section header information.
\fB\fB-C\fR\fR
.ad
.RS 18n
-Demangles C++ symbol names.
+Demangles symbol names.
.RE
.sp
diff --git a/usr/src/man/man1/gprof.1 b/usr/src/man/man1/gprof.1
index 4e2d0bf807..a6bfc0f2b4 100644
--- a/usr/src/man/man1/gprof.1
+++ b/usr/src/man/man1/gprof.1
@@ -3,7 +3,7 @@
.\" 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]
-.TH GPROF 1 "Feb 8, 2007"
+.TH GPROF 1 "Dec 19, 2018"
.SH NAME
gprof \- display call-graph profile data
.SH SYNOPSIS
@@ -109,7 +109,7 @@ shared objects' text segments are not examined.
\fB\fB-C\fR\fR
.ad
.RS 19n
-Demangle C++ symbol names before printing them out.
+Demangle symbol names before printing them out.
.RE
.sp
diff --git a/usr/src/man/man1/mdb.1 b/usr/src/man/man1/mdb.1
index e93f822a81..e197836a1c 100644
--- a/usr/src/man/man1/mdb.1
+++ b/usr/src/man/man1/mdb.1
@@ -1,11 +1,11 @@
'\" te
.\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved.
-.\" Copyright (c) 2017, Joyent, Inc. All Rights Reserved.
+.\" Copyright (c) 2019, Joyent, Inc. All Rights Reserved.
.\" Copyright (c) 2014, 2017 by Delphix. All rights reserved.
.\" 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]
-.TH MDB 1 "Dec 9, 2017"
+.TH MDB 1 "Feb 21, 2019"
.SH NAME
mdb \- modular debugger
.SH SYNOPSIS
@@ -1346,7 +1346,7 @@ N newline
O octal unsigned int (4 bytes)
P symbol (4 or 8 bytes)
Q octal signed int (4 bytes)
-R binary int (8 bytes)
+R binary unsigned long long (8 bytes)
S T{
string using C string notation (variable size)
T}
@@ -1369,6 +1369,7 @@ f float (4 bytes)
g octal signed long long (8 bytes)
h swap bytes (2 bytes)
i disassembled instruction (variable size)
+j jazzed-up binary unsigned long long (8 bytes)
n newline
o octal unsigned short (2 bytes)
p symbol (4 or 8 bytes)
diff --git a/usr/src/man/man1/nm.1 b/usr/src/man/man1/nm.1
index 23c1757ee1..880e92ebf7 100644
--- a/usr/src/man/man1/nm.1
+++ b/usr/src/man/man1/nm.1
@@ -43,25 +43,25 @@
.\" Copyright 1989 AT&T
.\" Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved
.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright 2019, Joyent, Inc.
.\"
-.TH NM 1 "Sep 10, 2013"
+.TH NM 1 "March 26, 2019"
.SH NAME
nm \- print name list of an object file
.SH SYNOPSIS
.LP
.nf
-\fB/usr/bin/nm\fR [\fB-ACDhlnPprRsTuVv\fR] [\fB-efox\fR] [\fB-g\fR | \fB-u\fR]
+\fB/usr/bin/nm\fR [\fB-ACDhilnPprRsTuVv\fR] [\fB-efox\fR] [\fB-g\fR | \fB-u\fR]
[\fB-t\fR \fIformat\fR] \fIfile\fR...
.fi
.LP
.nf
-\fB/usr/xpg4/bin/nm\fR [\fB-ACDhlnPprRsTuVv\fR] [\fB-efox\fR] [\fB-g\fR | \fB-u\fR]
+\fB/usr/xpg4/bin/nm\fR [\fB-ACDhilnPprRsTuVv\fR] [\fB-efox\fR] [\fB-g\fR | \fB-u\fR]
[\fB-t\fR \fIformat\fR] \fIfile\fR...
.fi
.SH DESCRIPTION
-.sp
.LP
The \fBnm\fR utility displays the symbol table of each \fBELF\fR object file
that is specified by \fIfile\fR.
@@ -70,7 +70,6 @@ that is specified by \fIfile\fR.
If no symbolic information is available for a valid input file, the \fBnm\fR
utility reports that fact, but not consider it an error condition.
.SH OPTIONS
-.sp
.LP
The output of \fBnm\fR can be controlled using the following options:
.sp
@@ -88,7 +87,7 @@ Writes the full path name or library name of an object on each line.
\fB\fB-C\fR\fR
.ad
.RS 13n
-Demangles C++ symbol names before printing them out.
+Demangles symbol names before printing them out.
.RE
.sp
@@ -109,7 +108,7 @@ by \fBld.so.1\fR and is present even in stripped dynamic executables. If
\fB\fB-e\fR\fR
.ad
.RS 13n
-See NOTES below.
+This option has been deprecated. For more information, see \fBNOTES\fR below.
.RE
.sp
@@ -118,7 +117,7 @@ See NOTES below.
\fB\fB-f\fR\fR
.ad
.RS 13n
-See NOTES below.
+This option has been deprecated. For more information, see \fBNOTES\fR below.
.RE
.sp
@@ -156,6 +155,15 @@ information.
.sp
.ne 2
.na
+\fB\fB-i\fR\fR
+.ad
+.RS 13n
+Display symbols in the existing symbol table order, do not sort the symbols.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fB-l\fR\fR
.ad
.RS 13n
@@ -392,11 +400,10 @@ The offset is written in hexadecimal.
\fB\fB-T\fR\fR
.ad
.RS 13n
-See \fBNOTES\fR.
+This option has been deprecated. For more information, see \fBNOTES\fR below.
.RE
.SS "/usr/bin/nm"
-.sp
.ne 2
.na
\fB\fB-u\fR\fR
@@ -406,7 +413,6 @@ Prints undefined symbols only.
.RE
.SS "/usr/xpg4/bin/nm"
-.sp
.ne 2
.na
\fB\fB-u\fR\fR
@@ -452,7 +458,6 @@ appear anywhere in the command line. When conflicting options are specified
and the second ignored with a warning message to the user. (See \fB-R\fR for
exception.)
.SH OPERANDS
-.sp
.LP
The following operand is supported:
.sp
@@ -465,11 +470,9 @@ A path name of an object file, executable file or object-file library.
.RE
.SH OUTPUT
-.sp
.LP
This section describes the \fBnm\fR utility's output options.
.SS "Standard Output"
-.sp
.LP
For each symbol, the following information is printed:
.sp
@@ -814,13 +817,11 @@ following symbols:
If \fB-P\fR is specified, but \fB-t\fR is not, the format is as if \fB-t\fR
\fBx\fR had been specified.
.SH ENVIRONMENT VARIABLES
-.sp
.LP
See \fBenviron\fR(5) for descriptions of the following environment variables
that affect the execution of \fBnm\fR: \fBLANG\fR, \fBLC_ALL\fR,
\fBLC_COLLATE\fR, \fBLC_CTYPE\fR, \fBLC_MESSAGES\fR, and \fBNLSPATH\fR.
.SH EXIT STATUS
-.sp
.LP
The following exit values are returned:
.sp
@@ -842,13 +843,9 @@ An error occurred.
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.SH /USR/XPG4/BIN/NM
-.sp
-
-.sp
.TS
box;
c | c
@@ -859,13 +856,11 @@ Interface Stability Committed
.TE
.SH SEE ALSO
-.sp
.LP
\fBar\fR(1), \fBas\fR(1), \fBdump\fR(1), \fBld\fR(1), \fBld.so.1\fR(1),
\fBar.h\fR(3HEAD), \fBa.out\fR(4), \fBattributes\fR(5), \fBenviron\fR(5),
\fBstandards\fR(5)
.SH NOTES
-.sp
.LP
The following options are obsolete because of changes to the object file format
and might be deleted in a future release.
diff --git a/usr/src/man/man1/pvs.1 b/usr/src/man/man1/pvs.1
index 8304261cd3..9375613b36 100644
--- a/usr/src/man/man1/pvs.1
+++ b/usr/src/man/man1/pvs.1
@@ -4,7 +4,7 @@
.\" 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]
-.TH PVS 1 "Sep 25, 2008"
+.TH PVS 1 "Dec 19, 2018"
.SH NAME
pvs \- display the internal version information of dynamic objects
.SH SYNOPSIS
@@ -63,7 +63,7 @@ options are specified, both are enabled.
\fB\fB-C\fR\fR
.ad
.RS 18n
-Demangles C++ symbol names.
+Demangles symbol names.
.RE
.sp
diff --git a/usr/src/man/man1m/Makefile b/usr/src/man/man1m/Makefile
index 66926a9e08..68b68b8d00 100644
--- a/usr/src/man/man1m/Makefile
+++ b/usr/src/man/man1m/Makefile
@@ -538,7 +538,8 @@ _MANFILES= 6to4relay.1m \
zoneadmd.1m \
zonecfg.1m \
zpool.1m \
- zstreamdump.1m
+ zstreamdump.1m \
+ ztest.1m
i386_MANFILES= \
acpidump.1m \
diff --git a/usr/src/man/man1m/ipadm.1m b/usr/src/man/man1m/ipadm.1m
index 9935c346e9..0381aa130d 100644
--- a/usr/src/man/man1m/ipadm.1m
+++ b/usr/src/man/man1m/ipadm.1m
@@ -13,6 +13,7 @@
.\" Copyright (c) 2013 by Delphix. All rights reserved.
.\" Copyright 2018 Nexenta Systems, Inc.
.\" Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
+.\" Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
.\"
.Dd February 6, 2018
.Dt IPADM 1M
@@ -788,6 +789,17 @@ Packet forwarding
.Pq Cm on Ns / Ns Cm off .
.It Cm hoplimit
The IPv6 hoplimit.
+.It Cm hostmodel
+IP packet handling on multi-homed systems
+.Pq Cm weak Ns / Ns Cm strong Ns / Ns Cm src-priority
+.Pq IPv4/IPv6 .
+.Cm weak
+and
+.Cm strong
+correspond to the model definitions defined in RFC 1122.
+.Cm src-priority
+is a hybrid mode where outbound packets are sent from the interface with the
+packet's source address if possible.
.It Cm largest_anon_port
Largest ephemeral port
.Pq SCTP/TCP/UDP .
diff --git a/usr/src/man/man1m/savecore.1m b/usr/src/man/man1m/savecore.1m
index e88ffbf8bc..28eee7cbba 100644
--- a/usr/src/man/man1m/savecore.1m
+++ b/usr/src/man/man1m/savecore.1m
@@ -2,17 +2,17 @@
.\" Copyright (c) 2004, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 1983 Regents of the University of California. All rights reserved. The Berkeley software License Agreement specifies the terms and conditions for redistribution.
.\" Copyright 2013 Nexenta Systems, Inc. All Rights Reserved.
-.TH SAVECORE 1M "Jan 30, 2013"
+.\" Copyright 2019 Joyent, Inc.
+.TH SAVECORE 1M "February 22, 2019"
.SH NAME
savecore \- save a crash dump of the operating system
.SH SYNOPSIS
.LP
.nf
-\fB/usr/bin/savecore\fR [\fB-Lvd\fR] [\fB-f\fR \fIdumpfile\fR] [\fIdirectory\fR]
+\fB/usr/bin/savecore\fR [\fB-L\fR | \fB-r\fR] [\fB-vd\fR] [\fB-f\fR \fIdumpfile\fR] [\fIdirectory\fR]
.fi
.SH DESCRIPTION
-.sp
.LP
The \fBsavecore\fR utility saves a crash dump of the kernel (assuming that one
was made) and writes a reboot message in the shutdown log. By default, it is
@@ -42,7 +42,6 @@ The \fBsavecore\fR utility also logs a reboot message using facility
\fBLOG_AUTH\fR (see \fBsyslog\fR(3C)). If the system crashed as a result of a
panic, \fBsavecore\fR logs the panic string too.
.SH OPTIONS
-.sp
.LP
The following options are supported:
.sp
@@ -90,6 +89,18 @@ are not fully self-consistent.
.sp
.ne 2
.na
+\fB\fB-r\fR\fR
+.ad
+.RS 15n
+Open the dump device or file as read-only, and don't update the dump header
+or do anything else that might modify the crash dump. This option can be used
+to recover a crash dump from a read-only device. This flag cannot be used in
+conjunction with \fB\fB-L\fR\fR.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fB-v\fR\fR
.ad
.RS 15n
@@ -97,7 +108,6 @@ Verbose. Enables verbose error messages from \fBsavecore\fR.
.RE
.SH OPERANDS
-.sp
.LP
The following operands are supported:
.sp
@@ -112,7 +122,6 @@ specified, \fBsavecore\fR saves the crash dump files to the default
.RE
.SH FILES
-.sp
.ne 2
.na
\fB\fIdirectory\fR\fB/vmdump.\fR\fIn\fR\fR
@@ -167,12 +176,10 @@ default crash dump directory
.RE
.SH SEE ALSO
-.sp
.LP
\fBadb\fR(1), \fBmdb\fR(1), \fBsvcs\fR(1), \fBdd\fR(1M), \fBdumpadm\fR(1M),
\fBsvcadm\fR(1M), \fBsyslog\fR(3C), \fBattributes\fR(5), \fBsmf\fR(5)
.SH NOTES
-.sp
.LP
The system crash dump service is managed by the service management facility,
\fBsmf\fR(5), under the service identifier:
diff --git a/usr/src/man/man1m/zfs.1m b/usr/src/man/man1m/zfs.1m
index 104d58a1c2..806cd8c838 100644
--- a/usr/src/man/man1m/zfs.1m
+++ b/usr/src/man/man1m/zfs.1m
@@ -23,14 +23,13 @@
.\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org>
.\" Copyright (c) 2011, 2016 by Delphix. All rights reserved.
.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
-.\" Copyright (c) 2015, Joyent, Inc. All rights reserved.
.\" Copyright (c) 2014 by Adam Stevko. All rights reserved.
.\" Copyright (c) 2014 Integros [integros.com]
.\" Copyright 2018 Nexenta Systems, Inc.
-.\" Copyright 2018 Joyent, Inc.
+.\" Copyright 2019 Joyent, Inc.
.\" Copyright (c) 2018 Datto Inc.
.\"
-.Dd Jan 05, 2019
+.Dd February 26, 2019
.Dt ZFS 1M
.Os
.Sh NAME
@@ -3496,6 +3495,7 @@ Channel programs may only be run with root privileges.
.sp
For full documentation of the ZFS channel program interface, see the manual
page for
+.Xr zfs-program 1M .
.Bl -tag -width ""
.It Fl j
Display channel program output in JSON format.
@@ -3921,6 +3921,7 @@ M F /tank/test/modified
.Xr share 1M ,
.Xr sharemgr 1M ,
.Xr unshare 1M ,
+.Xr zfs-program 1M ,
.Xr zonecfg 1M ,
.Xr zpool 1M ,
.Xr chmod 2 ,
diff --git a/usr/src/man/man1m/zpool.1m b/usr/src/man/man1m/zpool.1m
index 9e7f36afed..52d68929f1 100644
--- a/usr/src/man/man1m/zpool.1m
+++ b/usr/src/man/man1m/zpool.1m
@@ -175,6 +175,9 @@
.Oo Ar pool Oc Ns ...
.Op Ar interval Op Ar count
.Nm
+.Cm sync
+.Oo Ar pool Oc Ns ...
+.Nm
.Cm upgrade
.Nm
.Cm upgrade
@@ -1779,6 +1782,19 @@ Warnings about pools not using the latest on-disk format will not be included.
.El
.It Xo
.Nm
+.Cm sync
+.Oo Ar pool Oc Ns ...
+.Xc
+Forces all in-core dirty data to be written to the primary pool storage and
+not the ZIL.
+It will also update administrative information including quota reporting.
+Without arguments,
+.Nm zpool Cm sync
+will sync all pools on the system.
+Otherwise, it will only sync the specified
+.Ar pool .
+.It Xo
+.Nm
.Cm upgrade
.Xc
Displays pools which do not have all supported features enabled and pools
diff --git a/usr/src/man/man1m/ztest.1m b/usr/src/man/man1m/ztest.1m
new file mode 100755
index 0000000000..065f88e52c
--- /dev/null
+++ b/usr/src/man/man1m/ztest.1m
@@ -0,0 +1,169 @@
+.\" $NetBSD: ztest.1,v 1.4 2018/12/10 03:58:30 sevan Exp $
+.\"
+.\" Copyright (c) 2018 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Sevan Janiyan <sevan@NetBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"/
+.Dd December 10, 2018
+.Dt ZTEST 1M
+.Os
+.Sh NAME
+.Nm ztest
+.Nd ZFS stress test utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl EhV
+.Op Fl a Ar shift
+.Op Fl B Ar path
+.Op Fl d Ar datasets
+.Op Fl F Ar loops
+.Op Fl f Ar path
+.Op Fl g Ar threshold
+.Op Fl i Ar count
+.Op Fl k Ar percent
+.Op Fl m Ar copies
+.Op Fl P Ar passtime
+.Op Fl p Ar name
+.Op Fl R Ar parity
+.Op Fl r Ar disks
+.Op Fl s Ar size
+.Op Fl T Ar time
+.Op Fl t Ar threads
+.Op Fl v Ar vdevs
+.Sh DESCRIPTION
+The
+.Nm
+utility stress tests the DMU, ZAP, SPA components of ZFS from user space.
+.Pp
+.Nm
+provides a simple routine to test the functionality of a component task.
+These simple routines can then be used to stress test through parallel
+execution.
+Tests are run as child processes of the main process.
+.Pp
+The checksum and compression functions are changed each time a dataset is
+opened to introduce varying combinations of checksum and compression from block
+to block among objects.
+.Pp
+While tests are running, faults are injected into the pool to verify
+self-healing ability.
+.Pp
+To verify that the on-disk consistency is never lost after a crash, child
+processes are killed at random with a SIGKILL signal, after which the parent
+process invokes a new child to run the test again on the same storage pool.
+.Pp
+Many of the tests record the transaction group number as part of their data.
+When reading old data, tests verify that the transaction group number is less
+than the current, open state, transaction group to ensure the consistency of
+tests and detect unaccounted changes.
+It is advised that any new tests added to
+.Nm
+should also perform the same check with transaction group numbers, if
+applicable.
+.Pp
+The main
+.Nm
+process uses an
+.Xr mmap 2
+temporary file to pass information to child processes which allows shared
+memory to survive
+.Xr exec 3
+syscall.
+A copy of the
+.Vt ztest_shared_hdr_t
+struct containing information on the size and number of shared
+structures in the file is always stored at offset 0 of the file.
+.Pp
+For backwards compatibility testing
+.Nm
+can invoke an alternative version of
+.Nm
+after a
+.Dv SIGKILL
+signal using the
+.Fl B
+flag.
+.Pp
+The following options are available:
+.Bl -tag -width 5n
+.It Fl a Ar shift
+alignment shift (default: 9) use 0 for random
+.It Fl B Ar path
+alt ztest (default: <none>) alternate ztest path
+.It Fl d Ar datasets
+datasets (default: 7)
+.It Fl E
+use existing pool instead of creating new one
+.It Fl F Ar loops
+freezeloops (default: 50) max loops in
+.Fn spa_freeze
+.It Fl f Ar path
+dir (default:
+.Pa /tmp )
+file directory for vdev files
+.It Fl g Ar threshold
+gang block threshold (default: 32K)
+.It Fl h
+print help
+.It Fl i Ar count
+init count (default: 1) initialize pool
+.Ar count
+times
+.It Fl k Ar percent
+kill percentage (default: 70%)
+.It Fl m Ar copies
+mirror copies (default: 2)
+.It Fl P Ar passtime
+passtime (default: 60 sec) time per pass
+.It Fl p Ar name
+pool name (default: ztest)
+.It Fl R Ar parity
+raidz parity (default: 1)
+.It Fl r Ar disks
+raidz disks (default: 4)
+.It Fl s Ar size
+size of each vdev (default: 256M)
+.It Fl T Ar time
+time (default: 300 sec) total run time
+.It Fl t Ar threads
+threads (default: 23)
+.It Fl V
+verbose (use multiple times to increase verbosity)
+.It Fl v Ar vdevs
+number of vdevs (default: 5)
+.El
+.Sh AUTHORS
+This man page was written by
+.An Sevan Janiyan
+.Aq Mt sevan@NetBSD.org .
+.Sh CAVEATS
+To allow for backward compatibility testing using older versions of
+.Nm
+the information stored in the
+.Xr mmap 2
+temporary file passed from parent process to child must
+remain compatible with older versions of
+.Nm .
diff --git a/usr/src/man/man3c/sigfpe.3c b/usr/src/man/man3c/sigfpe.3c
index 5f40071c75..2067e19301 100644
--- a/usr/src/man/man3c/sigfpe.3c
+++ b/usr/src/man/man3c/sigfpe.3c
@@ -17,7 +17,6 @@ sigfpe \- signal handling for specific SIGFPE codes
.fi
.SH DESCRIPTION
-.sp
.LP
The \fBsigfpe()\fR function allows signal handling to be specified for
particular \fBSIGFPE\fR codes. A call to \fBsigfpe()\fR defines a new handler
@@ -41,6 +40,15 @@ FPE_FLTOVF fp_overflow \(mi floating-point overflow
FPE_FLTINV fp_invalid \(mi floating-point invalid operation
.fi
.in -2
+.LP
+And additionally on the x86 architecture:
+.sp
+.in +2
+.nf
+FPE_FLTDEN fp_denormalized \(mi floating-point denormalized result
+.fi
+.in -2
+
.sp
.LP
@@ -140,7 +148,6 @@ main(void) {
.in -2
.SH FILES
-.sp
.ne 2
.na
\fB\fB/usr/include/floatingpoint.h\fR\fR
@@ -161,7 +168,6 @@ main(void) {
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
@@ -177,12 +183,10 @@ MT-Level Safe
.TE
.SH SEE ALSO
-.sp
.LP
\fBsigaction\fR(2), \fBabort\fR(3C), \fBsignal\fR(3C), \fBattributes\fR(5),
\fBfloatingpoint.h\fR(3HEAD)
.SH DIAGNOSTICS
-.sp
.LP
The \fBsigfpe()\fR function returns (void(*)())-1 if \fIcode\fR is not zero or
a defined \fBSIGFPE\fR code.
diff --git a/usr/src/man/man3lib/libproc.3lib b/usr/src/man/man3lib/libproc.3lib
index 15b69e52d4..94ddc8b558 100644
--- a/usr/src/man/man3lib/libproc.3lib
+++ b/usr/src/man/man3lib/libproc.3lib
@@ -10,8 +10,10 @@
.\"
.\"
.\" Copyright 2018 Joyent, Inc.
+.\" Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+.\" Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
.\"
-.Dd September 15, 2018
+.Dd February 22, 2019
.Dt LIBPROC 3LIB
.Os
.Sh NAME
@@ -306,19 +308,19 @@ library.
.It Sy Perror_printf Ta Sy proc_arg_grab
.It Sy proc_arg_psinfo Ta Sy proc_arg_xgrab
.It Sy proc_arg_xpsinfo Ta Sy proc_content2str
-.It Sy proc_finistdio Ta Sy proc_fltname
-.It Sy proc_fltset2str Ta Sy proc_flushstdio
-.It Sy proc_get_auxv Ta Sy proc_get_cred
-.It Sy proc_get_priv Ta Sy proc_get_psinfo
-.It Sy proc_get_status Ta Sy proc_initstdio
-.It Sy proc_lwp_in_set Ta Sy proc_lwp_range_valid
-.It Sy proc_signame Ta Sy proc_sigset2str
-.It Sy proc_str2content Ta Sy proc_str2flt
-.It Sy proc_str2fltset Ta Sy proc_str2sig
-.It Sy proc_str2sigset Ta Sy proc_str2sys
-.It Sy proc_str2sysset Ta Sy proc_sysname
-.It Sy proc_sysset2str Ta Sy proc_unctrl_psinfo
-.It Sy proc_walk Ta ""
+.It Sy proc_dmodelname Ta Sy proc_finistdio
+.It Sy proc_fltname Ta Sy proc_fltset2str
+.It Sy proc_flushstdio Ta Sy proc_proc_get_auxv
+.It Sy proc_get_cred Ta Sy proc_get_priv
+.It Sy proc_get_psinfo Ta Sy proc_get_status
+.It Sy proc_get_initstdio Ta Sy proc_lwp_in_set
+.It Sy proc_lwp_range_valid Ta Sy proc_signame
+.It Sy proc_sigset2str Ta Sy proc_str2content
+.It Sy proc_str2flt Ta Sy proc_str2fltset
+.It Sy proc_str2sig Ta Sy proc_str2sigset
+.It Sy proc_str2sys Ta Sy proc_str2sysset
+.It Sy proc_sysname Ta Sy proc_sysset2str
+.It Sy proc_unctrl_psinfo Ta ""
.El
.Ss x86 Specific Routines
The following routines are specific to the x86, 32-bit and 64-bit,
@@ -1218,6 +1220,7 @@ changes may occur which break both source and binary compatibility.
.Xr proc_arg_xgrab 3PROC ,
.Xr proc_arg_xpsinfo 3PROC ,
.Xr proc_content2str 3PROC ,
+.Xr proc_dmodelname 3PROC ,
.Xr proc_finistdio 3PROC ,
.Xr proc_fltname 3PROC ,
.Xr proc_fltset2str 3PROC ,
diff --git a/usr/src/man/man3proc/Makefile b/usr/src/man/man3proc/Makefile
index e59e81fbf3..00403a19fa 100644
--- a/usr/src/man/man3proc/Makefile
+++ b/usr/src/man/man3proc/Makefile
@@ -13,7 +13,8 @@
# Copyright 2011, Richard Lowe
# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
-#
+# Copyright 2019, Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
include $(SRC)/Makefile.master
@@ -220,6 +221,7 @@ MANLINKS= \
Pread_string.3proc \
proc_arg_xgrab.3proc \
proc_arg_xpsinfo.3proc \
+ proc_dmodelname.3proc \
proc_finistdio.3proc \
proc_flushstdio.3proc \
proc_free_priv.3proc \
@@ -395,6 +397,7 @@ proc_str2content.3proc := LINKSRC = proc_content2str.3proc
proc_flushstdio.3proc := LINKSRC = proc_initstdio.3proc
proc_finistdio.3proc := LINKSRC = proc_initstdio.3proc
+proc_dmodelname.3proc := LINKSRC = proc_fltname.3proc
proc_signame.3proc := LINKSRC = proc_fltname.3proc
proc_sysname.3proc := LINKSRC = proc_fltname.3proc
diff --git a/usr/src/man/man3proc/proc_fltname.3proc b/usr/src/man/man3proc/proc_fltname.3proc
index 1dc563b714..f3f4a45aa0 100644
--- a/usr/src/man/man3proc/proc_fltname.3proc
+++ b/usr/src/man/man3proc/proc_fltname.3proc
@@ -10,6 +10,8 @@
.\"
.\"
.\" Copyright 2015 Joyent, Inc.
+.\" Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+.\" Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
.\"
.Dd May 11, 2016
.Dt PROC_FLTNAME 3PROC
@@ -17,8 +19,9 @@
.Sh NAME
.Nm proc_fltname ,
.Nm proc_signame ,
-.Nm proc_sysname
-.Nd convert a fault, signal, and system call to a name
+.Nm proc_sysname ,
+.Nm proc_dmodelname
+.Nd convert a fault, signal, system call and data model to a name
.Sh SYNOPSIS
.Lb libproc
.In libproc.h
@@ -40,17 +43,25 @@
.Fa "char *buf"
.Fa "size_t bufsz"
.Fc
+.Ft "char *"
+.Fo proc_dmodelname
+.Fa "int dmodel"
+.Fa "char *buf"
+.Fa "size_t bufsz"
+.Fc
.Sh DESCRIPTION
The
.Fn proc_fltname ,
.Fn proc_signame ,
-and
.Fn proc_sysname
-functions respectively convert the fault, signal, and system call in
+and
+.Fn proc_dmodelname
+functions respectively convert the fault, signal, system call and data model in
.Fa flt ,
.Fa sig ,
-and
.Fa sys
+and
+.Fa dmodel
to a human-readable name and place the corresponding string in
.Fa buf .
Up to
@@ -61,8 +72,9 @@ characters, including the null terminator, will be written into
Upon successful completion, the
.Fn proc_fltname ,
.Fn proc_signame ,
-and
.Fn proc_sysname
+and
+.Fn proc_dmodelname
functions return a pointer to
.Fa buf .
The contents of
diff --git a/usr/src/man/man4/nsmbrc.4 b/usr/src/man/man4/nsmbrc.4
index 2468be8f28..5eaffa9f63 100644
--- a/usr/src/man/man4/nsmbrc.4
+++ b/usr/src/man/man4/nsmbrc.4
@@ -3,7 +3,8 @@
.\" 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]
-.TH NSMBRC 4 "Dec 8, 2008"
+.\" Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+.TH NSMBRC 4 "May 8, 2018"
.SH NAME
nsmbrc \- configuration file for Solaris CIFS client requests
.SH SYNOPSIS
@@ -13,7 +14,6 @@ nsmbrc \- configuration file for Solaris CIFS client requests
.fi
.SH DESCRIPTION
-.sp
.LP
Global behavior of the Solaris CIFS client is defined by property values that
are stored in the Service Management Facility (SMF). The \fB\&.nsmbrc\fR file
@@ -137,6 +137,32 @@ value is \fBntlm\fR.
.sp
.ne 2
.na
+\fB\fBmin_protocol\fR\fR
+.ad
+.sp .6
+.RS 4n
+Is the minimum SMB protocol level that will be negotiated,
+which must be one of: \fB1\fR, \fB2.1\fR
+This property can only be set in the default and server sections.
+The default value is \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmax_protocol\fR\fR
+.ad
+.sp .6
+.RS 4n
+Is the maximum SMB protocol level that will be negotiated,
+which must be one of: \fB1\fR, \fB2.1\fR
+This property can only be set in the default and server sections.
+The default value is \fB2.1\fR.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBnbns\fR\fR
.ad
.sp .6
@@ -254,7 +280,6 @@ property. Use the \fBdomain\fR property instead.
.RE
.SH EXAMPLES
-.sp
.LP
The examples in this section show how to use the \fB\&.nsmbrc\fR file and the
\fBsmbutil\fR command to configure the \fBex.com\fR environment.
@@ -360,7 +385,6 @@ shown are those set by the previous example.
.sp
.SH FILES
-.sp
.ne 2
.na
\fB\fB$HOME/.nsmbrc\fR\fR
@@ -372,7 +396,6 @@ connection.
.RE
.SH ATTRIBUTES
-.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
@@ -388,13 +411,11 @@ Interface Stability Committed
.TE
.SH SEE ALSO
-.sp
.LP
\fBsmbutil\fR(1), \fBmount_smbfs\fR(1M), \fBsharectl\fR(1M),
\fBnsswitch.conf\fR(4), \fBuser_attr\fR(4), \fBattributes\fR(5), \fBrbac\fR(5),
\fBsmbfs\fR(7FS)
.SH NOTES
-.sp
.LP
By default, passwords stored in the \fB\&.nsmbrc\fR file are ignored unless
\fBonly\fR the file owner has read and write permission.
diff --git a/usr/src/man/man5/smf_method.5 b/usr/src/man/man5/smf_method.5
index 71a595aea0..4815a7196a 100644
--- a/usr/src/man/man5/smf_method.5
+++ b/usr/src/man/man5/smf_method.5
@@ -1,9 +1,10 @@
'\" te
+.\" Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
.\" 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]
-.TH SMF_METHOD 5 "June 6, 2016"
+.TH SMF_METHOD 5 "February 25, 2019"
.SH NAME
smf_method \- service management framework conventions for methods
.SH DESCRIPTION
@@ -269,6 +270,10 @@ l l l .
\fBSMF_EXIT_OK\fR \fB0\fR T{
Method exited, performing its operation successfully.
T}
+\fBSMF_EXIT_NODAEMON\fR \fB94\fR T{
+Method exited successfully but purposefully leaves no processes remaining in
+the contract; it should be treated as if it had a transient service model.
+T}
\fBSMF_EXIT_ERR_FATAL\fR \fB95\fR T{
Method failed fatally and is unrecoverable without administrative intervention.
T}
diff --git a/usr/src/man/man9e/open.9e b/usr/src/man/man9e/open.9e
index 94ac13d2d3..9f5e4ae797 100644
--- a/usr/src/man/man9e/open.9e
+++ b/usr/src/man/man9e/open.9e
@@ -1,10 +1,11 @@
'\" te
.\" Copyright 1989 AT&T
.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright 2019, Joyent, Inc.
.\" 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]
-.TH OPEN 9E "Apr 24, 2008"
+.TH OPEN 9E "March 7, 2019"
.SH NAME
open \- gain access to a device
.SH SYNOPSIS
@@ -40,13 +41,11 @@ open \- gain access to a device
.fi
.SH INTERFACE LEVEL
-.sp
.LP
Architecture independent level 1 (DDI/DKI). This entry point is required, but
it can be \fBnulldev\fR(9F)
.SH PARAMETERS
.SS "Block and Character"
-.sp
.ne 2
.na
\fB\fIdevp\fR\fR
@@ -163,7 +162,6 @@ Pointer to the user credential structure.
.RE
.SS "STREAMS"
-.sp
.ne 2
.na
\fB\fIq\fR\fR
@@ -244,7 +242,6 @@ Pointer to the user credential structure.
.RE
.SH DESCRIPTION
-.sp
.LP
The driver's \fBopen()\fR function is called by the kernel during an
\fBopen\fR(2) or a \fBmount\fR(2) on the special file for the device. A device
@@ -258,6 +255,13 @@ called. The function should verify that the minor number component of
using the user credentials pointed to by \fIcred_p\fR.
.sp
.LP
+When exclusive access is requested by including the \fBFEXCL\fR flag in
+\fIflag\fR or \fIoflag\fR, if the caller cannot be granted exclusive access
+to the device because it is already open, then the device driver should
+conventionally return \fBEBUSY\fR. If instead, exclusive opens are not
+supported, then the driver should return \fBENOTSUP\fR or \fBEINVAL\fR.
+.sp
+.LP
The kernel provides \fBopen()\fR \fBclose()\fR exclusion guarantees to the
driver at *\fIdevp\fR, \fIotyp\fR granularity. This delays new \fBopen()\fR
calls to the driver while a last-reference \fBclose()\fR call is executing. If
@@ -296,12 +300,10 @@ occurs.
.in -2
.SH RETURN VALUES
-.sp
.LP
The \fBopen()\fR function should return \fB0\fR for success, or the appropriate
error number.
.SH SEE ALSO
-.sp
.LP
\fBclose\fR(2), \fBexit\fR(2), \fBmmap\fR(2), \fBmount\fR(2), \fBmunmap\fR(2),
\fBopen\fR(2), \fBIntro\fR(9E), \fBattach\fR(9E), \fBclose\fR(9E),
@@ -314,7 +316,6 @@ error number.
.LP
\fISTREAMS Programming Guide\fR
.SH WARNINGS
-.sp
.LP
Do not attempt to change the major number.
.sp
diff --git a/usr/src/man/man9e/put.9e b/usr/src/man/man9e/put.9e
index 9d7c47c86f..e91c1a9587 100644
--- a/usr/src/man/man9e/put.9e
+++ b/usr/src/man/man9e/put.9e
@@ -4,7 +4,7 @@
.\" 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]
-.TH PUT 9E "Nov 12, 1992"
+.TH PUT 9E "Mar 21, 2019"
.SH NAME
put \- receive messages from the preceding queue
.SH SYNOPSIS
@@ -18,21 +18,19 @@ put \- receive messages from the preceding queue
-\fBint prefix\fR\fBrput\fR(\fBqueue_t *\fR\fIq\fR, \fBmblk_t\fR \fI*mp\fR/* read side */
+\fBint prefix\fR\fBrput\fR(\fBqueue_t *\fR\fIq\fR, \fBmblk_t\fR \fI*mp\fR); /* read side */
.fi
.LP
.nf
-\fBint prefix\fR\fBwput\fR(\fBqueue_t *\fR\fIq\fR, \fBmblk_t\fR \fI*mp\fR/* write side */
+\fBint prefix\fR\fBwput\fR(\fBqueue_t *\fR\fIq\fR, \fBmblk_t\fR \fI*mp\fR); /* write side */
.fi
.SH INTERFACE LEVEL
-.sp
.LP
Architecture independent level 1 (DDI/DKI). This entry point is required for
\fBSTREAMS. \fR
.SH ARGUMENTS
-.sp
.ne 2
.na
\fB\fIq\fR \fR
@@ -51,7 +49,6 @@ Pointer to the message block.
.RE
.SH DESCRIPTION
-.sp
.LP
The primary task of the \fBput()\fR routine is to coordinate the passing of
messages from one queue to the next in a stream. The \fBput()\fR routine is
@@ -106,15 +103,12 @@ The \fBputq\fR(9F) function can be used as a module's \fBput()\fR routine when
no special processing is required and all messages are to be enqueued for the
\fBsrv\fR(9E) routine.
.SH RETURN VALUES
-.sp
.LP
Ignored.
.SH CONTEXT
-.sp
.LP
\fBput()\fR routines do not have user context.
.SH SEE ALSO
-.sp
.LP
\fBsrv\fR(9E), \fBputctl\fR(9F), \fBputctl1\fR(9F), \fBputnext\fR(9F),
\fBputnextctl\fR(9F), \fBputnextctl1\fR(9F), \fBputq\fR(9F), \fBqreply\fR(9F),
diff --git a/usr/src/man/man9e/srv.9e b/usr/src/man/man9e/srv.9e
index 1d124bf219..54c0e7ebe7 100644
--- a/usr/src/man/man9e/srv.9e
+++ b/usr/src/man/man9e/srv.9e
@@ -4,7 +4,7 @@
.\" 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]
-.TH SRV 9E "Nov 12, 1992"
+.TH SRV 9E "Mar 15, 2019"
.SH NAME
srv \- service queued messages
.SH SYNOPSIS
@@ -18,21 +18,19 @@ srv \- service queued messages
-\fBintprefix\fR\fBrsrv\fR(\fBqueue_t *\fR\fIq\fR/* read side */
+\fBint prefix\fR\fBrsrv\fR(\fBqueue_t *\fR\fIq\fR); /* read side */
.fi
.LP
.nf
-\fBintprefix\fR\fBwsrv\fR(\fBqueue_t *\fR\fIq\fR/* write side */
+\fBint prefix\fR\fBwsrv\fR(\fBqueue_t *\fR\fIq\fR); /* write side */
.fi
.SH INTERFACE LEVEL
-.sp
.LP
Architecture independent level 1 (DDI/DKI). This entry point is required for
\fBSTREAMS\fR.
.SH ARGUMENTS
-.sp
.ne 2
.na
\fB\fIq\fR\fR
@@ -42,7 +40,6 @@ Pointer to the \fBqueue\fR(9S) structure.
.RE
.SH DESCRIPTION
-.sp
.LP
The optional service \fBsrv()\fR routine may be included in a \fBSTREAMS
\fRmodule or driver for many possible reasons, including:
@@ -149,11 +146,9 @@ If the message cannot be passed, put it back on the queue with
\fBputnext()\fR.
.RE
.SH RETURN VALUES
-.sp
.LP
Ignored.
.SH SEE ALSO
-.sp
.LP
\fBput\fR(9E), \fBbcanput\fR(9F), \fBbcanputnext\fR(9F), \fBcanput\fR(9F),
\fBcanputnext\fR(9F), \fBgetq\fR(9F), \fBnulldev\fR(9F), \fBputbq\fR(9F),
@@ -165,7 +160,6 @@ Ignored.
.LP
\fISTREAMS Programming Guide\fR
.SH WARNINGS
-.sp
.LP
Each stream module must specify a read and a write service \fBsrv()\fR routine.
If a service routine is not needed (because the \fBput()\fR routine processes
diff --git a/usr/src/pkg/manifests/system-file-system-zfs.mf b/usr/src/pkg/manifests/system-file-system-zfs.mf
index 6032e99675..3fa15b19f6 100644
--- a/usr/src/pkg/manifests/system-file-system-zfs.mf
+++ b/usr/src/pkg/manifests/system-file-system-zfs.mf
@@ -103,6 +103,7 @@ file path=usr/share/man/man1m/zfs-program.1m
file path=usr/share/man/man1m/zfs.1m
file path=usr/share/man/man1m/zpool.1m
file path=usr/share/man/man1m/zstreamdump.1m
+file path=usr/share/man/man1m/ztest.1m
file path=usr/share/man/man5/zpool-features.5
hardlink path=kernel/fs/$(ARCH64)/zfs target=../../../kernel/drv/$(ARCH64)/zfs
hardlink path=usr/lib/fs/zfs/fstyp target=../../../sbin/fstyp
diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf
index da171532a9..45751547c0 100644
--- a/usr/src/pkg/manifests/system-header.mf
+++ b/usr/src/pkg/manifests/system-header.mf
@@ -1681,6 +1681,7 @@ $(i386_ONLY)file path=usr/platform/i86pc/include/sys/cram.h
$(i386_ONLY)file path=usr/platform/i86pc/include/sys/ddi_subrdefs.h
$(i386_ONLY)file path=usr/platform/i86pc/include/sys/debug_info.h
$(i386_ONLY)file path=usr/platform/i86pc/include/sys/fastboot.h
+$(i386_ONLY)file path=usr/platform/i86pc/include/sys/hma.h
$(i386_ONLY)file path=usr/platform/i86pc/include/sys/ht.h
$(i386_ONLY)file path=usr/platform/i86pc/include/sys/mach_mmu.h
$(i386_ONLY)file path=usr/platform/i86pc/include/sys/machclock.h
diff --git a/usr/src/pkg/manifests/system-library.man3proc.inc b/usr/src/pkg/manifests/system-library.man3proc.inc
index 8528acca7b..0119a81518 100644
--- a/usr/src/pkg/manifests/system-library.man3proc.inc
+++ b/usr/src/pkg/manifests/system-library.man3proc.inc
@@ -11,6 +11,8 @@
#
# Copyright 2018 Joyent, Inc.
+# Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
file path=usr/share/man/man3proc/proc_service.3proc
@@ -229,6 +231,7 @@ link path=usr/share/man/man3proc/pr_stat64.3proc target=pr_stat.3proc
link path=usr/share/man/man3proc/Pread_string.3proc target=Pread.3proc
link path=usr/share/man/man3proc/proc_arg_xgrab.3proc target=proc_arg_grab.3proc
link path=usr/share/man/man3proc/proc_arg_xpsinfo.3proc target=proc_arg_psinfo.3proc
+link path=usr/share/man/man3proc/proc_dmodelname.3proc target=proc_fltname.3proc
link path=usr/share/man/man3proc/proc_finistdio.3proc target=proc_initstdio.3proc
link path=usr/share/man/man3proc/proc_flushstdio.3proc target=proc_initstdio.3proc
link path=usr/share/man/man3proc/proc_free_priv.3proc target=proc_get_priv.3proc
diff --git a/usr/src/pkg/manifests/system-test-elftest.mf b/usr/src/pkg/manifests/system-test-elftest.mf
new file mode 100644
index 0000000000..696fd56652
--- /dev/null
+++ b/usr/src/pkg/manifests/system-test-elftest.mf
@@ -0,0 +1,57 @@
+#
+# 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 2018, Richard Lowe.
+#
+
+set name=pkg.fmri value=pkg:/system/test/elftest@$(PKGVERS)
+set name=pkg.description value="ELF Unit Tests"
+set name=pkg.summary value="ELF Test Suite"
+set name=info.classification \
+ value=org.opensolaris.category.2008:Development/System
+set name=variant.arch value=$(ARCH)
+dir path=opt/elf-tests
+dir path=opt/elf-tests/bin
+dir path=opt/elf-tests/runfiles
+dir path=opt/elf-tests/tests
+dir path=opt/elf-tests/tests/assert-deflib
+dir path=opt/elf-tests/tests/tls
+dir path=opt/elf-tests/tests/tls/amd64
+dir path=opt/elf-tests/tests/tls/amd64/ie
+dir path=opt/elf-tests/tests/tls/amd64/ld
+dir path=opt/elf-tests/tests/tls/i386
+dir path=opt/elf-tests/tests/tls/i386/ld
+file path=opt/elf-tests/README mode=0444
+file path=opt/elf-tests/bin/elftest mode=0555
+file path=opt/elf-tests/runfiles/default.run mode=0444
+file path=opt/elf-tests/tests/assert-deflib/link.c mode=0444
+file path=opt/elf-tests/tests/assert-deflib/test-deflib mode=0555
+file path=opt/elf-tests/tests/tls/amd64/ie/Makefile.test mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/amd64-ie-test mode=0555
+file path=opt/elf-tests/tests/tls/amd64/ie/style1-func-with-r12.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/style1-func-with-r13.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/style1-func.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/style1-main.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/style2-with-badness.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/style2-with-r12.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/style2-with-r13.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ie/style2.s mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ld/Makefile.test mode=0444
+file path=opt/elf-tests/tests/tls/amd64/ld/amd64-ld-test mode=0555
+file path=opt/elf-tests/tests/tls/amd64/ld/ld-with-addend.s mode=0444
+file path=opt/elf-tests/tests/tls/i386/ld/Makefile.test mode=0444
+file path=opt/elf-tests/tests/tls/i386/ld/half-ldm.s mode=0444
+file path=opt/elf-tests/tests/tls/i386/ld/i386-ld-test mode=0555
+license lic_CDDL license=lic_CDDL
+depend fmri=developer/linker type=require
+depend fmri=developer/object-file type=require
+depend fmri=system/test/testrunner type=require
diff --git a/usr/src/pkg/manifests/system-test-utiltest.mf b/usr/src/pkg/manifests/system-test-utiltest.mf
index 5fdd891b11..c72dd147eb 100644
--- a/usr/src/pkg/manifests/system-test-utiltest.mf
+++ b/usr/src/pkg/manifests/system-test-utiltest.mf
@@ -15,6 +15,7 @@
# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
# Copyright 2017 Joyent, Inc.
# Copyright 2017 Jason King.
+# Copyright 2018, Joyent, Inc.
#
set name=pkg.fmri value=pkg:/system/test/utiltest@$(PKGVERS)
@@ -1118,10 +1119,12 @@ file path=opt/util-tests/tests/awk/tests/T.redir mode=0555
file path=opt/util-tests/tests/awk/tests/T.split mode=0555
file path=opt/util-tests/tests/awk/tests/T.sub mode=0555
file path=opt/util-tests/tests/awk/tests/T.system mode=0555
+file path=opt/util-tests/tests/chown_test mode=0555
file path=opt/util-tests/tests/date_test mode=0555
file path=opt/util-tests/tests/demangle/afl-fast mode=0555
file path=opt/util-tests/tests/demangle/gcc-libstdc++ mode=0555
file path=opt/util-tests/tests/demangle/llvm-stdcxxabi mode=0555
+file path=opt/util-tests/tests/demangle/rust mode=0555
file path=opt/util-tests/tests/dis/distest mode=0555
file path=opt/util-tests/tests/dis/i386/32.adx.out mode=0444
file path=opt/util-tests/tests/dis/i386/32.adx.s mode=0444
@@ -1291,6 +1294,18 @@ file path=opt/util-tests/tests/dis/risc-v/tst.supervisor.out mode=0444
file path=opt/util-tests/tests/dis/risc-v/tst.supervisor.s mode=0444
file path=opt/util-tests/tests/dis/sparc/tst.regs.out mode=0444
file path=opt/util-tests/tests/dis/sparc/tst.regs.s mode=0444
+file path=opt/util-tests/tests/files/cout0 mode=0444
+file path=opt/util-tests/tests/files/cout1 mode=0444
+file path=opt/util-tests/tests/files/cout10 mode=0444
+file path=opt/util-tests/tests/files/cout11 mode=0444
+file path=opt/util-tests/tests/files/cout2 mode=0444
+file path=opt/util-tests/tests/files/cout3 mode=0444
+file path=opt/util-tests/tests/files/cout4 mode=0444
+file path=opt/util-tests/tests/files/cout5 mode=0444
+file path=opt/util-tests/tests/files/cout6 mode=0444
+file path=opt/util-tests/tests/files/cout7 mode=0444
+file path=opt/util-tests/tests/files/cout8 mode=0444
+file path=opt/util-tests/tests/files/cout9 mode=0444
file path=opt/util-tests/tests/files/gout0 mode=0444
file path=opt/util-tests/tests/files/gout1 mode=0444
file path=opt/util-tests/tests/files/gout10 mode=0444
diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf
index c4d70e7980..eed3016079 100644
--- a/usr/src/pkg/manifests/system-test-zfstest.mf
+++ b/usr/src/pkg/manifests/system-test-zfstest.mf
@@ -13,7 +13,7 @@
# Copyright (c) 2012, 2017 by Delphix. All rights reserved.
# Copyright 2015, 2016 Nexenta Systems, Inc. All rights reserved.
# Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
# Copyright (c) 2018 Datto Inc.
#
@@ -91,6 +91,7 @@ dir path=opt/zfs-tests/tests/functional/cli_root/zpool_replace
dir path=opt/zfs-tests/tests/functional/cli_root/zpool_scrub
dir path=opt/zfs-tests/tests/functional/cli_root/zpool_set
dir path=opt/zfs-tests/tests/functional/cli_root/zpool_status
+dir path=opt/zfs-tests/tests/functional/cli_root/zpool_sync
dir path=opt/zfs-tests/tests/functional/cli_root/zpool_upgrade
dir path=opt/zfs-tests/tests/functional/cli_root/zpool_upgrade/blockfiles
dir path=opt/zfs-tests/tests/functional/cli_user
@@ -1727,6 +1728,14 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_002_pos \
mode=0555
+file path=opt/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup mode=0555
+file path=opt/zfs-tests/tests/functional/cli_root/zpool_sync/setup mode=0555
+file \
+ path=opt/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos \
+ mode=0555
+file \
+ path=opt/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg \
+ mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_upgrade/blockfiles/zfs-broken-mirror1.dat.bz2 \
mode=0444
@@ -2548,6 +2557,9 @@ file path=opt/zfs-tests/tests/functional/rsend/send-c_volume mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send-c_zstreamdump mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send-cpL_varied_recsize \
mode=0555
+file path=opt/zfs-tests/tests/functional/rsend/send_freeobjects mode=0555
+file path=opt/zfs-tests/tests/functional/rsend/send_realloc_dnode_size \
+ mode=0555
file path=opt/zfs-tests/tests/functional/rsend/setup mode=0555
file path=opt/zfs-tests/tests/functional/scrub_mirror/cleanup mode=0555
file path=opt/zfs-tests/tests/functional/scrub_mirror/default.cfg mode=0444
diff --git a/usr/src/pkg/manifests/system-xopen-xcu4.mf b/usr/src/pkg/manifests/system-xopen-xcu4.mf
index c9de2bb7fa..b7f5733eb4 100644
--- a/usr/src/pkg/manifests/system-xopen-xcu4.mf
+++ b/usr/src/pkg/manifests/system-xopen-xcu4.mf
@@ -38,8 +38,6 @@ file path=usr/xpg4/bin/at group=sys mode=4755
file path=usr/xpg4/bin/awk mode=0555
file path=usr/xpg4/bin/basename mode=0555
file path=usr/xpg4/bin/batch mode=0555
-file path=usr/xpg4/bin/chgrp mode=0555
-file path=usr/xpg4/bin/chown mode=0555
file path=usr/xpg4/bin/cp mode=0555
file path=usr/xpg4/bin/crontab mode=4555
file path=usr/xpg4/bin/ctags mode=0555
@@ -83,6 +81,8 @@ license lic_OSBL_preamble license=lic_OSBL_preamble
link path=usr/xpg4/bin/alias target=../../bin/alias
link path=usr/xpg4/bin/bg target=../../bin/alias
link path=usr/xpg4/bin/cd target=../../bin/alias
+link path=usr/xpg4/bin/chgrp target=../../bin/chgrp
+link path=usr/xpg4/bin/chown target=../../bin/chown
link path=usr/xpg4/bin/command target=../../bin/alias
link path=usr/xpg4/bin/df target=../../sbin/df
link path=usr/xpg4/bin/egrep target=../../bin/grep
diff --git a/usr/src/test/Makefile b/usr/src/test/Makefile
index 9ca989ce57..fa57d36772 100644
--- a/usr/src/test/Makefile
+++ b/usr/src/test/Makefile
@@ -16,7 +16,14 @@
.PARALLEL: $(SUBDIRS)
-SUBDIRS = libc-tests crypto-tests os-tests test-runner util-tests zfs-tests \
- smbclient-tests
+SUBDIRS = \
+ crypto-tests \
+ elf-tests \
+ libc-tests \
+ os-tests \
+ smbclient-tests \
+ test-runner \
+ util-tests \
+ zfs-tests
include Makefile.com
diff --git a/usr/src/test/elf-tests/Makefile b/usr/src/test/elf-tests/Makefile
new file mode 100644
index 0000000000..6669972e13
--- /dev/null
+++ b/usr/src/test/elf-tests/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 2015 Nexenta Systems, Inc. All rights reserved.
+#
+
+.PARALLEL: $(SUBDIRS)
+
+SUBDIRS = cmd doc runfiles tests
+
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/elf-tests/cmd/Makefile b/usr/src/test/elf-tests/cmd/Makefile
new file mode 100644
index 0000000000..ccda4af74e
--- /dev/null
+++ b/usr/src/test/elf-tests/cmd/Makefile
@@ -0,0 +1,38 @@
+#
+# 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 (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+include $(SRC)/test/Makefile.com
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+ROOTBIN = $(ROOTOPTPKG)/bin
+
+PROGS = elftest
+
+CMDS = $(PROGS:%=$(ROOTBIN)/%)
+$(CMDS) := FILEMODE = 0555
+
+all lint clean clobber:
+
+install: $(CMDS)
+
+$(CMDS): $(ROOTBIN)
+
+$(ROOTBIN):
+ $(INS.dir)
+
+$(ROOTBIN)/%: %.ksh
+ $(INS.rename)
diff --git a/usr/src/test/elf-tests/cmd/elftest.ksh b/usr/src/test/elf-tests/cmd/elftest.ksh
new file mode 100644
index 0000000000..b5a0d9b52f
--- /dev/null
+++ b/usr/src/test/elf-tests/cmd/elftest.ksh
@@ -0,0 +1,49 @@
+#!/usr/bin/ksh
+
+#
+# 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 2015 Nexenta Systems, Inc. All rights reserved.
+#
+
+ELF_TESTS="/opt/elf-tests"
+runner="/opt/test-runner/bin/run"
+
+function fail
+{
+ echo $1
+ exit ${2:-1}
+}
+
+function find_runfile
+{
+ typeset distro=default
+
+ [[ -n $distro ]] && echo $ELF_TESTS/runfiles/$distro.run
+}
+
+while getopts c: c; do
+ case $c in
+ 'c')
+ runfile=$OPTARG
+ [[ -f $runfile ]] || fail "Cannot read file: $runfile"
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+[[ -z $runfile ]] && runfile=$(find_runfile)
+[[ -z $runfile ]] && fail "Couldn't determine distro"
+
+$runner -c $runfile
+
+exit $?
diff --git a/usr/src/test/elf-tests/doc/Makefile b/usr/src/test/elf-tests/doc/Makefile
new file mode 100644
index 0000000000..b2d50b7b93
--- /dev/null
+++ b/usr/src/test/elf-tests/doc/Makefile
@@ -0,0 +1,36 @@
+#
+# 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 (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+
+READMES = README
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+
+FILES = $(READMES:%=$(ROOTOPTPKG)/%)
+$(FILES) := FILEMODE = 0444
+
+all: $(READMES)
+
+install: $(ROOTOPTPKG) $(FILES)
+
+clean lint clobber:
+
+$(ROOTOPTPKG):
+ $(INS.dir)
+
+$(ROOTOPTPKG)/%: %
+ $(INS.file)
diff --git a/usr/src/test/elf-tests/doc/README b/usr/src/test/elf-tests/doc/README
new file mode 100644
index 0000000000..ef8ecda914
--- /dev/null
+++ b/usr/src/test/elf-tests/doc/README
@@ -0,0 +1,59 @@
+#
+# 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 (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+#
+
+ELF Software Generation Utilities Unit Test Suite README
+
+1. Building and installing the ELF/SGS Unit Test Suite
+2. Running the ELF/SGS Unit Test Suite
+3. Test results
+
+--------------------------------------------------------------------------------
+
+1. Building and installing the ELF/SGS Unit Test Suite
+
+The ELF/SGS Unit Test Suite runs under the testrunner framework (which can be
+installed as pkg:/system/test/testrunner). To build both the ELF/SGS Unit Test Suite
+and the testrunner without running a full nightly:
+
+ build_machine$ bldenv [-d] <your_env_file>
+ build_machine$ cd $SRC/test
+ build_machine$ dmake install
+ build_machine$ cd $SRC/pkg
+ build_machine$ dmake install
+
+Then set the publisher on the test machine to point to your repository and
+install the ELF/SGS Unit Test Suite.
+
+ test_machine# pkg install pkg:/system/test/elftest
+
+Note, the framework will be installed automatically, as the ELF/SGS Unit Test Suite
+depends on it.
+
+2. Running the ELF/SGS Unit Test Suite
+
+The pre-requisites for running the ELF/SGS Unit Test Suite are:
+ None
+
+Once the pre-requisites are satisfied, simply run the elftest script:
+
+ test_machine$ /opt/elf-tests/bin/elftest
+
+3. Test results
+
+While the ELF/SGS Unit Test Suite is running, one informational line is printed at
+the end of each test, and a results summary is printed at the end of the run.
+The results summary includes the location of the complete logs, which is of the
+form /var/tmp/test_results/<ISO 8601 date>.
diff --git a/usr/src/test/elf-tests/runfiles/Makefile b/usr/src/test/elf-tests/runfiles/Makefile
new file mode 100644
index 0000000000..cf1ac703d7
--- /dev/null
+++ b/usr/src/test/elf-tests/runfiles/Makefile
@@ -0,0 +1,40 @@
+#
+# 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 (c) 2012 by Delphix. All rights reserved.
+# Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+#
+
+include $(SRC)/Makefile.master
+
+SRCS = default.run
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+RUNFILES = $(ROOTOPTPKG)/runfiles
+
+CMDS = $(SRCS:%=$(RUNFILES)/%)
+$(CMDS) := FILEMODE = 0444
+
+all: $(SRCS)
+
+install: $(CMDS)
+
+clean lint clobber:
+
+$(CMDS): $(RUNFILES) $(SRCS)
+
+$(RUNFILES):
+ $(INS.dir)
+
+$(RUNFILES)/%: %
+ $(INS.file)
diff --git a/usr/src/test/elf-tests/runfiles/default.run b/usr/src/test/elf-tests/runfiles/default.run
new file mode 100644
index 0000000000..f1b0c8980a
--- /dev/null
+++ b/usr/src/test/elf-tests/runfiles/default.run
@@ -0,0 +1,37 @@
+
+#
+# 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 2018, Richard Lowe.
+
+[DEFAULT]
+pre =
+verbose = False
+quiet = False
+timeout = 60
+post =
+outputdir = /var/tmp/test_results
+
+[/opt/elf-tests/tests/assert-deflib]
+tests = ['test-deflib']
+
+
+[/opt/elf-tests/tests/tls/amd64/ie]
+arch = i86pc
+tests = ['amd64-ie-test']
+
+[/opt/elf-tests/tests/tls/i386/ld]
+arch = i86pc
+tests = ['i386-ld-test']
+
+[/opt/elf-tests/tests/tls/amd64/ld]
+arch = i86pc
+tests = ['amd64-ld-test']
diff --git a/usr/src/test/elf-tests/tests/Makefile b/usr/src/test/elf-tests/tests/Makefile
new file mode 100644
index 0000000000..e3894ac07d
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/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 (c) 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2018 Joyent, Inc.
+#
+
+SUBDIRS = \
+ assert-deflib \
+ tls
+
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/elf-tests/tests/assert-deflib/Makefile b/usr/src/test/elf-tests/tests/assert-deflib/Makefile
new file mode 100644
index 0000000000..768182efbc
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/assert-deflib/Makefile
@@ -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 2018, Richard Lowe.
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = test-deflib
+
+DATAFILES = link.c
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+TESTDIR = $(ROOTOPTPKG)/tests/assert-deflib
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+DATA = $(DATAFILES:%=$(TESTDIR)/%)
+$(DATA) := FILEMODE = 0444
+
+all: $(PROG)
+
+install: all $(CMDS) $(DATA)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(CLEANFILES)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/cmd/sgs/test/ld/assert-deflib/link.c b/usr/src/test/elf-tests/tests/assert-deflib/link.c
index 823c7a3785..823c7a3785 100644
--- a/usr/src/cmd/sgs/test/ld/assert-deflib/link.c
+++ b/usr/src/test/elf-tests/tests/assert-deflib/link.c
diff --git a/usr/src/cmd/sgs/test/ld/assert-deflib/test-deflib.sh b/usr/src/test/elf-tests/tests/assert-deflib/test-deflib.sh
index cf07c35788..f2f710e0c1 100644
--- a/usr/src/cmd/sgs/test/ld/assert-deflib/test-deflib.sh
+++ b/usr/src/test/elf-tests/tests/assert-deflib/test-deflib.sh
@@ -24,13 +24,15 @@
#
unalias -a
+TESTDIR=$(dirname $0)
+
sh_path=
sh_lib="lib"
sh_lib64="$sh_lib/64"
sh_soname="libld.so.4"
-sh_cc="cc"
+sh_cc="gcc"
sh_cflags="-m32"
-sh_file="link.c"
+sh_file="${TESTDIR}/link.c"
sh_arg0=$(basename $0)
function fatal
@@ -73,8 +75,7 @@ function run
fi
}
-sh_path=$1
-[[ -z "$1" ]] && fatal "<proto root>"
+sh_path=${1:-/}
validate
run "-Wl,-zassert-deflib" 0 \
diff --git a/usr/src/test/elf-tests/tests/tls/Makefile b/usr/src/test/elf-tests/tests/tls/Makefile
new file mode 100644
index 0000000000..d0dc53a033
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/Makefile
@@ -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 (c) 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2018 Joyent, Inc.
+#
+
+SUBDIRS = amd64 i386
+
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/elf-tests/tests/tls/amd64/Makefile b/usr/src/test/elf-tests/tests/tls/amd64/Makefile
new file mode 100644
index 0000000000..c7755dcb5b
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/amd64/Makefile
@@ -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 (c) 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2018 Joyent, Inc.
+#
+
+SUBDIRS = ie ld
+
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/elf-tests/tests/tls/amd64/ie/Makefile b/usr/src/test/elf-tests/tests/tls/amd64/ie/Makefile
new file mode 100644
index 0000000000..7ffb91e837
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/Makefile
@@ -0,0 +1,58 @@
+#
+# 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 2018, Richard Lowe.
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = amd64-ie-test
+
+DATAFILES = \
+ Makefile.test \
+ style1-func-with-r12.s \
+ style1-func-with-r13.s \
+ style1-func.s \
+ style1-main.s \
+ style2-with-badness.s \
+ style2-with-r12.s \
+ style2-with-r13.s \
+ style2.s
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+TESTDIR = $(ROOTOPTPKG)/tests/tls/amd64/ie
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+
+DATA = $(DATAFILES:%=$(TESTDIR)/%)
+$(DATA) := FILEMODE = 0444
+
+all: $(PROG)
+
+install: all $(CMDS) $(DATA)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(CLEANFILES)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/Makefile b/usr/src/test/elf-tests/tests/tls/amd64/ie/Makefile.test
index d4e11255f0..7f08ba0538 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/Makefile
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/Makefile.test
@@ -11,29 +11,21 @@
# Copyright 2012, Richard Lowe.
-include $(SRC)/Makefile.master
+CC = gcc
+CFLAGS = -O1 -m64
-# We have to use GCC, and only GCC. The best way is to ask cw(1) which GCC to use.
-CC_CMD = $(ONBLD_TOOLS)/bin/$(MACH)/cw -_gcc -_compiler
-CC = $(CC_CMD:sh)
-CFLAGS = -O1 -m64
-
-LINK.c = env LD_ALTEXEC=$(PROTO)/usr/bin/amd64/ld $(CC) $(CFLAGS) -o $@ $^
-COMPILE.c = $(CC) $(CFLAGS) -c -o $@ $^
+LINK.c = $(CC) $(CFLAGS) -o $@ $^
COMPILE.s = $(CC) $(CFLAGS) -c -o $@ $^
.KEEP_STATE:
install default: all
-.c.o:
- $(COMPILE.c)
-
-.s.o:
+%.o: $(TESTDIR)/%.s
$(COMPILE.s)
# A basic use of TLS that uses the movq m/r --> movq i/r variant
-PROGS += style2
+PROGS += style2
STYLE2OBJS = style2.o
style2: $(STYLE2OBJS)
$(LINK.c)
@@ -78,7 +70,7 @@ style1-with-r12: $(STYLE1R12OBJS)
all: $(PROGS)
-clobber clean:
+clobber clean:
rm -f $(PROGS) $(STYLE1OBJS) $(STYLE1R13OBJS) $(STYLE1R12OBJS) \
$(STYLE2OBJS) $(STYLE2R13OBJS) $(STYLE2R12OBJS) $(STYLE2BADNESSOBJS)
diff --git a/usr/src/test/elf-tests/tests/tls/amd64/ie/README b/usr/src/test/elf-tests/tests/tls/amd64/ie/README
new file mode 100644
index 0000000000..cdbf6a4b20
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/README
@@ -0,0 +1,5 @@
+This tests the amd64 link-editor's handling of Initial Executable TLS sequences.
+
+The original C source files are in orig/ but unused, since we need to avoid
+any changes to the compiler influencing our tests.
+
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/x64-ie-test.sh b/usr/src/test/elf-tests/tests/tls/amd64/ie/amd64-ie-test.sh
index 61dd87bce0..4b9c9cd2d6 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/x64-ie-test.sh
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/amd64-ie-test.sh
@@ -20,8 +20,9 @@ function grep_test {
print -u2 "pass: $name"
else
print -u2 "FAIL: $name"
+ exit 1
fi
-}
+}
function dis_test {
name=${1}
@@ -32,7 +33,8 @@ function dis_test {
dis -F${func} ${file} | grep_test "${name}" "${pattern}"
}
-make PROTO="${1}"
+TESTDIR=$(dirname $0)
+make -f ${TESTDIR}/Makefile.test TESTDIR=${TESTDIR}
dis_test "addq-->leaq 1" func style1 \
'func+0x10: 48 8d 92 f8 ff ff leaq -0x8(%rdx),%rdx'
@@ -58,5 +60,5 @@ dis_test "movq-->movq w/REX" main style2-with-r13 \
dis_test "movq-->movq incase of SIB" main style2-with-r12 \
'main+0x4: 49 c7 c4 f0 ff ff movq $-0x10,%r12 <0xfffffffffffffff0>'
-make PROTO="${1}" fail 2>&1 | grep_test "bad insn sequence" \
+make -f ${TESTDIR}/Makefile.test fail TESTDIR=${TESTDIR} 2>&1 | grep_test "bad insn sequence" \
'ld: fatal: relocation error: R_AMD64_TPOFF32: file style2-with-badness.o: symbol foo: section .text: offset 0x7, relocation against unknown TLS instruction sequence'
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style1-func.c b/usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style1-func.c
index ed06493f66..ed06493f66 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style1-func.c
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style1-func.c
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style1-main.c b/usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style1-main.c
index ac95fe9a58..ac95fe9a58 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style1-main.c
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style1-main.c
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style2.c b/usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style2.c
index c8b9ae407c..c8b9ae407c 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/orig/style2.c
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/orig/style2.c
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func-with-r12.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func-with-r12.s
index 68badef3d1..7d7821bed5 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func-with-r12.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func-with-r12.s
@@ -29,7 +29,7 @@ func:
movq %r12, %rdx
addq bar@GOTTPOFF(%rip), %rdx
addq foo@GOTTPOFF(%rip), %r12
- movq %r12, %rsi
+ movq %r12, %rsi
movl $.LC0, %edi
movl $0, %eax
call printf
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func-with-r13.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func-with-r13.s
index 97908bd720..97908bd720 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func-with-r13.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func-with-r13.s
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func.s
index ae03161880..ae03161880 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-func.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-func.s
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-main.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-main.s
index 08362f3c93..08362f3c93 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style1-main.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style1-main.s
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-badness.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-badness.s
index 48572ccf25..74534f8dd3 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-badness.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-badness.s
@@ -11,7 +11,7 @@
/*
* Copyright 2012, Richard Lowe.
- */
+ */
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-r12.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-r12.s
index 00753f7d0e..d446982d90 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-r12.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-r12.s
@@ -11,7 +11,7 @@
/*
* Copyright 2012, Richard Lowe.
- */
+ */
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
@@ -40,6 +40,7 @@ main:
.section .rodata.str1.1
.LC1:
.string "foo"
+
.section .tdata,"awT",@progbits
.align 8
.type foo, @object
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-r13.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-r13.s
index 40cf796234..cc740903da 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2-with-r13.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2-with-r13.s
@@ -11,7 +11,7 @@
/*
* Copyright 2012, Richard Lowe.
- */
+ */
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
diff --git a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2.s b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2.s
index 90352f918e..8ab6cc9d40 100644
--- a/usr/src/cmd/sgs/test/ld/x64/tls/ie/style2.s
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ie/style2.s
@@ -11,7 +11,7 @@
/*
* Copyright 2012, Richard Lowe.
- */
+ */
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
diff --git a/usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile b/usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile
new file mode 100644
index 0000000000..29bf217170
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile
@@ -0,0 +1,51 @@
+#
+# 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 2018, Richard Lowe.
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = amd64-ld-test
+
+DATAFILES = \
+ Makefile.test \
+ ld-with-addend.s \
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+TESTDIR = $(ROOTOPTPKG)/tests/tls/amd64/ld
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+
+DATA = $(DATAFILES:%=$(TESTDIR)/%)
+$(DATA) := FILEMODE = 0444
+
+all: $(PROG)
+
+install: all $(CMDS) $(DATA)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(CLEANFILES)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile.test b/usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile.test
new file mode 100644
index 0000000000..026b70b6d5
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ld/Makefile.test
@@ -0,0 +1,38 @@
+#
+# 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 2012, Richard Lowe.
+
+CC = gcc
+CFLAGS = -O1 -m64
+
+LINK.c = $(CC) $(CFLAGS) -o $@ $^
+COMPILE.s = $(CC) $(CFLAGS) -c -o $@ $^
+
+.KEEP_STATE:
+
+install default: all
+
+%.o: $(TESTDIR)/%.s
+ $(COMPILE.s)
+
+# an R_AMD64_DTPOFF32 with an addend, which must be preserved
+PROGS += ld-with-addend
+
+ld-with-addend: ld-with-addend.o
+ $(LINK.c)
+
+all: $(PROGS)
+
+clobber clean:
+ rm -f $(PROGS) ld-with-addend.o
+
+FRC:
diff --git a/usr/src/test/elf-tests/tests/tls/amd64/ld/amd64-ld-test.sh b/usr/src/test/elf-tests/tests/tls/amd64/ld/amd64-ld-test.sh
new file mode 100644
index 0000000000..08eb00be54
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ld/amd64-ld-test.sh
@@ -0,0 +1,46 @@
+#!/bin/ksh
+#
+# 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 2012, Richard Lowe.
+
+function grep_test {
+ name=$1
+ pattern=$2
+
+ if /usr/bin/grep -q "${pattern}"; then
+ print -u2 "pass: $name"
+ else
+ print -u2 "FAIL: $name"
+ exit 1
+ fi
+}
+
+function dis_test {
+ name=${1}
+ func=${2}
+ file=${3}
+ pattern=${4}
+
+ dis -F${func} ${file} | grep_test "${name}" "${pattern}"
+}
+
+TESTDIR=$(dirname $0)
+
+make -f ${TESTDIR}/Makefile.test TESTDIR=${TESTDIR}
+
+# if we fail, the addend won't be applied, the leaq with be -0x10(%rax)
+dis_test "addend is preserved" main ld-with-addend \
+ 'main+0x10: 48 8d b0 f2 ff ff leaq -0xe(%rax),%rsi'
+
+# We have an addend of 2, a failure will print 'incorrect'
+./ld-with-addend | grep_test 'ld-with-addend execution' \
+ '^foo: correct ([a-f0-9]*)$'
diff --git a/usr/src/test/elf-tests/tests/tls/amd64/ld/ld-with-addend.s b/usr/src/test/elf-tests/tests/tls/amd64/ld/ld-with-addend.s
new file mode 100644
index 0000000000..1c919462f3
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/amd64/ld/ld-with-addend.s
@@ -0,0 +1,43 @@
+/*
+ * 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 2012, Richard Lowe.
+ */
+
+ .section .rodata.str1.1,"aMS",@progbits,1
+.LC0:
+ .string "foo: %s (%p)\n"
+ .text
+ .section .tdata,"awT",@progbits
+foo:
+ .string "incorrect"
+ .text
+.globl main
+ .type main, @function
+main:
+.LFB0:
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+ .LCFI1:
+ leaq foo@tlsld(%rip), %rdi
+ call __tls_get_addr@plt
+ leaq 2+foo@dtpoff(%rax), %rsi
+ movq %rsi, %rdx
+ movq %rsi, %rsi
+ movl $.LC0, %edi
+ movl $0, %eax
+ call printf
+ movl $0, %eax
+ leave
+ ret
+ .size main, .-main
diff --git a/usr/src/test/elf-tests/tests/tls/i386/Makefile b/usr/src/test/elf-tests/tests/tls/i386/Makefile
new file mode 100644
index 0000000000..51053ae31b
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/i386/Makefile
@@ -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 (c) 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2018 Joyent, Inc.
+#
+
+SUBDIRS = ld
+
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/elf-tests/tests/tls/i386/ld/Makefile b/usr/src/test/elf-tests/tests/tls/i386/ld/Makefile
new file mode 100644
index 0000000000..2550e1c457
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/i386/ld/Makefile
@@ -0,0 +1,51 @@
+#
+# 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 2018, Richard Lowe.
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = i386-ld-test
+
+DATAFILES = \
+ Makefile.test \
+ half-ldm.s \
+
+ROOTOPTPKG = $(ROOT)/opt/elf-tests
+TESTDIR = $(ROOTOPTPKG)/tests/tls/i386/ld
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+
+DATA = $(DATAFILES:%=$(TESTDIR)/%)
+$(DATA) := FILEMODE = 0444
+
+all: $(PROG)
+
+install: all $(CMDS) $(DATA)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(CLEANFILES)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/elf-tests/tests/tls/i386/ld/Makefile.test b/usr/src/test/elf-tests/tests/tls/i386/ld/Makefile.test
new file mode 100644
index 0000000000..f6e9413310
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/i386/ld/Makefile.test
@@ -0,0 +1,38 @@
+#
+# 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 2012, Richard Lowe.
+
+CC = gcc
+CFLAGS = -O1 -m32
+
+LINK.c = $(CC) $(CFLAGS) -o $@ $^
+COMPILE.s = $(CC) $(CFLAGS) -c -o $@ $^
+
+.KEEP_STATE:
+
+install default: all
+
+%.o: $(TESTDIR)/%.s
+ $(COMPILE.s)
+
+# an R_386_TLS_LDM with a regular R_386_PLT32 not a R_386_TLS_LDM_PLT
+PROGS += half-ldm
+
+half-ldm: half-ldm.o
+ $(LINK.c)
+
+all: $(PROGS)
+
+clobber clean:
+ rm -f $(PROGS) half-ldm.o
+
+FRC:
diff --git a/usr/src/test/elf-tests/tests/tls/i386/ld/half-ldm.s b/usr/src/test/elf-tests/tests/tls/i386/ld/half-ldm.s
new file mode 100644
index 0000000000..f8e6dbc528
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/i386/ld/half-ldm.s
@@ -0,0 +1,49 @@
+/*
+ * 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.u
+ */
+
+/*
+ * Copyright 2019, Richard Lowe.
+ */
+
+ .section .rodata.str1.1,"aMS",@progbits,1
+.LC0:
+ .string "foo: %s (%p)\n"
+ .section .tdata,"awT",@progbits
+ .align 4
+ .type foo, @object
+ .size foo,4
+.local foo
+foo:
+ .string "foo"
+ .text
+.globl main
+ .type main, @function
+main:
+ pushl %ebp
+ movl %esp, %ebp
+ /*
+ * an R_386_TLS_LDM relocation without a following
+ * followed by an R_386_PLT32 relocation, rather than an
+ * R_386_TLS_LDM_PLT the call should be removed, and _not_
+ * left alone unrelocated as it was prior to:
+ * 10267 ld and GCC disagree about i386 local dynamic TLS
+ */
+ leal foo@TLSLDM(%ebx), %eax
+ call ___tls_get_addr@PLT
+ leal foo@DTPOFF(%eax), %edx
+ pushl %edx
+ pushl %edx
+ pushl $.LC0
+ call printf@PLT
+ movl $0x0,%eax
+ leave
+ ret
+ .size main, .-main
diff --git a/usr/src/test/elf-tests/tests/tls/i386/ld/i386-ld-test.sh b/usr/src/test/elf-tests/tests/tls/i386/ld/i386-ld-test.sh
new file mode 100644
index 0000000000..a86cc5a717
--- /dev/null
+++ b/usr/src/test/elf-tests/tests/tls/i386/ld/i386-ld-test.sh
@@ -0,0 +1,43 @@
+#!/bin/ksh
+#
+# 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 2012, Richard Lowe.
+
+function grep_test {
+ name=$1
+ pattern=$2
+
+ if /usr/bin/grep -q "${pattern}"; then
+ print -u2 "pass: $name"
+ else
+ print -u2 "FAIL: $name"
+ exit 1
+ fi
+}
+
+function dis_test {
+ name=${1}
+ func=${2}
+ file=${3}
+ pattern=${4}
+
+ dis -F${func} ${file} | grep_test "${name}" "${pattern}"
+}
+
+TESTDIR=$(dirname $0)
+make -f ${TESTDIR}/Makefile.test TESTDIR=${TESTDIR}
+
+dis_test "call-->nop" main half-ldm \
+ 'main\+0x9: 0f 1f 44 00 00 nopl 0x0(%eax,%eax)'
+
+./half-ldm | grep_test 'half-ldm execution' \
+ '^foo: foo ([a-f0-9]*)$'
diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run
index b328670f8e..3cccf62ac9 100644
--- a/usr/src/test/util-tests/runfiles/default.run
+++ b/usr/src/test/util-tests/runfiles/default.run
@@ -52,6 +52,7 @@ tests = [ 'runtests.sh' ]
[/opt/util-tests/tests/grep_test]
[/opt/util-tests/tests/date_test]
+[/opt/util-tests/tests/chown_test]
[/opt/util-tests/tests/demangle]
tests = ['afl-fast', 'gcc-libstdc++', 'llvm-stdcxxabi']
diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile
index f947f4dc71..cb2d3028da 100644
--- a/usr/src/test/util-tests/tests/Makefile
+++ b/usr/src/test/util-tests/tests/Makefile
@@ -14,11 +14,11 @@
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
# Copyright 2017 Jason King
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4
-SUBDIRS += demangle mergeq workq
-SUBDIRS += bunyan awk smbios libjedec
+SUBDIRS += demangle mergeq workq chown
+SUBDIRS += bunyan awk smbios libjedec ctf
include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/util-tests/tests/chown/Makefile b/usr/src/test/util-tests/tests/chown/Makefile
new file mode 100644
index 0000000000..52c70f8b3c
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/Makefile
@@ -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 (c) 2013 by Delphix. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2019 Alexander Pyhalov
+#
+
+.PARALLEL: $(SUBDIRS)
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests
+
+PROGS = chown_test
+
+CMDS = $(PROGS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all lint clean clobber:
+
+install: $(CMDS)
+
+$(CMDS): $(TESTDIR)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %.ksh
+ $(INS.rename)
+
+SUBDIRS = files
+
+include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/util-tests/tests/chown/chown_test.ksh b/usr/src/test/util-tests/tests/chown/chown_test.ksh
new file mode 100644
index 0000000000..d3f3478a9d
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/chown_test.ksh
@@ -0,0 +1,103 @@
+#! /usr/bin/ksh
+#
+#
+# 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.
+# Copyright 2019 Alexander Pyhalov
+#
+
+CHOWN=${CHOWN:=/usr/bin/chown}
+FILEDIR=/opt/util-tests/tests/files
+
+fail() {
+ echo $1
+ exit -1
+}
+
+create_test_hier() {
+ mkdir -p $1/src $1/dst
+ touch $1/target
+ touch $1/file
+ touch $1/dst/file1
+ touch $1/src/file2
+ ln -s ../target $1/src/tlink
+ ln -s ../dst $1/src/dstlink
+ ln -s target $1/tlink
+}
+
+SUCCESSFLAGS="
+-f
+-h
+-fhR
+-R
+-RH
+-RP
+-RL
+-Rh
+-RHL
+-RPH
+-RLP"
+
+FAILFLAGS="-RPh
+-RLh
+-RHh
+-P
+-H
+-L"
+
+NEWOWNER=daemon
+
+# We set PATH to /bin to try get ksh chown builtin
+# and to ensure that /usr/bin/chown is used instead.
+export PATH=/bin
+
+# We want unified output from tools
+export LC_ALL=en_US.UTF-8
+
+i=0
+echo "$SUCCESSFLAGS" | while read flags; do
+ print -n "test $i: chown $flags: "
+ TD=$(mktemp -d -t)
+ if [ -d "$TD" ]; then
+ create_test_hier $TD
+ chown $flags $NEWOWNER $TD/src || fail "chown $flags $NEWOWNER $TD/src failed on exit"
+ chown $flags $NEWOWNER $TD/tlink || fail "chown $flags $NEWOWNER $TD/tlink failed on exit"
+ chown $flags $NEWOWNER $TD/file || fail "chown $flags $NEWOWNER $TD/file failed on exit"
+ (cd $TD ; find . -ls |\
+ awk ' { print $3 " " $5 " " $11 }'|\
+ sort -k 3 > /tmp/out.$$)
+ if [ -n "$(diff /tmp/out.$$ $FILEDIR/cout$i)" ]; then
+ print "$(diff -u /tmp/out.$$ $FILEDIR/cout$i)"
+ fail "result is different"
+ fi
+ echo "passed"
+ rm -fr $TD /tmp/out.$$
+ else
+ fail "couldn't create $TD"
+ fi
+ ((i++))
+done
+
+echo "$FAILFLAGS" | while read flags; do
+ print -n "test $i: chown $flags: "
+ TD=$(mktemp -d -t)
+ if [ -d "$TD" ]; then
+ create_test_hier $TD
+ chown $flags $NEWOWNER $TD/file && fail "chown $flags $NEWOWNER $TD/file should have failed"
+ echo "passed"
+ rm -fr $TD
+ else
+ fail "couldn't create $TD"
+ fi
+ ((i++))
+done
diff --git a/usr/src/test/util-tests/tests/chown/files/Makefile b/usr/src/test/util-tests/tests/chown/files/Makefile
new file mode 100644
index 0000000000..4c46abaa63
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/Makefile
@@ -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 (c) 2013 by Delphix. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2019 Alexander Pyhalov
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests/files
+
+PROGS = cout0 \
+ cout1 \
+ cout2 \
+ cout3 \
+ cout4 \
+ cout5 \
+ cout6 \
+ cout7 \
+ cout8 \
+ cout9 \
+ cout10 \
+ cout11
+
+CMDS = $(PROGS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0444
+
+all lint clean clobber:
+
+install: $(CMDS)
+
+$(CMDS): $(TESTDIR)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/util-tests/tests/chown/files/cout0 b/usr/src/test/util-tests/tests/chown/files/cout0
new file mode 100644
index 0000000000..d12a3e0a90
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout0
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx root ./src/dstlink
+-rw-r--r-- root ./src/file2
+lrwxrwxrwx root ./src/tlink
+-rw-r--r-- daemon ./target
+lrwxrwxrwx root ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout1 b/usr/src/test/util-tests/tests/chown/files/cout1
new file mode 100644
index 0000000000..d12a3e0a90
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout1
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx root ./src/dstlink
+-rw-r--r-- root ./src/file2
+lrwxrwxrwx root ./src/tlink
+-rw-r--r-- daemon ./target
+lrwxrwxrwx root ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout10 b/usr/src/test/util-tests/tests/chown/files/cout10
new file mode 100644
index 0000000000..f128e53d0a
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout10
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x daemon ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx root ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx root ./src/tlink
+-rw-r--r-- daemon ./target
+lrwxrwxrwx root ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout11 b/usr/src/test/util-tests/tests/chown/files/cout11
new file mode 100644
index 0000000000..e990d2c3d7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout11
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx daemon ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx daemon ./src/tlink
+-rw-r--r-- root ./target
+lrwxrwxrwx daemon ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout12 b/usr/src/test/util-tests/tests/chown/files/cout12
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout12
diff --git a/usr/src/test/util-tests/tests/chown/files/cout2 b/usr/src/test/util-tests/tests/chown/files/cout2
new file mode 100644
index 0000000000..68b3cfaf8b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout2
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx root ./src/dstlink
+-rw-r--r-- root ./src/file2
+lrwxrwxrwx root ./src/tlink
+-rw-r--r-- root ./target
+lrwxrwxrwx daemon ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout3 b/usr/src/test/util-tests/tests/chown/files/cout3
new file mode 100644
index 0000000000..e990d2c3d7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout3
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx daemon ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx daemon ./src/tlink
+-rw-r--r-- root ./target
+lrwxrwxrwx daemon ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout4 b/usr/src/test/util-tests/tests/chown/files/cout4
new file mode 100644
index 0000000000..e990d2c3d7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout4
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx daemon ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx daemon ./src/tlink
+-rw-r--r-- root ./target
+lrwxrwxrwx daemon ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout5 b/usr/src/test/util-tests/tests/chown/files/cout5
new file mode 100644
index 0000000000..f128e53d0a
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout5
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x daemon ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx root ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx root ./src/tlink
+-rw-r--r-- daemon ./target
+lrwxrwxrwx root ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout6 b/usr/src/test/util-tests/tests/chown/files/cout6
new file mode 100644
index 0000000000..e990d2c3d7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout6
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx daemon ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx daemon ./src/tlink
+-rw-r--r-- root ./target
+lrwxrwxrwx daemon ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout7 b/usr/src/test/util-tests/tests/chown/files/cout7
new file mode 100644
index 0000000000..dcf411a1e5
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout7
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x daemon ./dst
+-rw-r--r-- daemon ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx root ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx root ./src/tlink
+-rw-r--r-- daemon ./target
+lrwxrwxrwx root ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout8 b/usr/src/test/util-tests/tests/chown/files/cout8
new file mode 100644
index 0000000000..e990d2c3d7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout8
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x root ./dst
+-rw-r--r-- root ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx daemon ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx daemon ./src/tlink
+-rw-r--r-- root ./target
+lrwxrwxrwx daemon ./tlink
diff --git a/usr/src/test/util-tests/tests/chown/files/cout9 b/usr/src/test/util-tests/tests/chown/files/cout9
new file mode 100644
index 0000000000..dcf411a1e5
--- /dev/null
+++ b/usr/src/test/util-tests/tests/chown/files/cout9
@@ -0,0 +1,10 @@
+drwx------ root .
+drwxr-xr-x daemon ./dst
+-rw-r--r-- daemon ./dst/file1
+-rw-r--r-- daemon ./file
+drwxr-xr-x daemon ./src
+lrwxrwxrwx root ./src/dstlink
+-rw-r--r-- daemon ./src/file2
+lrwxrwxrwx root ./src/tlink
+-rw-r--r-- daemon ./target
+lrwxrwxrwx root ./tlink
diff --git a/usr/src/test/util-tests/tests/ctf/Makefile b/usr/src/test/util-tests/tests/ctf/Makefile
new file mode 100644
index 0000000000..007d6c1c2f
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/Makefile
@@ -0,0 +1,149 @@
+#
+# 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 (c) 2019, Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests/ctf
+
+SCRIPTS = ctftest.ksh
+
+TESTS = test-float.c \
+ test-reference.c \
+ test-int.c \
+ test-array.c \
+ test-enum.c \
+ test-forward.c \
+ test-sou.c \
+ test-function.c \
+ test-merge-static/Makefile.ctftest \
+ test-merge-static/test-a.c \
+ test-merge-static/test-b.c \
+ test-merge-static/test-c.c \
+ test-merge-static/test-d.c \
+ test-merge-static/test-main.c \
+ test-merge-forward/Makefile.ctftest \
+ test-merge-forward/test-impl.c \
+ test-merge-forward/test-merge.c \
+ test-merge-dedup/Makefile.ctftest \
+ test-merge-dedup/test-merge-1.c \
+ test-merge-dedup/test-merge-2.c \
+ test-merge-dedup/test-merge-3.c \
+ test-merge-dedup/test-merge-dedup.c \
+ test-merge-reduction/Makefile.ctftest \
+ test-merge-reduction/mapfile-vers \
+ test-merge-reduction/test-global.c \
+ test-merge-reduction/test-scoped.c \
+ test-merge-weak/Makefile.ctftest \
+ test-merge-weak/test-merge-weak.c \
+ test-weak.c \
+ Makefile.ctftest.com
+
+MAKEDIRS = test-merge-static \
+ test-merge-forward \
+ test-merge-dedup \
+ test-merge-reduction \
+ test-merge-weak
+
+CHECKS = check-float-32 \
+ check-float-64 \
+ check-int-32 \
+ check-int-64 \
+ check-reference \
+ check-array \
+ check-enum \
+ check-sou-32 \
+ check-sou-64 \
+ check-forward-32 \
+ check-forward-64 \
+ check-function \
+ check-merge-static \
+ check-merge-forward-32 \
+ check-merge-forward-64 \
+ check-merge-dedup \
+ check-merge-reduction \
+ check-merge-weak \
+ check-weak
+
+COMMON_OBJS = check-common.o
+ALL_OBJS = $(CHECKS:%=%.o) $(CHECKS:%-32=%.32.o) $(CHECKS:%-64=%.64.o) $(COMMON_OBJS)
+
+ROOTTESTS = $(TESTS:%=$(TESTDIR)/%)
+ROOTMAKEDIRS = $(MAKEDIRS:%=$(TESTDIR)/%)
+ROOTCHECKS = $(CHECKS:%=$(TESTDIR)/%)
+ROOTSCRIPTS = $(SCRIPTS:%.ksh=$(TESTDIR)/%)
+
+ROOTTESTS := FILEMODE = 0444
+ROOTCHECKS := FILEMODE = 0555
+ROOTSCRIPTS := FILEMODE = 0555
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+LDLIBS += -lctf
+
+check-merge-static := LDLIBS += -lelf
+
+all: $(CHECKS)
+
+install: all $(ROOTTESTS) $(ROOTCHECKS) $(ROOTSCRIPTS)
+
+$(CHECKS): $(COMMON_OBJS)
+
+clean:
+ $(RM) $(ALL_OBJS)
+
+clobber: clean
+ $(RM) $(CHECKS)
+
+$(ROOTTESTS): $(TESTDIR) $(ROOTMAKEDIRS) $(TESTS)
+$(ROOTCHECKS): $(TESTDIR) $(CHECKS)
+$(ROOTSCRIPTS): $(TESTDIR) $(SCRIPTS)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(ROOTMAKEDIRS):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
+
+$(TESTDIR)/%: %.ksh
+ $(INS.rename)
+
+%.o: %.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+%.32.o: %.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+%.64.o: %.c
+ $(COMPILE.c) -DTARGET_LP64 -o $@ $<
+ $(POST_PROCESS_O)
+
+%-32: %.32.o
+ $(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+%-64: %.64.o
+ $(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+%: %.o
+ $(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS)
+ $(POST_PROCESS)
diff --git a/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com b/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com
new file mode 100644
index 0000000000..f3f754dbf9
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com
@@ -0,0 +1,92 @@
+#
+# 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 2019 Joyent, Inc.
+#
+
+#
+# This Makefile is installed onto the target system and is used as part
+# of the running tests. It is not used as part of the build.
+#
+# This makefile could be simplified substantially. However, it does
+# everything explicitly to try and work with a wide variety of different
+# makes.
+#
+# The following values should be passed in by the invoker of the
+# Makefile:
+#
+# CC C Compiler to use
+# CFLAGS32 32-bit CFLAGS
+# CFLAGS64 64-bit CFLAGS
+# CTFCONVERT Path to ctfconvert
+# CTFMERGE Path to ctfmerge
+# DEBUGFLAGS The set of debug flags to use
+# BUILDDIR Directory things should be built in
+# CHECK32 Program to check 32-bit output
+# CHECK64 Program to check 64-bit output
+#
+# The following values should be set before building this:
+#
+# TEST The name of the test program
+# OBJS_C_32 32-bit convert objects
+# OBJS_C_64 64-bit convert objects
+# OBJS_M_32 32-bit merge objects
+# OBJS_M_64 64-bit merge objects
+#
+
+CONV32 = $(BUILDDIR)/$(TEST)-32c
+CONV64 = $(BUILDDIR)/$(TEST)-64c
+MERGE32 = $(BUILDDIR)/$(TEST)-32m
+MERGE64 = $(BUILDDIR)/$(TEST)-64m
+
+BINS = $(CONV32) \
+ $(CONV64) \
+ $(MERGE32) \
+ $(MERGE64)
+
+build: $(BINS)
+
+$(BUILDDIR)/%.32.c.o: %.c
+ $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.64.c.o: %.c
+ $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.32.m.o: %.c
+ $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+ $(CTFCONVERT) $@
+
+$(BUILDDIR)/%.64.m.o: %.c
+ $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+ $(CTFCONVERT) $@
+
+$(CONV32): $(OBJS_C_32)
+ $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ $(OBJS_C_32)
+ $(CTFCONVERT) $@
+
+$(CONV64): $(OBJS_C_64)
+ $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ $(OBJS_C_64)
+ $(CTFCONVERT) $@
+
+$(MERGE32): $(OBJS_M_32)
+ $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ $(OBJS_M_32)
+ $(CTFMERGE) -t -o $@ $(OBJS_M_32)
+
+$(MERGE64): $(OBJS_M_64)
+ $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ $(OBJS_M_64)
+ $(CTFMERGE) -t -o $@ $(OBJS_M_64)
+
+run-test:
+ $(CHECK32) $(CONV32)
+ $(CHECK64) $(CONV64)
+ $(CHECK32) $(MERGE32)
+ $(CHECK64) $(MERGE64)
diff --git a/usr/src/test/util-tests/tests/ctf/README b/usr/src/test/util-tests/tests/ctf/README
new file mode 100644
index 0000000000..0f9aeb9e3a
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/README
@@ -0,0 +1,54 @@
+#
+# 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 (c) 2019, Joyent, Inc.
+#
+
+CTF Tests
+---------
+
+This directory contains a series of tests for the Compact C Type Format
+(CTF). For each test program, there is a corresponding C program that
+goes through and checks the CTF for various aspects. Due to the fact
+that the CTF generated by compilers can change slightly, the tests have
+been designed this way to try and make it work with as wide a variety of
+programs as possible.
+
+The test suite requires the following:
+
+1. make
+2. C Compiler (defaults to gcc)
+3. A copy of ctfconvert
+
+The source for a given program will be compiled on the target system and
+then converted. This allows us to try the CTF tools against a wide
+variety of different compilers or DWARF standards.
+
+Caveats
+-------
+
+Right now the tests only pass when using gcc 4.x. The following are
+known issues with the tests:
+
+1. gcc7+ generates some different DWARF ordering, which causes some
+tests to spuriously fail. These tests should be improved.
+
+2. There are cases where gcc7+ appears to attribute things as being const
+twice in DWARF which throw off the tests. The CTF tools likely should
+work around this if we confirm that this is intentional.
+
+3. Many tests will cause clang not to emit DWARF information because
+clang infers that they cannot be used. The tests should be cleaned up in
+these cases.
+
+4. clang generated DWARF can confuse the CTF tools. The tools should be
+fixed and additional regression tests should be added.
diff --git a/usr/src/test/util-tests/tests/ctf/check-array.c b/usr/src/test/util-tests/tests/ctf/check-array.c
new file mode 100644
index 0000000000..c694726a3f
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-array.c
@@ -0,0 +1,116 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly generate basic nested arrays.
+ */
+
+#include "check-common.h"
+
+static check_number_t check_base[] = {
+ { "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 },
+ { "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+ { "double", CTF_K_FLOAT, CTF_FP_DOUBLE, 0, 64 },
+ { NULL }
+};
+
+static check_symbol_t check_syms[] = {
+ { "a", "int [3]" },
+ { "b", "double [42]" },
+ { "c", "const char *[2]" },
+ { "d", "int [4][5]" },
+ { "e", "int [4][5][6]" },
+ { "f", "int [4][5][6][7]" },
+ { "g", "int [4][5][6][7][8]" },
+ { "h", "int [4][5][6][7][8][9]" },
+ { "i", "int [4][5][6][7][8][9][10]" },
+ { NULL }
+};
+
+static check_descent_t check_array_a[] = {
+ { "int [3]", CTF_K_ARRAY, "int", 3 },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_array_b[] = {
+ { "double [42]", CTF_K_ARRAY, "double", 42 },
+ { "double", CTF_K_FLOAT },
+ { NULL }
+};
+
+static check_descent_t check_array_c[] = {
+ { "const char *[2]", CTF_K_ARRAY, "const char *", 2 },
+ { "const char *", CTF_K_POINTER },
+ { "const char", CTF_K_CONST },
+ { "char", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_array_i[] = {
+ { "int [4][5][6][7][8][9][10]", CTF_K_ARRAY,
+ "int [5][6][7][8][9][10]", 4 },
+ { "int [5][6][7][8][9][10]", CTF_K_ARRAY, "int [6][7][8][9][10]", 5 },
+ { "int [6][7][8][9][10]", CTF_K_ARRAY, "int [7][8][9][10]", 6 },
+ { "int [7][8][9][10]", CTF_K_ARRAY, "int [8][9][10]", 7 },
+ { "int [8][9][10]", CTF_K_ARRAY, "int [9][10]", 8 },
+ { "int [9][10]", CTF_K_ARRAY, "int [10]", 9 },
+ { "int [10]", CTF_K_ARRAY, "int", 10 },
+ { "int", CTF_K_INTEGER },
+ { NULL },
+};
+
+static check_descent_test_t descents[] = {
+ { "a", check_array_a },
+ { "b", check_array_b },
+ { "c", check_array_c },
+ { "i", check_array_i },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t d;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+ if (!ctftest_check_numbers(fp, check_base))
+ ret = EXIT_FAILURE;
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+ for (d = 0; descents[d].cdt_sym != NULL; d++) {
+ if (!ctftest_check_descent(descents[d].cdt_sym, fp,
+ descents[d].cdt_tests)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-common.c b/usr/src/test/util-tests/tests/ctf/check-common.c
new file mode 100644
index 0000000000..8aa5449cac
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-common.c
@@ -0,0 +1,802 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Collection of common utilities for CTF testing.
+ */
+
+#include <strings.h>
+#include <libctf.h>
+#include "check-common.h"
+
+typedef struct ctftests_lookup_cb {
+ ctf_file_t *clc_fp;
+ ctf_id_t clc_id;
+ const char *clc_name;
+} ctftests_lookup_cb_t;
+
+typedef struct ctftest_member_cb {
+ ctf_file_t *cmc_fp;
+ const check_member_t *cmc_members;
+ const char *cmc_name;
+} ctftest_member_cb_t;
+
+static int
+ctftest_lookup_type_cb(ctf_id_t id, boolean_t root, void *arg)
+{
+ char buf[2048];
+ ctftests_lookup_cb_t *clc = arg;
+
+ if (ctf_type_name(clc->clc_fp, id, buf, sizeof (buf)) == NULL)
+ return (0);
+
+ if (strcmp(buf, clc->clc_name) != 0)
+ return (0);
+
+ clc->clc_id = id;
+ return (1);
+}
+
+/*
+ * This is a variant on the classic ctf_lookup_by_name(). ctf_lookup_by_name()
+ * skips qualifiers, which makes sense given what the consumers of it are trying
+ * to do. However, that's not what we want here. So instead we basically have to
+ * walk the type table.
+ */
+static ctf_id_t
+ctftest_lookup_type(ctf_file_t *fp, const char *name)
+{
+ ctftests_lookup_cb_t clc;
+
+ clc.clc_fp = fp;
+ clc.clc_id = CTF_ERR;
+ clc.clc_name = name;
+
+ (void) ctf_type_iter(fp, B_TRUE, ctftest_lookup_type_cb, &clc);
+ return (clc.clc_id);
+}
+
+static int
+ctftest_lookup_object_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg)
+{
+ ctftests_lookup_cb_t *clc = arg;
+
+ if (strcmp(obj, clc->clc_name) == 0) {
+ clc->clc_id = type;
+ return (1);
+ }
+
+ return (0);
+}
+
+static ctf_id_t
+ctftest_lookup_symbol(ctf_file_t *fp, const char *name)
+{
+ ctftests_lookup_cb_t clc;
+
+ clc.clc_fp = fp;
+ clc.clc_id = CTF_ERR;
+ clc.clc_name = name;
+
+ (void) ctf_object_iter(fp, ctftest_lookup_object_cb, &clc);
+ return (clc.clc_id);
+}
+
+typedef struct ctf_function_cb {
+ const char *cfc_name;
+ ulong_t *cfc_symp;
+ ctf_funcinfo_t *cfc_fip;
+} ctf_function_cb_t;
+
+static int
+ctftest_lookup_function_cb(const char *name, ulong_t symidx,
+ ctf_funcinfo_t *fip, void *arg)
+{
+ ctf_function_cb_t *cfc = arg;
+ if (strcmp(name, cfc->cfc_name) != 0)
+ return (0);
+
+ *cfc->cfc_symp = symidx;
+ *cfc->cfc_fip = *fip;
+
+ return (1);
+}
+
+/*
+ * Note, this function finds the first one with a matching name. This must not
+ * be used when performing searches where a given name may occur more than once.
+ */
+static boolean_t
+ctftest_lookup_function(ctf_file_t *fp, const char *name, ulong_t *symp,
+ ctf_funcinfo_t *fip)
+{
+ ctf_function_cb_t cfc;
+
+ *symp = 0;
+ cfc.cfc_name = name;
+ cfc.cfc_symp = symp;
+ cfc.cfc_fip = fip;
+ (void) ctf_function_iter(fp, ctftest_lookup_function_cb, &cfc);
+ return (*symp == 0 ? B_FALSE : B_TRUE);
+}
+
+boolean_t
+ctftest_check_numbers(ctf_file_t *fp, const check_number_t *tests)
+{
+ uint_t i;
+ boolean_t ret = B_TRUE;
+
+ for (i = 0; tests[i].cn_tname != NULL; i++) {
+ ctf_id_t id;
+ ctf_encoding_t enc;
+
+ id = ctftest_lookup_type(fp, tests[i].cn_tname);
+ if (id == CTF_ERR) {
+ warnx("failed to look up %s", tests[i].cn_tname);
+ ret = B_FALSE;
+ continue;
+ }
+
+ if (ctf_type_kind(fp, id) != tests[i].cn_kind) {
+ warnx("type kind mismatch for %s: got %u, expected %u",
+ tests[i].cn_tname, ctf_type_kind(fp, id),
+ tests[i].cn_kind);
+ ret = B_FALSE;
+ continue;
+ }
+
+ if (ctf_type_encoding(fp, id, &enc) == CTF_ERR) {
+ warnx("failed to get type encoding for %s: %s",
+ tests[i].cn_tname, ctf_errmsg(ctf_errno(fp)));
+ ret = B_FALSE;
+ continue;
+ }
+
+ if (enc.cte_format != tests[i].cn_flags) {
+ warnx("encoding flags mismatch for %s: got 0x%x, "
+ "expected 0x%x", tests[i].cn_tname, enc.cte_format,
+ tests[i].cn_flags);
+ ret = B_FALSE;
+ continue;
+ }
+
+ if (enc.cte_offset != tests[i].cn_offset) {
+ warnx("encoding offset mismatch for %s: got 0x%x, "
+ "expected 0x%x", tests[i].cn_tname, enc.cte_offset,
+ tests[i].cn_offset);
+ ret = B_FALSE;
+ continue;
+ }
+
+ if (enc.cte_bits != tests[i].cn_size) {
+ warnx("encoding size mismatch for %s: got 0x%x, "
+ "expected 0x%x", tests[i].cn_tname, enc.cte_bits,
+ tests[i].cn_size);
+ ret = B_FALSE;
+ continue;
+ }
+ }
+
+ return (ret);
+}
+
+typedef struct ctftests_symbol_cb {
+ ctf_file_t *csc_fp;
+ boolean_t csc_ret;
+ const check_symbol_t *csc_tests;
+} ctftest_symbol_cb_t;
+
+static int
+ctftest_check_symbol_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg)
+{
+ ctftest_symbol_cb_t *cb = arg;
+ const check_symbol_t *tests = cb->csc_tests;
+ ctf_file_t *fp = cb->csc_fp;
+ uint_t i;
+
+ for (i = 0; tests[i].cs_symbol != NULL; i++) {
+ ctf_id_t id;
+
+ if (strcmp(obj, tests[i].cs_symbol) != 0)
+ continue;
+
+ id = ctftest_lookup_type(fp, tests[i].cs_type);
+ if (id == CTF_ERR) {
+ warnx("failed to lookup type %s for symbol %s",
+ tests[i].cs_type, tests[i].cs_symbol);
+ cb->csc_ret = B_FALSE;
+ return (0);
+ }
+
+ if (id != type) {
+ warnx("type mismatch for symbol %s, has type id %u, "
+ "but specified type %s has id %u",
+ tests[i].cs_symbol, type, tests[i].cs_type, id);
+ cb->csc_ret = B_FALSE;
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+boolean_t
+ctftest_check_symbols(ctf_file_t *fp, const check_symbol_t *tests)
+{
+ ctftest_symbol_cb_t cb;
+
+ cb.csc_fp = fp;
+ cb.csc_ret = B_TRUE;
+ cb.csc_tests = tests;
+ if (ctf_object_iter(fp, ctftest_check_symbol_cb, &cb) != 0)
+ return (B_FALSE);
+ return (cb.csc_ret);
+}
+
+
+boolean_t
+ctftest_check_descent(const char *symbol, ctf_file_t *fp,
+ const check_descent_t *tests)
+{
+ ctf_id_t base;
+ uint_t layer = 0;
+
+ /*
+ * First, find the initial type of the symbol.
+ */
+ base = ctftest_lookup_symbol(fp, symbol);
+ if (base == CTF_ERR) {
+ warnx("failed to lookup type for symbol %s", symbol);
+ return (B_FALSE);
+ }
+
+ while (tests->cd_tname != NULL) {
+ ctf_id_t tid;
+ int kind;
+ ctf_arinfo_t ari;
+
+ if (base == CTF_ERR) {
+ warnx("encountered non-reference type at layer %u "
+ "while still expecting type %s for symbol %s",
+ layer, tests->cd_tname, symbol);
+ return (B_FALSE);
+ }
+
+ tid = ctftest_lookup_type(fp, tests->cd_tname);
+ if (tid == CTF_ERR) {
+ warnx("failed to lookup type %s", tests->cd_tname);
+ return (B_FALSE);
+ }
+
+ if (tid != base) {
+ warnx("type mismatch at layer %u: found id %u, but "
+ "expecting type id %u for type %s, symbol %s",
+ layer, base, tid, tests->cd_tname, symbol);
+ return (B_FALSE);
+ }
+
+ kind = ctf_type_kind(fp, base);
+ if (kind != tests->cd_kind) {
+ warnx("type kind mismatch at layer %u: found kind %u, "
+ "but expected kind %u for %s, symbol %s", layer,
+ kind, tests->cd_kind, tests->cd_tname, symbol);
+ return (B_FALSE);
+ }
+
+ switch (kind) {
+ case CTF_K_ARRAY:
+ if (ctf_array_info(fp, base, &ari) == CTF_ERR) {
+ warnx("failed to lookup array info at layer "
+ "%u for type %s, symbol %s: %s", base,
+ tests->cd_tname, symbol,
+ ctf_errmsg(ctf_errno(fp)));
+ return (B_FALSE);
+ }
+
+ if (tests->cd_nents != ari.ctr_nelems) {
+ warnx("array element mismatch at layer %u "
+ "for type %s, symbol %s: found %u, "
+ "expected %u", layer, tests->cd_tname,
+ symbol, ari.ctr_nelems, tests->cd_nents);
+ return (B_FALSE);
+ }
+
+ tid = ctftest_lookup_type(fp, tests->cd_contents);
+ if (tid == CTF_ERR) {
+ warnx("failed to look up type %s",
+ tests->cd_contents);
+ return (B_FALSE);
+ }
+
+ if (ari.ctr_contents != tid) {
+ warnx("array contents mismatch at layer %u "
+ "for type %s, symbol %s: found %u, "
+ "expected %s/%u", layer, tests->cd_tname,
+ symbol, ari.ctr_contents,
+ tests->cd_contents, tid);
+
+ return (B_FALSE);
+ }
+ base = ari.ctr_contents;
+ break;
+ default:
+ base = ctf_type_reference(fp, base);
+ break;
+ }
+
+ tests++;
+ layer++;
+ }
+
+ if (base != CTF_ERR) {
+ warnx("found additional type %u in chain, but expected no more",
+ base);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+int
+ctftest_check_enum_count(const char *name, int value, void *arg)
+{
+ uint_t *u = arg;
+ *u = *u + 1;
+ return (0);
+}
+
+int
+ctftest_check_enum_value(const char *name, int value, void *arg)
+{
+ uint_t i;
+ const check_enum_t *enums = arg;
+
+ for (i = 0; enums[i].ce_name != NULL; i++) {
+ if (strcmp(enums[i].ce_name, name) != 0)
+ continue;
+ if (enums[i].ce_value == (int64_t)value)
+ return (0);
+ warnx("enum %s value mismatch: found %d, expected %" PRId64,
+ name, value, enums[i].ce_value);
+ return (1);
+ }
+
+ warnx("found no matching entry for enum member %s", name);
+ return (1);
+}
+
+boolean_t
+ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums)
+{
+ int ret;
+ uint_t tcount, ecount;
+ ctf_id_t base;
+
+ if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
+ warnx("Failed to look up type %s", type);
+ return (B_FALSE);
+ }
+
+ if (ctf_type_kind(fp, base) != CTF_K_ENUM) {
+ warnx("%s is not an enum", type);
+ return (B_FALSE);
+ }
+
+ /*
+ * First count how many entries we have.
+ */
+ tcount = 0;
+ while (enums[tcount].ce_name != NULL) {
+ tcount++;
+ }
+
+ ecount = 0;
+ if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) {
+ warnx("failed to walk enum %s: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ return (B_FALSE);
+ }
+
+ if (tcount != ecount) {
+ warnx("enum value mismatch: expected %u values, but found %u",
+ tcount, ecount);
+ return (B_FALSE);
+ }
+
+ if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value,
+ (void *)enums)) != 0) {
+ if (ret == -1) {
+ warnx("failed to walk enum %s: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ }
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+int
+ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff,
+ void *arg)
+{
+ uint_t *countp = arg;
+ *countp = *countp + 1;
+ return (0);
+}
+
+int
+ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff,
+ void *arg)
+{
+ uint_t i;
+ const ctftest_member_cb_t *cmc = arg;
+ const check_member_t *members = cmc->cmc_members;
+ ctf_file_t *fp = cmc->cmc_fp;
+
+ for (i = 0; members[i].cm_name != NULL; i++) {
+ boolean_t bad = B_FALSE;
+ char buf[2048];
+
+ if (strcmp(mname, members[i].cm_name) != 0)
+ continue;
+
+ if (bitoff != members[i].cm_offset) {
+ warnx("member %s of type %s has mismatched bit offset: "
+ "found %lu, expected %lu", mname, cmc->cmc_name,
+ bitoff, members[i].cm_offset);
+ bad = B_TRUE;
+ }
+
+ if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) {
+ warnx("failed to obtain type name for member %s",
+ mname, ctf_errmsg(ctf_errno(fp)));
+ bad = B_TRUE;
+ } else if (strcmp(buf, members[i].cm_type) != 0) {
+ warnx("member %s has bad type, found %s, expected %s",
+ mname, buf, members[i].cm_type);
+ bad = B_TRUE;
+ }
+
+ return (bad ? 1 : 0);
+ }
+
+ warnx("found no matching entry for member %s of type %s", mname,
+ cmc->cmc_name);
+ return (1);
+}
+
+boolean_t
+ctftest_check_members(const char *type, ctf_file_t *fp, int kind,
+ size_t size, const check_member_t *members)
+{
+ int ret;
+ uint_t tcount, mcount;
+ ctf_id_t base;
+ ctftest_member_cb_t cmc;
+
+ if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
+ warnx("failed to look up type %s", type);
+ return (B_FALSE);
+ }
+
+ if (ctf_type_kind(fp, base) != kind) {
+ warnx("%s has kind %s, expected %s", type,
+ ctf_kind_name(fp, ctf_type_kind(fp, base)),
+ ctf_kind_name(fp, kind));
+ return (B_FALSE);
+ }
+
+ if (size != ctf_type_size(fp, base)) {
+ warnx("%s has bad size, expected %lu, found %lu",
+ type, size, ctf_type_size(fp, base));
+ return (B_FALSE);
+ }
+
+ /*
+ * First count how many entries we have.
+ */
+ tcount = 0;
+ while (members[tcount].cm_name != NULL) {
+ tcount++;
+ }
+
+ mcount = 0;
+ if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) !=
+ 0) {
+ warnx("failed to walk members of %s: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ return (B_FALSE);
+ }
+
+ if (tcount != mcount) {
+ warnx("type member mismatch: expected %u values, but found %u",
+ tcount, mcount);
+ return (B_FALSE);
+ }
+
+ cmc.cmc_fp = fp;
+ cmc.cmc_members = members;
+ cmc.cmc_name = type;
+ if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb,
+ &cmc)) != 0) {
+ if (ret == -1) {
+ warnx("failed to walk type %s: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ }
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+boolean_t
+ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype,
+ uint_t nargs, uint_t flags, const char **argv)
+{
+ ulong_t sym;
+ ctf_funcinfo_t fi;
+ uint_t i;
+ boolean_t ret = B_TRUE;
+ ctf_id_t *args;
+ char buf[2048];
+
+
+ if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) {
+ warnx("failed to look up function %s", symbol);
+ return (B_FALSE);
+ }
+
+ if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
+ warnx("failed to lookup return type name for function %s",
+ symbol);
+ ret = B_FALSE;
+ } else if (strcmp(rtype, buf) != 0) {
+ warnx("return type has wrong type: found %s, expected %s",
+ buf, rtype);
+ ret = B_FALSE;
+ }
+
+ if (nargs != fi.ctc_argc) {
+ warnx("function argument mismatch: found %u, expected %u",
+ fi.ctc_argc, nargs);
+ ret = B_FALSE;
+ }
+
+ if (flags != fi.ctc_flags) {
+ warnx("function flags mismatch, found 0x%x, expected 0x%x",
+ fi.ctc_flags, flags);
+ ret = B_FALSE;
+ }
+
+ if (!ret || fi.ctc_argc == 0) {
+ return (ret);
+ }
+
+ if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
+ warnx("failed to allocate memory for function arguments");
+ return (B_FALSE);
+ }
+
+ if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) {
+ warnx("failed to get function information: %s",
+ ctf_errmsg(ctf_errno(fp)));
+ free(args);
+ return (B_FALSE);
+ }
+
+ for (i = 0; i < fi.ctc_argc; i++) {
+ if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
+ warnx("failed to obtain type name for argument %u",
+ i, ctf_errmsg(ctf_errno(fp)));
+ ret = B_FALSE;
+ break;
+ }
+
+ if (strcmp(buf, argv[i]) != 0) {
+ warnx("argument %u has wrong type: found %s, "
+ "expected %s", i, buf, argv[i]);
+ ret = B_FALSE;
+ break;
+ }
+ }
+
+ free(args);
+ return (ret);
+}
+
+boolean_t
+ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype,
+ uint_t nargs, uint_t flags, const char **argv)
+{
+ ctf_id_t tid;
+ ctf_funcinfo_t fi;
+ uint_t i;
+ boolean_t ret = B_TRUE;
+ ctf_id_t *args;
+ char buf[2048];
+
+
+ if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) {
+ warnx("failed to look up type %s: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ return (B_FALSE);
+ }
+
+ /*
+ * Perform two CTF type resolves, one for the function pointer and one
+ * for the typedef that gets passed in.
+ */
+ if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) {
+ warnx("failed to convert type %s to base type: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ return (B_FALSE);
+ }
+
+ if (ctf_type_kind(fp, tid) == CTF_K_POINTER &&
+ (tid = ctf_type_reference(fp, tid)) == CTF_ERR) {
+ warnx("failed to convert type %s to base type: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ return (B_FALSE);
+ }
+
+ if (ctf_func_info_by_id(fp, tid, &fi) != 0) {
+ warnx("failed to get function information for type %s: %s",
+ type, ctf_errmsg(ctf_errno(fp)));
+ return (B_FALSE);
+ }
+
+ if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
+ warnx("failed to lookup return type name for function %s",
+ type);
+ ret = B_FALSE;
+ } else if (strcmp(rtype, buf) != 0) {
+ warnx("return type has wrong type: found %s, expected %s",
+ buf, rtype);
+ ret = B_FALSE;
+ }
+
+ if (nargs != fi.ctc_argc) {
+ warnx("function argument mismatch: found %u, expected %u",
+ fi.ctc_argc, nargs);
+ ret = B_FALSE;
+ }
+
+ if (flags != fi.ctc_flags) {
+ warnx("function flags mismatch, found 0x%x, expected 0x%x",
+ fi.ctc_flags, flags);
+ ret = B_FALSE;
+ }
+
+ if (!ret || fi.ctc_argc == 0) {
+ return (ret);
+ }
+
+ if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
+ warnx("failed to allocate memory for function arguments");
+ return (B_FALSE);
+ }
+
+ if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) {
+ warnx("failed to get function information: %s",
+ ctf_errmsg(ctf_errno(fp)));
+ free(args);
+ return (B_FALSE);
+ }
+
+ for (i = 0; i < fi.ctc_argc; i++) {
+ if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
+ warnx("failed to obtain type name for argument %u",
+ i, ctf_errmsg(ctf_errno(fp)));
+ ret = B_FALSE;
+ break;
+ }
+
+ if (strcmp(buf, argv[i]) != 0) {
+ warnx("argument %u has wrong type: found %s, "
+ "expected %s", i, buf, argv[i]);
+ ret = B_FALSE;
+ break;
+ }
+ }
+
+ free(args);
+ return (ret);
+}
+
+typedef struct ctftest_duplicates {
+ ctf_file_t *ctd_fp;
+ char **ctd_names;
+ size_t ctd_len;
+ size_t ctd_curent;
+ boolean_t ctd_ret;
+} ctftest_duplicates_t;
+
+static int
+ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg)
+{
+ char buf[2048];
+ ctftest_duplicates_t *dup = arg;
+ size_t i;
+
+ if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) {
+ warnx("failed to lookup name for id %ld", id);
+ dup->ctd_ret = B_FALSE;
+ return (1);
+ }
+
+ for (i = 0; i < dup->ctd_curent; i++) {
+ if (strcmp(buf, dup->ctd_names[i]) == 0) {
+ warnx("encountered duplicate type '%s'", buf);
+ dup->ctd_ret = B_FALSE;
+ /*
+ * Don't break out of the loop and keep going in case we
+ * find another duplicate.
+ */
+ return (0);
+ }
+ }
+
+ if (dup->ctd_curent == dup->ctd_len) {
+ char **n;
+ size_t newlen = dup->ctd_len * 2;
+
+ n = recallocarray(dup->ctd_names, dup->ctd_len, newlen,
+ sizeof (char *));
+ if (n == NULL) {
+ warnx("failed to resize type name array");
+ dup->ctd_ret = B_FALSE;
+ return (1);
+ }
+
+ dup->ctd_names = n;
+ dup->ctd_len = newlen;
+ }
+
+ dup->ctd_names[dup->ctd_curent] = strdup(buf);
+ if (dup->ctd_names[dup->ctd_curent] == NULL) {
+ warn("failed to duplicate type name");
+ dup->ctd_ret = B_FALSE;
+ return (1);
+ }
+ dup->ctd_curent++;
+
+ return (0);
+}
+
+boolean_t
+ctftest_duplicates(ctf_file_t *fp)
+{
+ size_t i;
+ ctftest_duplicates_t d;
+
+ bzero(&d, sizeof (d));
+ d.ctd_fp = fp;
+ d.ctd_len = 4;
+ d.ctd_ret = B_TRUE;
+ d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *));
+ if (d.ctd_names == NULL) {
+ warnx("failed to allocate duplicate name storage");
+ return (B_FALSE);
+ }
+
+ (void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d);
+
+ for (i = 0; i < d.ctd_curent; i++) {
+ free(d.ctd_names[i]);
+ }
+ free(d.ctd_names);
+
+ return (d.ctd_ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-common.h b/usr/src/test/util-tests/tests/ctf/check-common.h
new file mode 100644
index 0000000000..f78fb2f00c
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-common.h
@@ -0,0 +1,141 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#ifndef _CHECK_COMMON_H
+#define _CHECK_COMMON_H
+
+/*
+ * Common definitions for the CTF tests
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <libctf.h>
+#include <err.h>
+#include <strings.h>
+#include <sys/param.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct check_number {
+ const char *cn_tname;
+ uint_t cn_kind;
+ uint_t cn_flags;
+ uint_t cn_offset;
+ uint_t cn_size;
+} check_number_t;
+
+typedef struct check_symbol {
+ const char *cs_symbol;
+ const char *cs_type;
+} check_symbol_t;
+
+typedef struct check_descent {
+ const char *cd_tname;
+ uint_t cd_kind;
+ const char *cd_contents;
+ uint_t cd_nents;
+} check_descent_t;
+
+typedef struct check_descent_test {
+ const char *cdt_sym;
+ const check_descent_t *cdt_tests;
+} check_descent_test_t;
+
+typedef struct check_enum {
+ const char *ce_name;
+ int64_t ce_value;
+} check_enum_t;
+
+typedef struct check_enum_test {
+ const char *cet_type;
+ const check_enum_t *cet_tests;
+} check_enum_test_t;
+
+typedef struct check_member {
+ const char *cm_name;
+ const char *cm_type;
+ ulong_t cm_offset;
+} check_member_t;
+
+typedef struct check_member_test {
+ const char *cmt_type;
+ int cmt_kind;
+ size_t cmt_size;
+ const check_member_t *cmt_members;
+} check_member_test_t;
+
+typedef struct check_function_test {
+ const char *cft_name;
+ const char *cft_rtype;
+ uint_t cft_nargs;
+ uint_t cft_flags;
+ const char **cft_args;
+} check_function_test_t;
+
+/*
+ * Looks up each type and verifies that it matches the expected type.
+ */
+extern boolean_t ctftest_check_numbers(ctf_file_t *, const check_number_t *);
+
+/*
+ * Looks at each symbol specified and verifies that it matches the expected
+ * type.
+ */
+extern boolean_t ctftest_check_symbols(ctf_file_t *, const check_symbol_t *);
+
+/*
+ * Given a symbol name which refers to a type, walks all the references of that
+ * type and checks against it with each subsequent entry.
+ */
+extern boolean_t ctftest_check_descent(const char *, ctf_file_t *,
+ const check_descent_t *);
+
+/*
+ * Checks that all of the listed members of an enum are present and have the
+ * right values.
+ */
+extern boolean_t ctftest_check_enum(const char *, ctf_file_t *,
+ const check_enum_t *);
+
+/*
+ * Checks that all of the members of a structure or union are present and have
+ * the right types and byte offsets. This can be used for either structures or
+ * unions.
+ */
+extern boolean_t ctftest_check_members(const char *, ctf_file_t *, int, size_t,
+ const check_member_t *);
+
+/*
+ * Check that the named function or function pointer has the correct return
+ * type, arguments, and function flags.
+ */
+extern boolean_t ctftest_check_function(const char *, ctf_file_t *,
+ const char *, uint_t, uint_t, const char **);
+extern boolean_t ctftest_check_fptr(const char *, ctf_file_t *,
+ const char *, uint_t, uint_t, const char **);
+
+/*
+ * Determine whether or not we have a duplicate type or not based on its name.
+ */
+extern boolean_t ctftest_duplicates(ctf_file_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CHECK_COMMON_H */
diff --git a/usr/src/test/util-tests/tests/ctf/check-enum.c b/usr/src/test/util-tests/tests/ctf/check-enum.c
new file mode 100644
index 0000000000..79d6f795ed
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-enum.c
@@ -0,0 +1,143 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle enums.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+ { "ff6", "enum ff6" },
+ { "ff10", "ff10_t" },
+ { NULL }
+};
+
+static check_descent_t check_descent_ff6[] = {
+ { "enum ff6", CTF_K_ENUM },
+ { NULL }
+};
+
+static check_descent_t check_descent_ff10[] = {
+ { "ff10_t", CTF_K_TYPEDEF },
+ { "enum ff10", CTF_K_ENUM },
+ { NULL }
+};
+
+static check_descent_t check_descent_chrono[] = {
+ { "chrono_t", CTF_K_TYPEDEF },
+ { "enum chrono", CTF_K_ENUM },
+ { NULL }
+};
+
+static check_descent_test_t descents[] = {
+ { "ff10", check_descent_ff10 },
+ { "ff6", check_descent_ff6 },
+ { "trigger", check_descent_chrono },
+ { NULL }
+};
+
+static check_enum_t check_enum_ff6[] = {
+ { "TERRA", 0 },
+ { "LOCKE", 1 },
+ { "EDGAR", 2 },
+ { "SABIN", 3 },
+ { "CELES", 4 },
+ { "CYAN", 5 },
+ { "SHADOW", 6 },
+ { "GAU", 7 },
+ { "SETZER", 8 },
+ { "STRAGO", 9 },
+ { "RELM", 10 },
+ { "MOG", 11 },
+ { "GOGO", 12 },
+ { "UMARO", 13 },
+ { "LEO", 14 },
+ { "KEFKA", 15 },
+ { NULL }
+};
+
+static check_enum_t check_enum_ff10[] = {
+ { "TIDUS", -10 },
+ { "YUNA", 23 },
+ { "AURON", -34 },
+ { "WAKA", 52 },
+ { "LULU", INT32_MAX },
+ { "RIKKU", INT32_MIN },
+ { "KHIMARI", 0 },
+ { NULL }
+};
+
+static check_enum_t check_enum_chrono[] = {
+ { "CRONO", 0x1000 },
+ { "LUCCA", 0x2000 },
+ { "MARLE", 0x3000 },
+ { "FROG", 0x4000 },
+ { "ROBO", 0x5000 },
+ { "AYLA", 0x6000 },
+ { "MAGUS", 0x7000 },
+ { "SCHALA", 0x8000 },
+ { "LAVOS", 0x9000 },
+ { "BALTHAZAR", 0xa000 },
+ { NULL }
+};
+
+static check_enum_test_t enums[] = {
+ { "enum ff6", check_enum_ff6 },
+ { "enum ff10", check_enum_ff10 },
+ { "enum chrono", check_enum_chrono },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t d;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+ for (d = 0; descents[d].cdt_sym != NULL; d++) {
+ if (!ctftest_check_descent(descents[d].cdt_sym, fp,
+ descents[d].cdt_tests)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ for (d = 0; enums[d].cet_type != NULL; d++) {
+ if (!ctftest_check_enum(enums[d].cet_type, fp,
+ enums[d].cet_tests)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+ ctf_close(fp);
+ }
+
+ return (ret);
+
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-float.c b/usr/src/test/util-tests/tests/ctf/check-float.c
new file mode 100644
index 0000000000..948c467446
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-float.c
@@ -0,0 +1,80 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check for basic float types.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "check-common.h"
+
+static check_number_t check_floats[] = {
+ { "float", CTF_K_FLOAT, CTF_FP_SINGLE, 0, 32 },
+ { "double", CTF_K_FLOAT, CTF_FP_DOUBLE, 0, 64 },
+#ifdef TARGET_LP64
+ { "long double", CTF_K_FLOAT, CTF_FP_LDOUBLE, 0, 128 },
+#else
+ { "long double", CTF_K_FLOAT, CTF_FP_LDOUBLE, 0, 96 },
+#endif
+ { "complex float", CTF_K_FLOAT, CTF_FP_CPLX, 0, 64 },
+ { "complex double", CTF_K_FLOAT, CTF_FP_DCPLX, 0, 128 },
+#ifdef TARGET_LP64
+ { "complex long double", CTF_K_FLOAT, CTF_FP_LDCPLX, 0, 256 },
+#else
+ { "complex long double", CTF_K_FLOAT, CTF_FP_LDCPLX, 0, 192 },
+#endif
+ { NULL }
+};
+
+static check_symbol_t check_syms[] = {
+ { "a", "float" },
+ { "b", "double" },
+ { "c", "long double" },
+ { "d", "complex float" },
+ { "e", "complex double" },
+ { "f", "complex long double" },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_numbers(fp, check_floats))
+ ret = EXIT_FAILURE;
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-forward.c b/usr/src/test/util-tests/tests/ctf/check-forward.c
new file mode 100644
index 0000000000..2b00209fce
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-forward.c
@@ -0,0 +1,130 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Verify that we can properly handle forward declarations.
+ *
+ * In test-forward.c barp is declared as a union, not a struct. However, today
+ * the CTF tooling does not contain enough information to know whether a forward
+ * declaration was for a struct or a union, only that it was a forward.
+ * Therefore, the type printing information assumes at the moment that the type
+ * is a struct. In a future revision of the CTF type data, we should encode this
+ * information in the equivalent of ctt_info so we can properly distinguish
+ * between these.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+ { "forward", "struct forward" },
+ { "foop", "struct foo *" },
+ { "barp", "struct bar *" },
+ { "bazp", "enum baz *" },
+ { NULL }
+};
+
+static check_member_t check_member_forward[] = {
+#ifdef TARGET_LP64
+ { "prev", "struct foo *", 0 },
+ { "next", "struct foo *", 8 * NBBY },
+ { "data", "struct bar *", 16 * NBBY },
+ { "tag", "enum baz *", 24 * NBBY },
+#else
+ { "prev", "struct foo *", 0 },
+ { "next", "struct foo *", 4 * NBBY },
+ { "data", "struct bar *", 8 * NBBY },
+ { "tag", "enum baz *", 12 * NBBY },
+#endif
+ { NULL }
+};
+
+
+static check_member_test_t members[] = {
+#ifdef TARGET_LP64
+ { "struct forward", CTF_K_STRUCT, 32, check_member_forward },
+#else
+ { "struct forward", CTF_K_STRUCT, 16, check_member_forward },
+#endif
+ { NULL }
+};
+
+static check_descent_t check_descent_foo[] = {
+ { "struct foo *", CTF_K_POINTER },
+ { "struct foo", CTF_K_FORWARD },
+ { NULL }
+};
+
+static check_descent_t check_descent_bar[] = {
+ { "struct bar *", CTF_K_POINTER },
+ { "struct bar", CTF_K_FORWARD },
+ { NULL }
+};
+
+static check_descent_t check_descent_baz[] = {
+ { "enum baz *", CTF_K_POINTER },
+ { "enum baz", CTF_K_ENUM },
+ { NULL }
+};
+
+static check_descent_test_t descents[] = {
+ { "foop", check_descent_foo },
+ { "barp", check_descent_bar },
+ { "bazp", check_descent_baz },
+ { NULL }
+};
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t j;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+
+ for (j = 0; descents[j].cdt_sym != NULL; j++) {
+ if (!ctftest_check_descent(descents[j].cdt_sym, fp,
+ descents[j].cdt_tests)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+
+ for (j = 0; members[j].cmt_type != NULL; j++) {
+ if (!ctftest_check_members(members[j].cmt_type, fp,
+ members[j].cmt_kind, members[j].cmt_size,
+ members[j].cmt_members)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-function.c b/usr/src/test/util-tests/tests/ctf/check-function.c
new file mode 100644
index 0000000000..fdb60ce290
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-function.c
@@ -0,0 +1,88 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle functions and function pointers.
+ */
+
+#include "check-common.h"
+
+static const char *one_args[] = { "int" };
+static const char *two_args[] = { "int", "const char *" };
+static const char *three_args[] = { "int", "const char *", "float" };
+static const char *argument_args[] = { "uintptr_t" };
+static const char *vararg_args[] = { "const char *" };
+
+static check_function_test_t functions[] = {
+ { "simple_func", "void", 0, 0, NULL },
+ { "one", "void", 1, 0, one_args },
+ { "two", "void", 2, 0, two_args },
+ { "three", "void", 3, 0, three_args },
+ { "noarg", "const char *", 0, 0, NULL },
+ { "argument", "const char *", 1, 0, argument_args },
+ { "vararg", "void", 1, CTF_FUNC_VARARG, vararg_args },
+ { "vararg_ret", "uintptr_t", 1, CTF_FUNC_VARARG, vararg_args },
+ { NULL }
+};
+
+static const char *strfunc_args[] = { "const char *", "const char *" };
+
+static check_function_test_t fptrs[] = {
+ { "strfunc_t", "int", 2, 0, strfunc_args },
+ { "vararg_t", "void", 1, CTF_FUNC_VARARG, vararg_args },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t j;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ for (j = 0; functions[j].cft_name != NULL; j++) {
+ if (!ctftest_check_function(functions[j].cft_name, fp,
+ functions[j].cft_rtype, functions[j].cft_nargs,
+ functions[j].cft_flags, functions[j].cft_args)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ for (j = 0; fptrs[j].cft_name != NULL; j++) {
+ if (!ctftest_check_fptr(fptrs[j].cft_name, fp,
+ fptrs[j].cft_rtype, fptrs[j].cft_nargs,
+ fptrs[j].cft_flags, fptrs[j].cft_args)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-int.c b/usr/src/test/util-tests/tests/ctf/check-int.c
new file mode 100644
index 0000000000..ac34f27e85
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-int.c
@@ -0,0 +1,88 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check for basic integer types.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "check-common.h"
+
+static check_number_t check_ints[] = {
+ { "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 },
+ { "short", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 16 },
+ { "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+#ifdef TARGET_LP64
+ { "long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 64 },
+#else
+ { "long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+#endif
+ { "long long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 64 },
+ { "unsigned char", CTF_K_INTEGER, CTF_INT_CHAR, 0, 8 },
+ { "unsigned short", CTF_K_INTEGER, 0, 0, 16 },
+ { "unsigned int", CTF_K_INTEGER, 0, 0, 32 },
+#ifdef TARGET_LP64
+ { "unsigned long", CTF_K_INTEGER, 0, 0, 64 },
+#else
+ { "unsigned long", CTF_K_INTEGER, 0, 0, 32 },
+#endif
+ { "unsigned long long", CTF_K_INTEGER, 0, 0, 64 },
+ { NULL }
+};
+
+static check_symbol_t check_syms[] = {
+ { "a", "char" },
+ { "b", "unsigned char" },
+ { "d", "short" },
+ { "e", "unsigned short" },
+ { "g", "int" },
+ { "h", "unsigned int" },
+ { "j", "long" },
+ { "k", "unsigned long" },
+ { "m", "long long" },
+ { "n", "unsigned long long" },
+ { NULL },
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_numbers(fp, check_ints))
+ ret = EXIT_FAILURE;
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c b/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c
new file mode 100644
index 0000000000..06db2ad1f0
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c
@@ -0,0 +1,82 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests that we don't end up with several copies of the same type.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+ { "int", "a" },
+ { "short", "b" },
+ { "const char *", "c" },
+ { "float", "d" },
+ { "double" "e" },
+ { "int", "f" },
+ { "short", "g" },
+ { "const char *", "h" },
+ { "float", "i" },
+ { "double" "j" },
+ { "int", "k" },
+ { "short", "l" },
+ { "const char *", "m" },
+ { "float", "n" },
+ { "double" "o" },
+ { "int", "p" },
+ { "short", "q" },
+ { "const char *", "r" },
+ { "float", "s" },
+ { "double" "t" },
+ { "struct dup" "dupmain" },
+ { "struct dup" "dup1" },
+ { "struct dup" "dup2" },
+ { "struct dup" "dup3" },
+ { NULL }
+};
+
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_symbols(fp, check_syms)) {
+ ret = EXIT_FAILURE;
+ }
+
+ if (!ctftest_duplicates(fp)) {
+ ret = EXIT_FAILURE;
+ }
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-forward.c b/usr/src/test/util-tests/tests/ctf/check-merge-forward.c
new file mode 100644
index 0000000000..e396beb133
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-forward.c
@@ -0,0 +1,132 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests that a forward declared in one object file that is defined in
+ * another doesn't end up in the final one.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+ { "list", "foo_list_t" },
+ { NULL }
+};
+
+static check_member_t check_member_foo_list[] = {
+ { "count", "int", 0 },
+#ifdef TARGET_LP64
+ { "head", "struct foo *", 8 * NBBY },
+ { "tail", "struct foo *", 16 * NBBY },
+#else
+ { "head", "struct foo *", 4 * NBBY },
+ { "tail", "struct foo *", 8 * NBBY },
+#endif
+ { NULL }
+};
+
+static check_member_t check_member_foo[] = {
+ { "next", "struct foo *", 0 * NBBY },
+#ifdef TARGET_LP64
+ { "left", "int", 8 * NBBY },
+ { "right", "int", 12 * NBBY },
+ { "count", "int", 16 * NBBY },
+#else
+ { "left", "int", 4 * NBBY },
+ { "right", "int", 8 * NBBY },
+ { "count", "int", 12 * NBBY },
+#endif
+ { NULL }
+};
+
+static check_member_test_t members[] = {
+#ifdef TARGET_LP64
+ { "struct foo_list", CTF_K_STRUCT, 24, check_member_foo_list },
+ { "struct foo", CTF_K_STRUCT, 24, check_member_foo },
+#else
+ { "struct foo_list", CTF_K_STRUCT, 12, check_member_foo_list },
+ { "struct foo", CTF_K_STRUCT, 16, check_member_foo },
+#endif
+ { NULL }
+};
+
+static int
+ctf_merge_forward_cb(ctf_id_t id, boolean_t root, void *arg)
+{
+ ctf_file_t *fp = arg;
+ char buf[2048];
+
+ if (ctf_type_kind(fp, id) != CTF_K_FORWARD)
+ return (0);
+
+ if (ctf_type_name(fp, id, buf, sizeof (buf)) == NULL) {
+ warnx("failed to lookup the name of type %ld: %s", id,
+ ctf_errmsg(ctf_errno(fp)));
+ return (1);
+ }
+
+ /*
+ * If a forward shows up, that's OK. It's only bad if it's the name of
+ * the one we created.
+ */
+ if (strcmp("struct foo", buf) == 0) {
+ warnx("encountered forward type for struct foo that "
+ "shouldn't exist");
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t j;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+
+ for (j = 0; members[j].cmt_type != NULL; j++) {
+ if (!ctftest_check_members(members[j].cmt_type, fp,
+ members[j].cmt_kind, members[j].cmt_size,
+ members[j].cmt_members)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ if (ctf_type_iter(fp, B_TRUE, ctf_merge_forward_cb, fp) != 0) {
+ ret = EXIT_FAILURE;
+ }
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c b/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c
new file mode 100644
index 0000000000..86b688bc0b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c
@@ -0,0 +1,72 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests that a global that has been scoped to local scope through symbol
+ * reduction of a mapfile can still be detected.
+ */
+
+#include "check-common.h"
+
+static check_symbol_t check_syms[] = {
+ { "data", "int" },
+ { NULL }
+};
+
+static const char *scoped_args[] = { "uint32_t" };
+
+static check_function_test_t functions[] = {
+ { "global", "int", 0, 0, NULL },
+ { "scoped", "int", 1, 0, scoped_args },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t j;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+
+ for (j = 0; functions[j].cft_name != NULL; j++) {
+ if (!ctftest_check_function(functions[j].cft_name, fp,
+ functions[j].cft_rtype, functions[j].cft_nargs,
+ functions[j].cft_flags, functions[j].cft_args)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-static.c b/usr/src/test/util-tests/tests/ctf/check-merge-static.c
new file mode 100644
index 0000000000..3ca40eb5aa
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-static.c
@@ -0,0 +1,290 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Verify that various type information for static symbols is accurate for the
+ * file in question. To run this test, there's a global and static version of a
+ * symbol and function that exists on a per-file basis. These will all have been
+ * reproduced in the output file. As such, we need to iterate the symbol table
+ * to know which version should be which and use that to drive things.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <limits.h>
+#include <strings.h>
+
+#include "check-common.h"
+
+typedef struct check_map {
+ const char *map_file;
+ const char *map_type;
+} check_map_t;
+
+static const char *global_type = "int";
+static check_map_t map[] = {
+ { "test-a.c", "uint8_t" },
+ { "test-b.c", "uint16_t" },
+ { "test-c.c", "uint32_t" },
+ { "test-d.c", "uint64_t" },
+ { NULL }
+};
+
+static const char *
+check_file_to_type(GElf_Sym *symp, const char *file, const char *name)
+{
+ uint_t i;
+
+ if (ELF32_ST_BIND(symp->st_info) == STB_GLOBAL) {
+ return (global_type);
+ }
+
+ if (file == NULL) {
+ warnx("encountered non-global symbol without STT_FILE info: %s",
+ name);
+ return (NULL);
+ }
+
+ for (i = 0; map[i].map_file != NULL; i++) {
+ if (strcmp(map[i].map_file, file) == 0) {
+ return (map[i].map_type);
+ }
+ }
+
+ warnx("failed to find type mapping for symbol %s, file %s", name, file);
+ return (NULL);
+}
+
+static int
+check_global(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file,
+ const char *name)
+{
+ const char *type;
+ ctf_id_t tid;
+ char buf[2048];
+
+ if ((type = check_file_to_type(symp, file, name)) == NULL) {
+ return (EXIT_FAILURE);
+ }
+
+ if ((tid = ctf_lookup_by_symbol(fp, symid)) == CTF_ERR) {
+ warnx("failed to get type for symbol %s (%d): %s", name, symid,
+ ctf_errmsg(ctf_errno(fp)));
+ return (EXIT_FAILURE);
+ }
+
+ if (ctf_type_name(fp, tid, buf, sizeof (buf)) == NULL) {
+ warnx("failed to get type name for symbol %s (%d): %s",
+ name, symid, ctf_errmsg(ctf_errno(fp)));
+ return (EXIT_FAILURE);
+ }
+
+ if (strcmp(buf, type) != 0) {
+ warnx("type mismatch for symbol %s (%d): found %s, expected %s",
+ name, symid, buf, type);
+ return (EXIT_FAILURE);
+ }
+
+ return (0);
+}
+
+static int
+check_mumble(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file,
+ const char *name)
+{
+ const char *type;
+ ctf_funcinfo_t fi;
+ ctf_id_t id, args;
+
+ if ((type = check_file_to_type(symp, file, name)) == NULL) {
+ return (EXIT_FAILURE);
+ }
+
+ if ((id = ctf_lookup_by_name(fp, type)) == CTF_ERR) {
+ warnx("failed to lookup type id for %s: %s", type,
+ ctf_errmsg(ctf_errno(fp)));
+ return (EXIT_FAILURE);
+ }
+
+ if (ctf_func_info(fp, symid, &fi) != 0) {
+ warnx("failed to get function information for %s (%d): %s",
+ name, symid, ctf_errmsg(ctf_errno(fp)));
+ return (EXIT_FAILURE);
+ }
+
+ if (fi.ctc_argc != 1) {
+ warnx("argument count mismatch for symbol %s (%d): found %u, "
+ "expected %d", name, symid, fi.ctc_argc, 1);
+ return (EXIT_FAILURE);
+ }
+
+ if (fi.ctc_flags != 0) {
+ warnx("function flags mismatch for symbol %s (%d): found %u, "
+ "expected %d", name, symid, fi.ctc_flags, 0);
+ return (EXIT_FAILURE);
+ }
+
+ if (fi.ctc_return != id) {
+ warnx("return value mismatch for symbol %s (%d): found %ld, "
+ "expected %ld", name, symid, fi.ctc_return, id);
+ return (EXIT_FAILURE);
+ }
+
+ if (ctf_func_args(fp, symid, 1, &args) != 0) {
+ warnx("failed to get function arguments for symbol %s (%d): %s",
+ name, symid, ctf_errmsg(ctf_errno(fp)));
+ return (EXIT_FAILURE);
+ }
+
+ if (args != id) {
+ warnx("argument mismatch for symbol %s (%d): found %ld, "
+ "expected %ld", name, symid, args, id);
+ return (EXIT_FAILURE);
+ }
+
+ return (0);
+}
+
+static int
+check_merge_static(const char *file, ctf_file_t *fp, Elf *elf)
+{
+ Elf_Scn *scn = NULL, *symscn = NULL;
+ Elf_Data *symdata = NULL;
+ GElf_Shdr symhdr;
+ ulong_t nsyms;
+ int i;
+ const char *curfile = NULL;
+ int ret = 0;
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ if (gelf_getshdr(scn, &symhdr) == NULL) {
+ warnx("failed to get section header: %s",
+ elf_errmsg(elf_errno()));
+ return (EXIT_FAILURE);
+ }
+
+ if (symhdr.sh_type == SHT_SYMTAB) {
+ symscn = scn;
+ break;
+ }
+ }
+
+ if (symscn == NULL) {
+ warnx("failed to find symbol table for %s", file);
+ return (EXIT_FAILURE);
+ }
+
+ if ((symdata = elf_getdata(symscn, NULL)) == NULL) {
+ warnx("failed to get data for symbol table %s: %s", file,
+ elf_errmsg(elf_errno()));
+ return (EXIT_FAILURE);
+ }
+
+ if (symhdr.sh_link == SHN_XINDEX) {
+ warnx("test does not support extended ELF sections!");
+ return (EXIT_FAILURE);
+ }
+ nsyms = symhdr.sh_size / symhdr.sh_entsize;
+ if (nsyms > INT_MAX) {
+ warnx("file contains more symbols than libelf can iterate");
+ return (EXIT_FAILURE);
+ }
+
+ for (i = 1; i < (int)nsyms; i++) {
+ GElf_Sym sym;
+ const char *name;
+ uint_t type;
+
+ if (gelf_getsym(symdata, i, &sym) == NULL) {
+ warnx("failed to get data about symbol %d", i);
+ return (EXIT_FAILURE);
+ }
+
+ if ((name = elf_strptr(elf, symhdr.sh_link, sym.st_name)) ==
+ NULL) {
+ warnx("failed to get name for symbol %d", i);
+ return (EXIT_FAILURE);
+ }
+
+ type = GELF_ST_TYPE(sym.st_info);
+ if (type == STT_FILE) {
+ curfile = name;
+ continue;
+ }
+
+ if (strcmp(name, "global") == 0) {
+ ret |= check_global(fp, &sym, i, curfile, name);
+ } else if (strcmp(name, "mumble") == 0) {
+ ret |= check_mumble(fp, &sym, i, curfile, name);
+ }
+ }
+
+ return (ret);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ errx(EXIT_FAILURE, "failed to initialize libelf");
+ }
+
+ for (i = 1; i < argc; i++) {
+ int fd;
+ ctf_file_t *fp;
+ Elf *elf;
+
+ if ((fd = open(argv[i], O_RDONLY)) < 0) {
+ warn("failed to open %s", argv[i]);
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+ warnx("failed to open libelf handle to %s", argv[i]);
+ ret = EXIT_FAILURE;
+ (void) close(fd);
+ continue;
+ }
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ (void) close(fd);
+ (void) elf_end(elf);
+ continue;
+ }
+
+ if (check_merge_static(argv[i], fp, elf) != 0) {
+ ret = EXIT_FAILURE;
+ }
+
+ ctf_close(fp);
+ (void) close(fd);
+ (void) elf_end(elf);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-weak.c b/usr/src/test/util-tests/tests/ctf/check-merge-weak.c
new file mode 100644
index 0000000000..da6d37def8
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-merge-weak.c
@@ -0,0 +1,70 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle weak symbols.
+ */
+
+#include "check-common.h"
+
+
+static check_function_test_t functions[] = {
+ { "mumble", "int", 0, 0, NULL },
+ { "_mumble", "int", 0, 0, NULL },
+ { NULL }
+};
+
+static check_symbol_t check_syms[] = {
+ { "foo", "int" },
+ { "_foo", "int" },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t j;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+
+ for (j = 0; functions[j].cft_name != NULL; j++) {
+ if (!ctftest_check_function(functions[j].cft_name, fp,
+ functions[j].cft_rtype, functions[j].cft_nargs,
+ functions[j].cft_flags, functions[j].cft_args)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-reference.c b/usr/src/test/util-tests/tests/ctf/check-reference.c
new file mode 100644
index 0000000000..05c0469c15
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-reference.c
@@ -0,0 +1,197 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly understand reference types and can walk through them
+ * as well as generate them.
+ */
+
+#include "check-common.h"
+
+static check_number_t check_base[] = {
+ { "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 },
+ { "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
+ { "float", CTF_K_FLOAT, CTF_FP_SINGLE, 0, 32 },
+ { NULL }
+};
+
+static check_symbol_t check_syms[] = {
+ { "a", "int" },
+ { "aa", "test_int_t" },
+ { "b", "const short" },
+ { "c", "volatile float" },
+ { "d", "int *" },
+ { "dd", "int **" },
+ { "ddd", "int ***" },
+ { "e", "test_int_t *" },
+ { "ce", "const test_int_t *" },
+ { "ve", "volatile test_int_t *" },
+ { "cve", "const volatile test_int_t *" },
+ { "f", "int *const *" },
+ { "g", "const char *const" },
+ { NULL },
+};
+
+static check_descent_t check_descent_aa[] = {
+ { "test_int_t", CTF_K_TYPEDEF },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_b[] = {
+ { "const short", CTF_K_CONST },
+ { "short", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_c[] = {
+ { "volatile float", CTF_K_VOLATILE },
+ { "float", CTF_K_FLOAT },
+ { NULL }
+};
+
+static check_descent_t check_descent_d[] = {
+ { "int *", CTF_K_POINTER },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_dd[] = {
+ { "int **", CTF_K_POINTER },
+ { "int *", CTF_K_POINTER },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_ddd[] = {
+ { "int ***", CTF_K_POINTER },
+ { "int **", CTF_K_POINTER },
+ { "int *", CTF_K_POINTER },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_e[] = {
+ { "test_int_t *", CTF_K_POINTER },
+ { "test_int_t", CTF_K_TYPEDEF },
+ { "int", CTF_K_INTEGER },
+ { NULL },
+};
+
+static check_descent_t check_descent_ce[] = {
+ { "const test_int_t *", CTF_K_POINTER },
+ { "const test_int_t", CTF_K_CONST },
+ { "test_int_t", CTF_K_TYPEDEF },
+ { "int", CTF_K_INTEGER },
+ { NULL },
+};
+
+static check_descent_t check_descent_ve[] = {
+ { "volatile test_int_t *", CTF_K_POINTER},
+ { "volatile test_int_t", CTF_K_VOLATILE },
+ { "test_int_t", CTF_K_TYPEDEF },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_cve[] = {
+ { "const volatile test_int_t *", CTF_K_POINTER },
+ { "const volatile test_int_t", CTF_K_CONST },
+ { "volatile test_int_t", CTF_K_VOLATILE },
+ { "test_int_t", CTF_K_TYPEDEF },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_f[] = {
+ { "int *const *", CTF_K_POINTER },
+ { "int *const", CTF_K_CONST },
+ { "int *", CTF_K_POINTER },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_g[] = {
+ { "const char *const", CTF_K_CONST },
+ { "const char *", CTF_K_POINTER },
+ { "const char", CTF_K_CONST },
+ { "char", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_t check_descent_cvh[] = {
+ { "const volatile foo_t *", CTF_K_POINTER },
+ { "const volatile foo_t", CTF_K_CONST },
+ { "volatile foo_t", CTF_K_VOLATILE },
+ { "foo_t", CTF_K_TYPEDEF },
+ { "int *const *", CTF_K_POINTER },
+ { "int *const", CTF_K_CONST },
+ { "int *", CTF_K_POINTER },
+ { "int", CTF_K_INTEGER },
+ { NULL }
+};
+
+static check_descent_test_t descents[] = {
+ { "aa", check_descent_aa },
+ { "b", check_descent_b },
+ { "c", check_descent_c },
+ { "d", check_descent_d },
+ { "dd", check_descent_dd },
+ { "ddd", check_descent_ddd },
+ { "e", check_descent_e },
+ { "ce", check_descent_ce },
+ { "ve", check_descent_ve },
+ { "cve", check_descent_cve },
+ { "f", check_descent_f },
+ { "g", check_descent_g },
+ { "cvh", check_descent_cvh },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t d;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_numbers(fp, check_base))
+ ret = EXIT_FAILURE;
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+ for (d = 0; descents[d].cdt_sym != NULL; d++) {
+ if (!ctftest_check_descent(descents[d].cdt_sym, fp,
+ descents[d].cdt_tests)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-sou.c b/usr/src/test/util-tests/tests/ctf/check-sou.c
new file mode 100644
index 0000000000..32bcc20b6d
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-sou.c
@@ -0,0 +1,405 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle structures and unions.
+ */
+
+#include "check-common.h"
+
+static check_number_t check_bitfields[] = {
+#ifdef TARGET_LP64
+ { "unsigned long:1", CTF_K_INTEGER, 0, 0, 1 },
+ { "unsigned long:2", CTF_K_INTEGER, 0, 0, 2 },
+ { "unsigned long:4", CTF_K_INTEGER, 0, 0, 4 },
+ { "unsigned long:5", CTF_K_INTEGER, 0, 0, 5 },
+ { "unsigned long:8", CTF_K_INTEGER, 0, 0, 8 },
+ { "unsigned long:16", CTF_K_INTEGER, 0, 0, 16 },
+ { "unsigned long:19", CTF_K_INTEGER, 0, 0, 19 },
+ { "unsigned long:32", CTF_K_INTEGER, 0, 0, 32 },
+#else
+ { "unsigned long long:1", CTF_K_INTEGER, 0, 0, 1 },
+ { "unsigned long long:2", CTF_K_INTEGER, 0, 0, 2 },
+ { "unsigned long long:4", CTF_K_INTEGER, 0, 0, 4 },
+ { "unsigned long long:5", CTF_K_INTEGER, 0, 0, 5 },
+ { "unsigned long long:8", CTF_K_INTEGER, 0, 0, 8 },
+ { "unsigned long long:16", CTF_K_INTEGER, 0, 0, 16 },
+ { "unsigned long long:19", CTF_K_INTEGER, 0, 0, 19 },
+ { "unsigned long long:32", CTF_K_INTEGER, 0, 0, 32 },
+#endif
+ { "unsigned short:1", CTF_K_INTEGER, 0, 0, 1 },
+ { "unsigned int:7", CTF_K_INTEGER, 0, 0, 7 },
+ { "unsigned int:32", CTF_K_INTEGER, 0, 0, 32 },
+ { "int:3", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 3 },
+ { NULL }
+};
+
+static check_symbol_t check_syms[] = {
+ { "foo", "struct foo" },
+ { "head", "nlist_t" },
+ { "forward", "const forward_t" },
+ { "oot", "struct round_up" },
+ { "botw", "struct fixed_up" },
+ { "sophie", "struct mysterious_barrel" },
+ { "ayesha", "struct dusk_barrel" },
+ { "stats", "struct stats" },
+ { "ring", "struct fellowship" },
+ { "rings", "struct rings" },
+ { "nvme", "struct csts" },
+ { "games", "union jrpg" },
+ { "nier", "union nier" },
+ { "kh", "union kh" },
+ { "ct", "struct trigger" },
+ { "regress", "const union regress [9]" },
+ { NULL }
+};
+
+static check_member_t check_member_foo[] = {
+ { "a", "int", 0 },
+ { "b", "float", 4 * NBBY },
+ { "c", "const char *", 8 * NBBY },
+ { NULL }
+};
+
+static check_member_t check_member_node[] = {
+ { "prev", "struct node *", 0 },
+#ifdef TARGET_LP64
+ { "next", "struct node *", 8 * NBBY },
+#else
+ { "next", "struct node *", 4 * NBBY },
+#endif
+ { NULL }
+};
+
+static check_member_t check_member_nlist[] = {
+ { "size", "size_t", 0 },
+#ifdef TARGET_LP64
+ { "off", "size_t", 8 * NBBY },
+ { "head", "struct node", 16 * NBBY },
+#else
+ { "off", "size_t", 4 * NBBY },
+ { "head", "struct node", 8 * NBBY },
+#endif
+ { NULL }
+};
+
+static check_member_t check_member_forward[] = {
+ { "past", "void *", 0 },
+#ifdef TARGET_LP64
+ { "present", "void *", 8 * NBBY },
+ { "future", "void *", 16 * NBBY },
+#else
+ { "present", "void *", 4 * NBBY },
+ { "future", "void *", 8 * NBBY },
+#endif
+ { NULL }
+};
+
+static check_member_t check_member_round_up[] = {
+ { "triforce", "uint8_t", 0 },
+ { "link", "uint32_t", 4 * NBBY },
+ { "zelda", "uint8_t", 8 * NBBY },
+ { "ganon", "uint8_t", 9 * NBBY },
+ { NULL }
+};
+
+static check_member_t check_member_fixed_up[] = {
+ { "triforce", "uint8_t", 0 },
+ { "link", "uint32_t", 1 * NBBY },
+ { "zelda", "uint8_t", 5 * NBBY },
+ { "ganon", "uint8_t", 6 * NBBY },
+ { NULL }
+};
+
+#ifdef TARGET_LP64
+static check_member_t check_member_component[] = {
+ { "m", "enum material", 0 },
+ { "grade", "uint64_t", 8 * NBBY },
+ { "count", "uint64_t", 16 * NBBY },
+ { "locations", "const char *[4]", 24 * NBBY },
+ { NULL }
+};
+
+static check_member_t check_member_mysterious[] = {
+ { "name", "const char *", 0 },
+ { "capacity", "size_t", 8 * NBBY },
+ { "optional", "struct component [0]", 16 * NBBY },
+ { NULL }
+};
+
+static check_member_t check_member_dusk[] = {
+ { "name", "const char *", 0 },
+ { "opacity", "size_t", 8 * NBBY },
+ { "optional", "struct component [0]", 16 * NBBY },
+ { NULL }
+};
+
+
+static check_member_t check_member_stats[] = {
+ { "hp", "unsigned long:16", 0 },
+ { "mp", "unsigned long:16", 16 },
+ { "str", "unsigned long:8", 32 },
+ { "dex", "unsigned long:4", 40 },
+ { "con", "unsigned long:1", 44 },
+ { "inte", "unsigned long:2", 45 },
+ { "wis", "unsigned long:1", 47 },
+ { "cha", "unsigned long:4", 48 },
+ { "sanity", "unsigned long:1", 52 },
+ { "attack", "unsigned long:2", 53 },
+ { "mattack", "unsigned long:1", 55 },
+ { "defense", "unsigned long:8", 56 },
+ { "mdefense", "unsigned long:32", 64 },
+ { "evasion", "unsigned long:8", 96 },
+ { "crit", "unsigned long:5", 104 },
+ { "luck", "unsigned long:19", 109 },
+ { NULL }
+};
+#else
+static check_member_t check_member_component[] = {
+ { "m", "enum material", 0 },
+ { "grade", "uint64_t", 4 * NBBY },
+ { "count", "uint64_t", 12 * NBBY },
+ { "locations", "const char *[4]", 20 * NBBY },
+ { NULL }
+};
+
+static check_member_t check_member_mysterious[] = {
+ { "name", "const char *", 0 },
+ { "capacity", "size_t", 4 * NBBY },
+ { "optional", "struct component [0]", 8 * NBBY },
+ { NULL }
+};
+
+static check_member_t check_member_dusk[] = {
+ { "name", "const char *", 0 },
+ { "opacity", "size_t", 4 * NBBY },
+ { "optional", "struct component [0]", 8 * NBBY },
+ { NULL }
+};
+
+
+static check_member_t check_member_stats[] = {
+ { "hp", "unsigned long long:16", 0 },
+ { "mp", "unsigned long long:16", 16 },
+ { "str", "unsigned long long:8", 32 },
+ { "dex", "unsigned long long:4", 40 },
+ { "con", "unsigned long long:1", 44 },
+ { "inte", "unsigned long long:2", 45 },
+ { "wis", "unsigned long long:1", 47 },
+ { "cha", "unsigned long long:4", 48 },
+ { "sanity", "unsigned long long:1", 52 },
+ { "attack", "unsigned long long:2", 53 },
+ { "mattack", "unsigned long long:1", 55 },
+ { "defense", "unsigned long long:8", 56 },
+ { "mdefense", "unsigned long long:32", 64 },
+ { "evasion", "unsigned long long:8", 96 },
+ { "crit", "unsigned long long:5", 104 },
+ { "luck", "unsigned long long:19", 109 },
+ { NULL }
+};
+#endif
+
+static check_member_t check_member_fellowship[] = {
+ { "frodo", "unsigned short:1", 0 },
+ { "sam", "unsigned short:1", 1 },
+ { "merry", "unsigned short:1", 2 },
+ { "pippin", "unsigned short:1", 3 },
+ { "aragorn", "unsigned short:1", 4 },
+ { "boromir", "unsigned short:1", 5 },
+ { "legolas", "unsigned short:1", 6 },
+ { "gimli", "unsigned short:1", 7 },
+ { "gandalf", "unsigned short:1", 8 },
+ { NULL }
+};
+
+static check_member_t check_member_rings[] = {
+ { "elves", "unsigned int:3", 0 },
+ { "dwarves", "unsigned int:7", 3 },
+ { "men", "unsigned int:9", 10 },
+ { "one", "uint8_t", 3 * NBBY },
+ { "silmarils", "uint8_t [3]", 4 * NBBY },
+ { NULL }
+};
+
+static check_member_t check_member_csts[] = {
+ { "rdy", "unsigned int:7", 0 },
+ { "csts", "unsigned int:32", 7 },
+ { NULL }
+};
+
+static check_member_t check_member_jrpg[] = {
+ { "ff", "int", 0 },
+ { "atelier", "double [4]", 0 },
+ { "tales", "const char *", 0 },
+ { "chrono", "int (*)()", 0 },
+ { "xeno", "struct rings", 0 },
+ { NULL }
+};
+
+static check_member_t check_member_android[] = {
+ { "_2b", "unsigned int:16", 0 },
+ { "_9s", "unsigned int:16", 16 },
+ { NULL }
+};
+
+static check_member_t check_member_nier[] = {
+ { "automata", "uint32_t", 0 },
+ { "android", "struct android", 0 },
+ { NULL }
+};
+
+static check_member_t check_member_kh[] = {
+ { "sora", "int:3", 0 },
+ { "riku", "char:7", 0 },
+ { "kairi", "double", 0 },
+ { "namine", "complex double", 0 },
+ { NULL }
+};
+
+static check_member_t check_member_trigger[] = {
+ { "chrono", "uint8_t", 0 },
+ { "cross", "uint8_t", 8 },
+ /*
+ * This test has an anonymous union. Unfortunately, there's not a great
+ * way to distinguish between various anonymous unions in this form.
+ */
+#ifdef TARGET_LP64
+ { "", "union ", 64 },
+#else
+ { "", "union ", 32 },
+#endif
+ { NULL }
+};
+
+static check_member_t check_member_regress[] = {
+ { "i", "unsigned int [3]", 0 },
+ { "e", "long double", 0 },
+ { NULL }
+};
+
+static check_member_test_t members[] = {
+#ifdef TARGET_LP64
+ { "struct foo", CTF_K_STRUCT, 16, check_member_foo },
+ { "struct node", CTF_K_STRUCT, 16, check_member_node },
+ { "struct nlist", CTF_K_STRUCT, 32, check_member_nlist },
+ { "struct forward", CTF_K_STRUCT, 24, check_member_forward },
+#else
+ { "struct foo", CTF_K_STRUCT, 12, check_member_foo },
+ { "struct node", CTF_K_STRUCT, 8, check_member_node },
+ { "struct nlist", CTF_K_STRUCT, 16, check_member_nlist },
+ { "struct forward", CTF_K_STRUCT, 12, check_member_forward },
+#endif
+ { "struct round_up", CTF_K_STRUCT, 12, check_member_round_up },
+ { "struct fixed_up", CTF_K_STRUCT, 7, check_member_fixed_up },
+#ifdef TARGET_LP64
+ { "struct component", CTF_K_STRUCT, 56, check_member_component },
+ { "struct mysterious_barrel", CTF_K_STRUCT, 16,
+ check_member_mysterious },
+ { "struct dusk_barrel", CTF_K_STRUCT, 16, check_member_dusk },
+#else
+ { "struct component", CTF_K_STRUCT, 36, check_member_component },
+ { "struct mysterious_barrel", CTF_K_STRUCT, 8,
+ check_member_mysterious },
+ { "struct dusk_barrel", CTF_K_STRUCT, 8, check_member_dusk },
+#endif
+ { "struct stats", CTF_K_STRUCT, 16, check_member_stats },
+ { "struct fellowship", CTF_K_STRUCT, 2, check_member_fellowship },
+ { "struct rings", CTF_K_STRUCT, 8, check_member_rings },
+ { "struct csts", CTF_K_STRUCT, 5, check_member_csts },
+ { "union jrpg", CTF_K_UNION, 32, check_member_jrpg },
+ { "struct android", CTF_K_STRUCT, 4, check_member_android },
+ { "union nier", CTF_K_UNION, 4, check_member_nier },
+ { "union kh", CTF_K_UNION, 16, check_member_kh },
+#ifdef TARGET_LP64
+ { "struct trigger", CTF_K_STRUCT, 32, check_member_trigger },
+ { "union regress", CTF_K_UNION, 16, check_member_regress },
+#else
+ { "struct trigger", CTF_K_STRUCT, 28, check_member_trigger },
+ { "union regress", CTF_K_UNION, 12, check_member_regress },
+#endif
+ { NULL }
+};
+
+static check_descent_t check_descent_head[] = {
+ { "nlist_t", CTF_K_TYPEDEF },
+ { "struct nlist", CTF_K_STRUCT },
+ { NULL }
+};
+
+static check_descent_t check_descent_forward[] = {
+ { "const forward_t", CTF_K_CONST },
+ { "forward_t", CTF_K_TYPEDEF },
+ { "struct forward", CTF_K_STRUCT },
+ { NULL }
+};
+
+static check_descent_t check_descent_regress[] = {
+ { "const union regress [9]", CTF_K_CONST },
+ { "union regress [9]", CTF_K_ARRAY, "union regress", 9 },
+ { "union regress", CTF_K_UNION },
+ { NULL }
+};
+
+static check_descent_test_t descents[] = {
+ { "head", check_descent_head },
+ { "forward", check_descent_forward },
+ { "regress", check_descent_regress },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t j;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_numbers(fp, check_bitfields))
+ ret = EXIT_FAILURE;
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+ for (j = 0; descents[j].cdt_sym != NULL; j++) {
+ if (!ctftest_check_descent(descents[j].cdt_sym, fp,
+ descents[j].cdt_tests)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ for (j = 0; members[j].cmt_type != NULL; j++) {
+ if (!ctftest_check_members(members[j].cmt_type, fp,
+ members[j].cmt_kind, members[j].cmt_size,
+ members[j].cmt_members)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/check-weak.c b/usr/src/test/util-tests/tests/ctf/check-weak.c
new file mode 100644
index 0000000000..13e69e87de
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/check-weak.c
@@ -0,0 +1,70 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Check that we properly handle weak symbols.
+ */
+
+#include "check-common.h"
+
+
+static check_function_test_t functions[] = {
+ { "mumble", "int", 0, 0, NULL },
+ { "_mumble", "int", 0, 0, NULL },
+ { NULL }
+};
+
+static check_symbol_t check_syms[] = {
+ { "strong", "int" },
+ { "_strong", "int" },
+ { NULL }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, ret = 0;
+
+ if (argc < 2) {
+ errx(EXIT_FAILURE, "missing test files");
+ }
+
+ for (i = 1; i < argc; i++) {
+ ctf_file_t *fp;
+ uint_t j;
+
+ if ((fp = ctf_open(argv[i], &ret)) == NULL) {
+ warnx("failed to open %s: %s", argv[i],
+ ctf_errmsg(ret));
+ ret = EXIT_FAILURE;
+ continue;
+ }
+
+ if (!ctftest_check_symbols(fp, check_syms))
+ ret = EXIT_FAILURE;
+
+ for (j = 0; functions[j].cft_name != NULL; j++) {
+ if (!ctftest_check_function(functions[j].cft_name, fp,
+ functions[j].cft_rtype, functions[j].cft_nargs,
+ functions[j].cft_flags, functions[j].cft_args)) {
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ ctf_close(fp);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/ctftest.ksh b/usr/src/test/util-tests/tests/ctf/ctftest.ksh
new file mode 100644
index 0000000000..62f5cc5dd7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/ctftest.ksh
@@ -0,0 +1,257 @@
+#!/usr/bin/ksh
+#
+#
+# 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 (c) 2019, Joyent, Inc.
+#
+
+#
+# Run all of the various CTF tests
+#
+
+unalias -a
+#set -o xtrace
+
+if [[ -z "$TMPDIR" ]]; then
+ TMPDIR="/tmp"
+fi
+
+ctf_arg0=$(basename $0)
+ctf_root=$(cd $(dirname $0) && echo $PWD)
+ctf_tests=
+ctf_compiler="gcc"
+ctf_convert="ctfconvert"
+ctf_merge="ctfmerge"
+ctf_debugflags="-gdwarf-2 "
+ctf_mach32="-m32"
+ctf_mach64="-m64"
+ctf_32cflags="$ctf_mach32 $ctf_debugflags"
+ctf_64cflags="$ctf_mach64 $ctf_debugflags"
+ctf_temp="$TMPDIR/ctftest.$$.o"
+ctf_makefile="Makefile.ctftest"
+ctf_nerrs=0
+
+usage()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] || echo "$msg" >&2
+ cat <<USAGE >&2
+Usage: $ctf_arg0 [-c compiler] [-g flags] [-m ctfmerge] [-t ctfconvert]
+
+ Runs the CTF test suite
+
+ -c compiler Use the specified compiler, defaults to 'gcc'
+ on path.
+ -g flags Use flags to generate debug info. Defaults to
+ "-gdwarf-2".
+ -m ctfmerge Use the specified ctfmerge, defaults to
+ 'ctfmerge' on path.
+ -t ctfconvert Use the specified ctfconvert, defaults to
+ 'ctfconvert' on path.
+USAGE
+ exit 2
+}
+
+
+test_fail()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "TEST FAILED: $msg" >&2
+ ((ctf_nerrs++))
+}
+
+fatal()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "$ctf_arg0: $msg" >&2
+ rm -f "$ctf_tmp32" "$ctf_temp64"
+ exit 1
+}
+
+check_env()
+{
+ if which "$1" 2>/dev/null >/dev/null; then
+ return
+ fi
+
+ [[ -f "$1" ]] || fatal "failed to find tool $1"
+}
+
+announce()
+{
+ cat << EOF
+Beginning CTF tests with the following settings:
+COMPILER: $(which $ctf_compiler)
+CTFCONVERT: $(which $ctf_convert)
+CTFMERGE: $(which $ctf_merge)
+32-bit CFLAGS: $ctf_32cflags
+64-bit CFLAGS: $ctf_64cflags
+
+EOF
+}
+
+run_one()
+{
+ typeset source=$1 checker=$2 flags=$3
+
+ if ! "$ctf_compiler" $flags -o "$ctf_temp" -c "$source"; then
+ test_fail "failed to compile $source with flags: $flags"
+ return
+ fi
+
+ if ! "$ctf_convert" "$ctf_temp"; then
+ test_fail "failed to convert CTF in $source"
+ return
+ fi
+
+ if ! "$checker" "$ctf_temp"; then
+ test_fail "check for $source, $checker, failed"
+ return
+ fi
+
+ echo "TEST PASSED: $source $flags"
+}
+
+#
+# Perform a more complex build. The Makefile present will drive the
+# building of the artifacts and the running of the tests based on the
+# variables that we pass to it.
+#
+run_dir()
+{
+ typeset dir outdir check32 check64 flags32 flags64
+
+ dir=$1
+ outdir="$TMPDIR/ctftest.$$-$(basename $d)"
+ check32=$2
+ flags32=$3
+ check64=$4
+ flags64=$5
+
+ if ! mkdir $outdir; then
+ fatal "failed to make temporary directory '$outdir'"
+ fi
+
+ if ! make -C $dir -f Makefile.ctftest \
+ BUILDDIR="$outdir" \
+ CC="$ctf_compiler" \
+ CFLAGS32="$ctf_mach32" \
+ CFLAGS64="$ctf_mach64" \
+ DEBUGFLAGS="$ctf_debugflags" \
+ CTFCONVERT="$ctf_convert" \
+ CTFMERGE="$ctf_merge" \
+ build 1>/dev/null; then
+ rm -rf $outdir
+ test_fail "failed to build $dir"
+ return
+ fi
+
+ if ! make -C $dir -f Makefile.ctftest \
+ BUILDDIR="$outdir" \
+ CHECK32="$check32" \
+ CHECK64="$check64" \
+ run-test 1>/dev/null; then
+ rm -rf $outdir
+ test_fail "failed to run tests for $dir"
+ return
+ fi
+
+ rm -rf $outdir
+ echo "TEST PASSED: $dir (dir)"
+}
+
+#
+# Find all of the tests that exist and then try to run them all. Tests
+# may either be a single file or a directory.
+#
+run_tests()
+{
+ typeset t base check
+ ctf_tests=$(ls "$ctf_root"/*.c)
+ for t in $ctf_tests; do
+ base=$(basename "$t" .c)
+ check=$(echo "$base" | sed s/test-/check-/)
+ if [[ -f "$ctf_root/$check" ]]; then
+ run_one $t "$ctf_root/$check" "$ctf_32cflags"
+ run_one $t "$ctf_root/$check" "$ctf_64cflags"
+ elif [[ -f "$ctf_root/$check-32" && \
+ -f "$ctf_root/$check-64" ]]; then
+ run_one $t "$ctf_root/$check-32" "$ctf_32cflags"
+ run_one $t "$ctf_root/$check-64" "$ctf_64cflags"
+ else
+ test_fail "missing checker for $t"
+ fi
+ done
+
+ for d in $(find "$ctf_root" -maxdepth 1 -type d -name 'test-*'); do
+ [[ ! -f "$d/$ctf_makefile" ]] && continue
+ base=$(basename "$d")
+ check=$(echo "$base" | sed s/test-/check-/)
+ if [[ -f "$ctf_root/$check" ]]; then
+ run_dir $d "$ctf_root/$check" "$ctf_32cflags" \
+ "$ctf_root/$check" "$ctf_64cflags"
+ elif [[ -f "$ctf_root/$check-32" && \
+ -f "$ctf_root/$check-64" ]]; then
+ run_dir $d "$ctf_root/$check-32" "$ctf_32cflags" \
+ "$ctf_root/$check-64" "$ctf_64cflags"
+ else
+ test_fail "missing checker for $t"
+ fi
+ done
+}
+
+while getopts ":c:g:m:t:" c $@; do
+ case "$c" in
+ c)
+ ctf_compiler=$OPTARG
+ ;;
+ g)
+ ctf_debugflags=$OPTARG
+ ;;
+ m)
+ ctf_merge=$OPTARG
+ ;;
+ t)
+ ctf_convert=$OPTARG
+ ;;
+ :)
+ usage "option requires an argument -- $OPTARG"
+ ;;
+ *)
+ usage "invalid option -- $OPTARG"
+ ;;
+ esac
+done
+
+ctf_32cflags="$ctf_mach32 $ctf_debugflags"
+ctf_64cflags="$ctf_mach64 $ctf_debugflags"
+
+check_env "$ctf_compiler"
+check_env "$ctf_convert"
+check_env "$ctf_merge"
+announce
+
+run_tests
+
+if [[ $ctf_nerrs -ne 0 ]]; then
+ if [[ $ctf_nerrs -eq 1 ]]; then
+ printf "\n%s: %u test failed\n" "$ctf_arg0" "$ctf_nerrs"
+ else
+ printf "\n%s: %u tests failed\n" "$ctf_arg0" "$ctf_nerrs"
+ fi
+else
+ printf "\n%s: All tests passed successfully\n" "$ctf_arg0"
+ exit 0
+fi
diff --git a/usr/src/test/util-tests/tests/ctf/test-array.c b/usr/src/test/util-tests/tests/ctf/test-array.c
new file mode 100644
index 0000000000..9c15771caf
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-array.c
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * A series of basic array tests with simple base types.
+ */
+
+int a[3];
+double b[42];
+const char *c[] = { "17" "31", "169" };
+
+int d[4][5];
+int e[4][5][6];
+int f[4][5][6][7];
+int g[4][5][6][7][8];
+int h[4][5][6][7][8][9];
+int i[4][5][6][7][8][9][10];
diff --git a/usr/src/test/util-tests/tests/ctf/test-enum.c b/usr/src/test/util-tests/tests/ctf/test-enum.c
new file mode 100644
index 0000000000..f6bfbfccb0
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-enum.c
@@ -0,0 +1,74 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#include <stdint.h>
+
+/*
+ * Basic sanity checking of enumerations, using specific numbers and arbitrary
+ * numbers.
+ */
+
+enum ff6 {
+ TERRA,
+ LOCKE,
+ EDGAR,
+ SABIN,
+ CELES,
+ CYAN,
+ SHADOW,
+ GAU,
+ SETZER,
+ STRAGO,
+ RELM,
+ MOG,
+ GOGO,
+ UMARO,
+ LEO,
+ KEFKA
+};
+
+typedef enum ff10 {
+ TIDUS = -10,
+ YUNA = 23,
+ AURON = -34,
+ WAKA = 52,
+ LULU = INT32_MAX,
+ RIKKU = INT32_MIN,
+ KHIMARI = 0
+} ff10_t;
+
+/*
+ * The following enum is copy of the ddi_hp_cn_state_t enumeration which was
+ * previously incorrectly converted by the tools. Notably, we always assumed
+ * that the DWARF enum values were signed; however, in this case we needed to
+ * check for an unsigned version before a signed version, otherwise some of the
+ * entries below will have the wrong values.
+ */
+typedef enum chrono {
+ CRONO = 0x1000,
+ LUCCA = 0x2000,
+ MARLE = 0x3000,
+ FROG = 0x4000,
+ ROBO = 0x5000,
+ AYLA = 0x6000,
+ MAGUS = 0x7000,
+ SCHALA = 0x8000,
+ LAVOS = 0x9000,
+ BALTHAZAR = 0xa000
+} chrono_t;
+
+enum ff6 ff6;
+ff10_t ff10;
+chrono_t trigger;
diff --git a/usr/src/test/util-tests/tests/ctf/test-float.c b/usr/src/test/util-tests/tests/ctf/test-float.c
new file mode 100644
index 0000000000..ddec7a7167
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-float.c
@@ -0,0 +1,28 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#include <complex.h>
+
+/*
+ * Test floating point types. Unfortunately neither gcc nor clang support the
+ * imaginary keyword which means that we cannot test it.
+ */
+
+float a;
+double b;
+long double c;
+float complex d;
+double complex e;
+long double complex f;
diff --git a/usr/src/test/util-tests/tests/ctf/test-forward.c b/usr/src/test/util-tests/tests/ctf/test-forward.c
new file mode 100644
index 0000000000..4aa0fa2486
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-forward.c
@@ -0,0 +1,34 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * This tests the use of forward declarations of unknown types.
+ */
+
+struct foo;
+union bar;
+enum baz;
+
+struct forward {
+ struct foo *prev;
+ struct foo *next;
+ union bar *data;
+ enum baz *tag;
+};
+
+struct foo *foop;
+union bar *barp;
+enum baz *bazp;
+struct forward forward;
diff --git a/usr/src/test/util-tests/tests/ctf/test-function.c b/usr/src/test/util-tests/tests/ctf/test-function.c
new file mode 100644
index 0000000000..af999b5c78
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-function.c
@@ -0,0 +1,71 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Test various function and function pointer cases.
+ */
+
+static void
+simple_func(void)
+{
+}
+
+static void
+one(int v)
+{
+}
+
+static void
+two(int v, const char *a)
+{
+}
+
+static void
+three(int v, const char *a, float b)
+{
+}
+
+static const char *
+noarg(void)
+{
+ return ("hello, world");
+}
+
+static const char *
+argument(uintptr_t base)
+{
+ return ((const char *)(base + 1));
+}
+
+static void
+vararg(const char *foo, ...)
+{
+
+}
+
+static uintptr_t
+vararg_ret(const char *foo, ...)
+{
+ return ((uintptr_t)foo);
+}
+
+typedef int (*strfunc_t)(const char *, const char *);
+typedef void (*vararg_t)(const char *, ...);
+
+strfunc_t s = strcmp;
+vararg_t v = vararg;
diff --git a/usr/src/test/util-tests/tests/ctf/test-int.c b/usr/src/test/util-tests/tests/ctf/test-int.c
new file mode 100644
index 0000000000..d7cca69956
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-int.c
@@ -0,0 +1,34 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Test basic integer types. Note that signed types are considered the same as
+ * the base type.
+ */
+
+char a;
+unsigned char b;
+
+short d;
+unsigned short e;
+
+int g;
+unsigned int h;
+
+long j;
+unsigned long k;
+
+long long m;
+unsigned long long n;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest
new file mode 100644
index 0000000000..e19e461a1a
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest
@@ -0,0 +1,39 @@
+#
+# 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 2019 Joyent, Inc.
+#
+
+TEST = test-merge-dedup
+
+OBJS_C_32 = $(BUILDDIR)/test-merge-1.32.c.o \
+ $(BUILDDIR)/test-merge-2.32.c.o \
+ $(BUILDDIR)/test-merge-3.32.c.o \
+ $(BUILDDIR)/test-merge-dedup.32.c.o
+
+OBJS_C_64 = $(BUILDDIR)/test-merge-1.64.c.o \
+ $(BUILDDIR)/test-merge-2.64.c.o \
+ $(BUILDDIR)/test-merge-3.64.c.o \
+ $(BUILDDIR)/test-merge-dedup.64.c.o
+
+OBJS_M_32 = $(BUILDDIR)/test-merge-1.32.m.o \
+ $(BUILDDIR)/test-merge-2.32.m.o \
+ $(BUILDDIR)/test-merge-3.32.m.o \
+ $(BUILDDIR)/test-merge-dedup.32.m.o
+
+OBJS_M_64 = $(BUILDDIR)/test-merge-1.64.m.o \
+ $(BUILDDIR)/test-merge-2.64.m.o \
+ $(BUILDDIR)/test-merge-3.64.m.o \
+ $(BUILDDIR)/test-merge-dedup.64.m.o
+
+
+include ../Makefile.ctftest.com
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c
new file mode 100644
index 0000000000..7119026d83
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c
@@ -0,0 +1,27 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+int f;
+short g;
+const char *h;
+float i;
+double j;
+
+struct dup {
+ int dup;
+ int dup2;
+};
+
+struct dup dup1;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c
new file mode 100644
index 0000000000..5d3da5b082
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c
@@ -0,0 +1,27 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+int k;
+short l;
+const char *m;
+float n;
+double o;
+
+struct dup {
+ int dup;
+ int dup2;
+};
+
+struct dup dup2;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c
new file mode 100644
index 0000000000..81ed216743
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c
@@ -0,0 +1,27 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+int p;
+short q;
+const char *r;
+float s;
+double t;
+
+struct dup {
+ int dup;
+ int dup2;
+};
+
+struct dup dup3;
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c
new file mode 100644
index 0000000000..798457bd05
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c
@@ -0,0 +1,33 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+int a;
+short b;
+const char *c;
+float d;
+double e;
+
+struct dup {
+ int dup;
+ int dup2;
+};
+
+struct dup dupmain;
+
+int
+main(int argc, const char *argv[])
+{
+ return (0);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest
new file mode 100644
index 0000000000..270264370e
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest
@@ -0,0 +1,30 @@
+#
+# 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.c.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+TEST = test-merge-forward
+
+OBJS_C_32 = $(BUILDDIR)/test-merge.32.c.o \
+ $(BUILDDIR)/test-impl.32.c.o
+
+OBJS_C_64 = $(BUILDDIR)/test-merge.64.c.o \
+ $(BUILDDIR)/test-impl.64.c.o
+
+OBJS_M_32 = $(BUILDDIR)/test-merge.32.m.o \
+ $(BUILDDIR)/test-impl.32.m.o
+
+OBJS_M_64 = $(BUILDDIR)/test-merge.64.m.o \
+ $(BUILDDIR)/test-impl.64.m.o
+
+include ../Makefile.ctftest.com
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c
new file mode 100644
index 0000000000..c4319032a0
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+struct foo {
+ struct foo *next;
+ int left;
+ int right;
+ int count;
+};
+
+void
+mumble(struct foo *foo)
+{
+ foo->left = foo->right - foo->count;
+ foo->count += foo->right;
+ foo->right--;
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c
new file mode 100644
index 0000000000..ab986d920b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c
@@ -0,0 +1,32 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#include <stdio.h>
+
+struct foo;
+
+typedef struct foo_list {
+ int count;
+ struct foo *head;
+ struct foo *tail;
+} foo_list_t;
+
+foo_list_t list;
+
+int
+main(void)
+{
+ (void) printf("%p", &list);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest
new file mode 100644
index 0000000000..3cf1fd647f
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest
@@ -0,0 +1,92 @@
+#
+# 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 2019 Joyent, Inc.
+#
+
+#
+# This makefile could be simplified substantially. However, it does
+# everything explicitly to try and work with a wide variety of different
+# makes.
+#
+# The following values should be passed in by the invoker of the
+# Makefile:
+#
+# CC C Compiler to use
+# CFLAGS32 32-bit CFLAGS
+# CFLAGS64 64-bit CFLAGS
+# CTFCONVERT Path to ctfconvert
+# CTFMERGE Path to ctfmerge
+# DEBUGFLAGS The set of debug flags to use
+# BUILDDIR Directory things should be built in
+# CHECK32 Program to check 32-bit output
+# CHECK64 Program to check 64-bit output
+#
+
+OBJS_C_32 = $(BUILDDIR)/test-global.32.c.o \
+ $(BUILDDIR)/test-scoped.32.c.o
+
+OBJS_C_64 = $(BUILDDIR)/test-global.64.c.o \
+ $(BUILDDIR)/test-scoped.64.c.o
+
+OBJS_M_32 = $(BUILDDIR)/test-global.32.m.o \
+ $(BUILDDIR)/test-scoped.32.m.o
+
+OBJS_M_64 = $(BUILDDIR)/test-global.64.m.o \
+ $(BUILDDIR)/test-scoped.64.m.o
+
+BINS = $(BUILDDIR)/test-merge-reduction-32c.so.1 \
+ $(BUILDDIR)/test-merge-reduction-32m.so.1 \
+ $(BUILDDIR)/test-merge-reduction-64c.so.1 \
+ $(BUILDDIR)/test-merge-reduction-64m.so.1 \
+
+CFLAGS = -fPIC
+LDFLAGS = -shared -Wl,-Mmapfile-vers -Wl,-ztext -Wl,-zdefs \
+ -htest-merge-reduction.so.1
+
+build: $(BINS)
+
+$(BUILDDIR)/%.32.c.o: %.c
+ $(CC) $(CFLAGS) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.64.c.o: %.c
+ $(CC) $(CFLAGS) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+
+$(BUILDDIR)/%.32.m.o: %.c
+ $(CC) $(CFLAGS) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $<
+ $(CTFCONVERT) $@
+
+$(BUILDDIR)/%.64.m.o: %.c
+ $(CC) $(CFLAGS) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $<
+ $(CTFCONVERT) $@
+
+$(BUILDDIR)/test-merge-reduction-32c.so.1: $(OBJS_C_32)
+ $(CC) $(CFLAGS32) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_C_32)
+ $(CTFCONVERT) $@
+
+$(BUILDDIR)/test-merge-reduction-64c.so.1: $(OBJS_C_64)
+ $(CC) $(CFLAGS64) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_C_64)
+ $(CTFCONVERT) $@
+
+$(BUILDDIR)/test-merge-reduction-32m.so.1: $(OBJS_M_32)
+ $(CC) $(CFLAGS32) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_M_32)
+ $(CTFMERGE) -t -o $@ $(OBJS_M_32)
+
+$(BUILDDIR)/test-merge-reduction-64m.so.1: $(OBJS_M_64)
+ $(CC) $(CFLAGS64) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_M_64)
+ $(CTFMERGE) -t -o $@ $(OBJS_M_64)
+
+run-test:
+ $(CHECK32) $(BUILDDIR)/test-merge-reduction-32c.so.1
+ $(CHECK64) $(BUILDDIR)/test-merge-reduction-64c.so.1
+ $(CHECK32) $(BUILDDIR)/test-merge-reduction-32m.so.1
+ $(CHECK64) $(BUILDDIR)/test-merge-reduction-64m.so.1
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers
new file mode 100644
index 0000000000..c1e47627ad
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers
@@ -0,0 +1,37 @@
+#
+# 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 2019 Joyent, Inc.
+#
+
+#
+# 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 CTFTEST {
+ global:
+ global;
+ local:
+ *;
+};
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c
new file mode 100644
index 0000000000..09f2914c12
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c
@@ -0,0 +1,25 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+
+#include <stdlib.h>
+
+extern int scoped(uint32_t);
+
+int
+global(void)
+{
+ return (scoped(arc4random()));
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c
new file mode 100644
index 0000000000..a30fe7a7b7
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+
+int data;
+
+int
+scoped(uint32_t a)
+{
+ if (a >= INT32_MAX) {
+ data = a - INT32_MAX;
+ }
+
+ return (data);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest
new file mode 100644
index 0000000000..7d5a875bce
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest
@@ -0,0 +1,42 @@
+#
+# 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 2019 Joyent, Inc.
+#
+
+TEST = test-merge-static
+
+OBJS_C_32 = $(BUILDDIR)/test-a.32.c.o \
+ $(BUILDDIR)/test-b.32.c.o \
+ $(BUILDDIR)/test-c.32.c.o \
+ $(BUILDDIR)/test-d.32.c.o \
+ $(BUILDDIR)/test-main.32.c.o
+
+OBJS_C_64 = $(BUILDDIR)/test-a.64.c.o \
+ $(BUILDDIR)/test-b.64.c.o \
+ $(BUILDDIR)/test-c.64.c.o \
+ $(BUILDDIR)/test-d.64.c.o \
+ $(BUILDDIR)/test-main.64.c.o
+
+OBJS_M_32 = $(BUILDDIR)/test-a.32.m.o \
+ $(BUILDDIR)/test-b.32.m.o \
+ $(BUILDDIR)/test-c.32.m.o \
+ $(BUILDDIR)/test-d.32.m.o \
+ $(BUILDDIR)/test-main.32.m.o
+
+OBJS_M_64 = $(BUILDDIR)/test-a.64.m.o \
+ $(BUILDDIR)/test-b.64.m.o \
+ $(BUILDDIR)/test-c.64.m.o \
+ $(BUILDDIR)/test-d.64.m.o \
+ $(BUILDDIR)/test-main.64.m.o
+
+include ../Makefile.ctftest.com
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c
new file mode 100644
index 0000000000..749e9fbd22
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c
@@ -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 (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint8_t global;
+
+static uint8_t
+mumble(uint8_t a)
+{
+ return (a);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c
new file mode 100644
index 0000000000..7fca620966
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c
@@ -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 (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint16_t global;
+
+static uint16_t
+mumble(uint16_t a)
+{
+ return (a);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c
new file mode 100644
index 0000000000..2627cec22c
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c
@@ -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 (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint32_t global;
+
+static uint32_t
+mumble(uint32_t a)
+{
+ return (a);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c
new file mode 100644
index 0000000000..516b6c2fa2
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c
@@ -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 (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+
+static uint64_t global;
+
+static uint64_t
+mumble(uint64_t a)
+{
+ return (a);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c
new file mode 100644
index 0000000000..e645302f8b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c
@@ -0,0 +1,28 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+int global;
+
+int
+mumble(int a)
+{
+ return (a);
+}
+
+int
+main(void)
+{
+ return (0);
+}
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest
new file mode 100644
index 0000000000..35b3ecf69c
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest
@@ -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.c.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+TEST = test-merge-weak
+
+OBJS_C_32 = $(BUILDDIR)/test-merge-weak.32.c.o
+OBJS_C_64 = $(BUILDDIR)/test-merge-weak.64.c.o
+OBJS_M_32 = $(BUILDDIR)/test-merge-weak.32.m.o
+OBJS_M_64 = $(BUILDDIR)/test-merge-weak.64.m.o
+
+include ../Makefile.ctftest.com
diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c b/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c
new file mode 100644
index 0000000000..7d47c02fea
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c
@@ -0,0 +1,33 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#include <stdlib.h>
+
+#pragma weak mumble = _mumble
+#pragma weak foo = _foo
+
+int _foo = 5;
+
+int
+_mumble(void)
+{
+ return ((int)arc4random());
+}
+
+int
+main(void)
+{
+ return (mumble());
+};
diff --git a/usr/src/test/util-tests/tests/ctf/test-reference.c b/usr/src/test/util-tests/tests/ctf/test-reference.c
new file mode 100644
index 0000000000..b738a2e429
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-reference.c
@@ -0,0 +1,44 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+/*
+ * Test the encoding of references to another type. Specifically the references
+ * that we generally care about are things like:
+ *
+ * o pointers
+ * o typedefs
+ * o const
+ * o volatile
+ * o restrict
+ */
+
+int a;
+typedef int test_int_t;
+test_int_t aa;
+const short b;
+volatile float c;
+
+int *d;
+int **dd;
+int ***ddd;
+test_int_t *e;
+const test_int_t *ce;
+volatile test_int_t *ve;
+volatile const test_int_t *cve;
+int *const *f;
+const char *const g;
+
+typedef int *const * foo_t;
+const volatile foo_t *cvh;
diff --git a/usr/src/test/util-tests/tests/ctf/test-sou.c b/usr/src/test/util-tests/tests/ctf/test-sou.c
new file mode 100644
index 0000000000..8194248df5
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-sou.c
@@ -0,0 +1,246 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <complex.h>
+
+/*
+ * Test various structure and union constructs, including various things that
+ * have caused regressions in the past.
+ */
+
+/*
+ * Basic, simple struct.
+ */
+struct foo {
+ int a;
+ float b;
+ const char *c;
+};
+
+struct foo foo;
+
+/*
+ * Self-referential structs
+ */
+struct node {
+ struct node *prev;
+ struct node *next;
+};
+
+typedef struct nlist {
+ size_t size;
+ size_t off;
+ struct node head;
+} nlist_t;
+
+nlist_t head;
+
+/*
+ * Struct that has a forward declaration.
+ */
+typedef struct forward forward_t;
+struct forward {
+ void *past;
+ void *present;
+ void *future;
+};
+
+const forward_t forward;
+
+/*
+ * Here, we have a pair of structures that basically round up to different
+ * sizes. As in, the size of the structure is somewhat compiler dependent.
+ */
+struct round_up {
+ uint8_t triforce;
+ uint32_t link;
+ uint8_t zelda;
+ uint8_t ganon;
+};
+
+#pragma pack(1)
+struct fixed_up {
+ uint8_t triforce;
+ uint32_t link;
+ uint8_t zelda;
+ uint8_t ganon;
+};
+#pragma pack()
+
+struct round_up oot;
+struct fixed_up botw;
+
+/*
+ * Various GNU and c99 style arrays
+ */
+enum material {
+ COPPER,
+ IRON,
+ STEEL,
+ ADAMANTIUM,
+ MYTHRIL,
+ ORIHALCUM
+};
+
+struct component {
+ enum material m;
+ uint64_t grade;
+ uint64_t count;
+ const char *locations[4];
+};
+
+struct mysterious_barrel {
+ const char *name;
+ size_t capacity;
+ struct component optional[];
+};
+
+struct dusk_barrel {
+ const char *name;
+ size_t opacity;
+ struct component optional[0];
+};
+
+struct mysterious_barrel sophie;
+struct dusk_barrel ayesha;
+
+/*
+ * Various bitfield forms.
+ */
+
+/*
+ * Variant of the Intel system_desc.
+ */
+struct stats {
+ uint64_t hp:16;
+ uint64_t mp:16;
+ uint64_t str:8;
+ uint64_t dex:4;
+ uint64_t con:1;
+ uint64_t inte:2;
+ uint64_t wis:1;
+ uint64_t cha:4;
+ uint64_t sanity:1;
+ uint64_t attack:2;
+ uint64_t mattack:1;
+ uint64_t defense:8;
+ uint64_t mdefense:32;
+ uint64_t evasion:8;
+ uint64_t crit:5;
+ uint64_t luck:19;
+};
+
+struct stats stats;
+
+/*
+ * More odd length structures due to bitfields
+ */
+struct fellowship {
+ uint16_t frodo:1;
+ uint16_t sam:1;
+ uint16_t merry:1;
+ uint16_t pippin:1;
+ uint16_t aragorn:1;
+ uint16_t boromir:1;
+ uint16_t legolas:1;
+ uint16_t gimli:1;
+ uint16_t gandalf:1;
+};
+
+struct fellowship ring;
+
+struct rings {
+ uint32_t elves:3;
+ uint32_t dwarves:7;
+ uint32_t men:9;
+ uint8_t one;
+ uint8_t silmarils[3];
+};
+
+struct rings rings;
+
+/*
+ * Regression, we didn't handle receiving a negative offset from DWARF with
+ * this.
+ */
+#pragma pack(1)
+struct csts {
+ unsigned int rdy:7;
+ unsigned int csts:32;
+};
+
+struct csts nvme;
+#pragma pack()
+
+/*
+ * Onto unions
+ */
+union jrpg {
+ int ff;
+ double atelier[4];
+ const char *tales;
+ int (*chrono)(void);
+ struct rings xeno;
+};
+
+union jrpg games;
+
+#pragma pack(1)
+struct android {
+ uint32_t _2b:16;
+ uint32_t _9s:16;
+};
+
+union nier {
+ uint32_t automata;
+ struct android android;
+};
+#pragma pack()
+
+union nier nier;
+
+union kh {
+ int sora:3;
+ char riku:7;
+ double kairi;
+ complex double namine;
+};
+
+union kh kh;
+
+/*
+ * Anonymous union in a struct, GNU extension / C11
+ */
+
+struct trigger {
+ uint8_t chrono;
+ uint8_t cross;
+ union {
+ void *lavos;
+ int *crono;
+ uint64_t schala[3];
+ };
+};
+
+struct trigger ct;
+
+/*
+ * This is an array/union combo that failed conversion previously.
+ */
+static const union regress {
+ unsigned int i[3];
+ long double e;
+} regress[9];
diff --git a/usr/src/test/util-tests/tests/ctf/test-weak.c b/usr/src/test/util-tests/tests/ctf/test-weak.c
new file mode 100644
index 0000000000..d07981f369
--- /dev/null
+++ b/usr/src/test/util-tests/tests/ctf/test-weak.c
@@ -0,0 +1,25 @@
+/*
+ * 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 (c) 2019, Joyent, Inc.
+ */
+
+#pragma weak _strong = strong
+#pragma weak _mumble = mumble
+
+int strong = 3;
+
+int
+mumble(void)
+{
+ return (42);
+}
diff --git a/usr/src/test/util-tests/tests/demangle/Makefile b/usr/src/test/util-tests/tests/demangle/Makefile
index fd64f0a2f4..f5522772db 100644
--- a/usr/src/test/util-tests/tests/demangle/Makefile
+++ b/usr/src/test/util-tests/tests/demangle/Makefile
@@ -11,6 +11,7 @@
#
# Copyright 2018 Jason King.
+# Copyright 2019, Joyent, Inc.
#
include $(SRC)/Makefile.master
@@ -19,7 +20,7 @@ include $(SRC)/test/Makefile.com
ROOTBINDIR = $(ROOTOPTPKG)/bin
-PROG = gcc-libstdc++ llvm-stdcxxabi afl-fast
+PROG = gcc-libstdc++ llvm-stdcxxabi afl-fast rust
ROOTOPTPKG = $(ROOT)/opt/util-tests
TESTDIR = $(ROOTOPTPKG)/tests/demangle
@@ -32,7 +33,7 @@ SRCS = $(OBJS:%.o=%.c)
CSTD = $(CSTD_GNU99)
-LDLIBS += -ldemangle-sys
+LDLIBS += -ldemangle-sys -lumem
all: $(PROG)
@@ -48,6 +49,10 @@ afl-fast: afl-fast.o
$(LINK.c) -o $@ afl-fast.o $(LDLIBS)
$(POST_PROCESS)
+rust: rust.o
+ $(LINK.c) -o $@ rust.o $(LDLIBS)
+ $(POST_PROCESS)
+
install: all $(CMDS)
lint:
diff --git a/usr/src/test/util-tests/tests/demangle/rust.c b/usr/src/test/util-tests/tests/demangle/rust.c
new file mode 100644
index 0000000000..0b13c9db7e
--- /dev/null
+++ b/usr/src/test/util-tests/tests/demangle/rust.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2014 Alex Crichton
+ *
+ * Permission is hereby granted, free of charge, to any
+ * person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the
+ * Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software
+ * is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice
+ * shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+ * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * Copyright 2019, Joyent, Inc.
+ */
+
+/*
+ * Test cases taken from rustc-demangle 0.1.9
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/sysmacros.h>
+#include <demangle-sys.h>
+
+typedef struct rust_test_case {
+ const char *mangled;
+ const char *demangled;
+} rust_test_case_t;
+#define T(_m, _d) { .mangled = _m, .demangled = _d }
+#define T_ERR(_m) { .mangled = _m }
+
+typedef struct rust_test_grp {
+ const char *name;
+ rust_test_case_t tests[];
+} rust_test_grp_t;
+#define GROUP(_n, ...) \
+ static rust_test_grp_t _n = { \
+ .name = #_n, \
+ .tests = { \
+ __VA_ARGS__, \
+ { NULL, NULL } \
+ } \
+ }
+
+GROUP(demangle,
+ T_ERR("test"),
+ T("_ZN4testE", "test"),
+ T_ERR("_ZN4test"),
+ T("_ZN4test1a2bcE", "test::a::bc"));
+
+GROUP(demangle_dollars,
+ T("_ZN4$RP$E", ")"),
+ T("_ZN8$RF$testE", "&test"),
+ T("_ZN8$BP$test4foobE", "*test::foob"),
+ T("_ZN9$u20$test4foobE", " test::foob"),
+ T("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"));
+
+GROUP(demangle_many_dollars,
+ T("_ZN13test$u20$test4foobE", "test test::foob"),
+ T("_ZN12test$BP$test4foobE", "test*test::foob"));
+
+/* BEGIN CSTYLED */
+GROUP(demangle_osx,
+ T("__ZN5alloc9allocator6Layout9for_value17h02a996811f781011E",
+ "alloc::allocator::Layout::for_value::h02a996811f781011"),
+ T("__ZN38_$LT$core..option..Option$LT$T$GT$$GT$6unwrap18_MSG_FILE_LINE_COL17haf7cb8d5824ee659E",
+ "<core::option::Option<T>>::unwrap::_MSG_FILE_LINE_COL::haf7cb8d5824ee659"),
+ T("__ZN4core5slice89_$LT$impl$u20$core..iter..traits..IntoIterator$u20$for$u20$$RF$$u27$a$u20$$u5b$T$u5d$$GT$9into_iter17h450e234d27262170E",
+ "core::slice::<impl core::iter::traits::IntoIterator for &'a [T]>::into_iter::h450e234d27262170"));
+/* END CSTYLED */
+
+GROUP(demangle_elements_beginning_with_underscore,
+ T("_ZN13_$LT$test$GT$E", "<test>"),
+ T("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"),
+ T("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"));
+
+/* BEGIN CSTYLED */
+GROUP(demangle_trait_impls,
+ T("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE",
+ "<Test + 'static as foo::Bar<Test>>::bar"));
+/* END CSTYLED */
+
+GROUP(invalid_no_chop, T_ERR("_ZNfooE"));
+
+/* BEGIN CSTYLED */
+GROUP(handle_assoc_types,
+ T("_ZN151_$LT$alloc..boxed..Box$LT$alloc..boxed..FnBox$LT$A$C$$u20$Output$u3d$R$GT$$u20$$u2b$$u20$$u27$a$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$9call_once17h69e8f44b3723e1caE",
+ "<alloc::boxed::Box<alloc::boxed::FnBox<A, Output=R> + 'a> as core::ops::function::FnOnce<A>>::call_once::h69e8f44b3723e1ca"));
+/* END CSTYLED */
+
+static rust_test_grp_t *rust_tests[] = {
+ &demangle,
+ &demangle_dollars,
+ &demangle_many_dollars,
+ &demangle_osx,
+ &demangle_elements_beginning_with_underscore,
+ &demangle_trait_impls,
+ &invalid_no_chop,
+ &handle_assoc_types
+};
+
+static const size_t n_rust_tests = ARRAY_SIZE(rust_tests);
+
+static boolean_t
+check_failure(size_t i, rust_test_case_t *tc, const char *dem, boolean_t res)
+{
+ int savederr = errno;
+
+ if (dem == NULL && savederr == EINVAL)
+ return (B_TRUE);
+
+ if (res)
+ (void) printf("FAILURE\n");
+
+ if (dem != NULL) {
+ (void) printf(" [%zu] Successfully demanged an invalid "
+ "name\n", i);
+ (void) printf(" Name: '%s'\n", tc->mangled);
+ (void) printf(" Demangled: '%s'\n", dem);
+ return (B_FALSE);
+ }
+
+ (void) printf(" [%zu] demangle() returned an unexpected error\n", i);
+ (void) printf(" Errno: %d\n", savederr);
+ return (B_FALSE);
+}
+
+static boolean_t
+check_success(size_t i, rust_test_case_t *tc, const char *dem, boolean_t res)
+{
+ if (dem != NULL && strcmp(tc->demangled, dem) == 0)
+ return (B_TRUE);
+
+ if (res)
+ (void) printf("FAILURE\n");
+
+ if (dem == NULL) {
+ (void) printf(" [%zu] Failed to demangle '%s'\n", i,
+ tc->mangled);
+ return (B_FALSE);
+ }
+
+ (void) printf(" [%zu] Demangled results do not match.\n", i);
+ (void) printf(" Mangled: %s\n", tc->mangled);
+ (void) printf(" Expected: %s\n", tc->demangled);
+ (void) printf(" Actual: %s\n", dem);
+ return (B_FALSE);
+}
+
+static boolean_t
+run_test(rust_test_grp_t *test)
+{
+ boolean_t res = B_TRUE;
+
+ (void) printf("Test %s: ", test->name);
+
+ for (size_t i = 0; test->tests[i].mangled != NULL; i++) {
+ char *dem;
+
+ dem = sysdemangle(test->tests[i].mangled, SYSDEM_LANG_RUST,
+ NULL);
+ if (test->tests[i].demangled == NULL)
+ res &= check_failure(i, &test->tests[i], dem, res);
+ else
+ res &= check_success(i, &test->tests[i], dem, res);
+
+ free(dem);
+ }
+
+ if (res)
+ (void) printf("SUCCESS\n");
+
+ return (res);
+}
+
+int
+main(int argc, char **argv)
+{
+ boolean_t ok = B_TRUE;
+
+ for (size_t i = 0; i < n_rust_tests; i++)
+ ok &= run_test(rust_tests[i]);
+
+ return (ok ? 0 : 1);
+}
+
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose");
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents");
+}
diff --git a/usr/src/test/zfs-tests/include/libtest.shlib b/usr/src/test/zfs-tests/include/libtest.shlib
index 66db2c9501..ed87c46317 100644
--- a/usr/src/test/zfs-tests/include/libtest.shlib
+++ b/usr/src/test/zfs-tests/include/libtest.shlib
@@ -2625,6 +2625,26 @@ function get_objnum
}
#
+# Sync data to the pool
+#
+# $1 pool name
+# $2 boolean to force uberblock (and config including zpool cache file) update
+#
+function sync_pool #pool <force>
+{
+ typeset pool=${1:-$TESTPOOL}
+ typeset force=${2:-false}
+
+ if [[ $force == true ]]; then
+ log_must zpool sync -f $pool
+ else
+ log_must zpool sync $pool
+ fi
+
+ return 0
+}
+
+#
# Prints the current time in seconds since UNIX Epoch.
#
function current_epoch
diff --git a/usr/src/test/zfs-tests/runfiles/delphix.run b/usr/src/test/zfs-tests/runfiles/delphix.run
index 1f7ce39c8c..ed3961f323 100644
--- a/usr/src/test/zfs-tests/runfiles/delphix.run
+++ b/usr/src/test/zfs-tests/runfiles/delphix.run
@@ -349,6 +349,9 @@ tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_002_pos',
'zpool_upgrade_006_neg', 'zpool_upgrade_007_pos', 'zpool_upgrade_008_pos',
'zpool_upgrade_009_neg']
+[/opt/zfs-tests/tests/functional/cli_root/zpool_sync]
+tests = ['zpool_sync_001_pos', 'zpool_sync_002_neg']
+
[/opt/zfs-tests/tests/functional/cli_user/misc]
tests = ['zdb_001_neg', 'zfs_001_neg', 'zfs_allow_001_neg',
'zfs_clone_001_neg', 'zfs_create_001_neg', 'zfs_destroy_001_neg',
diff --git a/usr/src/test/zfs-tests/runfiles/omnios.run b/usr/src/test/zfs-tests/runfiles/omnios.run
index a8bad95433..5847e0e980 100644
--- a/usr/src/test/zfs-tests/runfiles/omnios.run
+++ b/usr/src/test/zfs-tests/runfiles/omnios.run
@@ -13,6 +13,7 @@
# Copyright (c) 2013, 2017 by Delphix. All rights reserved.
# Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
+# Copyright 2019 RackTop Systems.
#
[DEFAULT]
@@ -318,6 +319,9 @@ tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_002_pos',
'zpool_upgrade_006_neg', 'zpool_upgrade_007_pos', 'zpool_upgrade_008_pos',
'zpool_upgrade_009_neg']
+[/opt/zfs-tests/tests/functional/cli_root/zpool_sync]
+tests = ['zpool_sync_001_pos', 'zpool_sync_002_neg']
+
[/opt/zfs-tests/tests/functional/cli_user/misc]
tests = ['zdb_001_neg', 'zfs_001_neg', 'zfs_allow_001_neg',
'zfs_clone_001_neg', 'zfs_create_001_neg', 'zfs_destroy_001_neg',
@@ -456,8 +460,6 @@ tests = ['checkpoint_after_rewind', 'checkpoint_big_rewind',
'checkpoint_open', 'checkpoint_removal', 'checkpoint_rewind',
'checkpoint_ro_rewind', 'checkpoint_sm_scale', 'checkpoint_twice',
'checkpoint_vdev_add', 'checkpoint_zdb', 'checkpoint_zhack_feat']
-pre =
-post =
[/opt/zfs-tests/tests/functional/pool_names]
tests = ['pool_names_001_pos', 'pool_names_002_neg']
diff --git a/usr/src/test/zfs-tests/runfiles/openindiana.run b/usr/src/test/zfs-tests/runfiles/openindiana.run
index fc3131dc76..3c1202f751 100644
--- a/usr/src/test/zfs-tests/runfiles/openindiana.run
+++ b/usr/src/test/zfs-tests/runfiles/openindiana.run
@@ -13,6 +13,7 @@
# Copyright (c) 2012, 2017 by Delphix. All rights reserved.
# Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
+# Copyright 2019 RackTop Systems.
#
[DEFAULT]
@@ -318,6 +319,9 @@ tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_002_pos',
'zpool_upgrade_006_neg', 'zpool_upgrade_007_pos', 'zpool_upgrade_008_pos',
'zpool_upgrade_009_neg']
+[/opt/zfs-tests/tests/functional/cli_root/zpool_sync]
+tests = ['zpool_sync_001_pos', 'zpool_sync_002_neg']
+
[/opt/zfs-tests/tests/functional/cli_user/misc]
tests = ['zdb_001_neg', 'zfs_001_neg', 'zfs_allow_001_neg',
'zfs_clone_001_neg', 'zfs_create_001_neg', 'zfs_destroy_001_neg',
@@ -456,8 +460,6 @@ tests = ['checkpoint_after_rewind', 'checkpoint_big_rewind',
'checkpoint_open', 'checkpoint_removal', 'checkpoint_rewind',
'checkpoint_ro_rewind', 'checkpoint_sm_scale', 'checkpoint_twice',
'checkpoint_vdev_add', 'checkpoint_zdb', 'checkpoint_zhack_feat']
-pre =
-post =
[/opt/zfs-tests/tests/functional/pool_names]
tests = ['pool_names_001_pos', 'pool_names_002_neg']
diff --git a/usr/src/test/zfs-tests/runfiles/smartos.run b/usr/src/test/zfs-tests/runfiles/smartos.run
index 952be3652f..1155c29025 100644
--- a/usr/src/test/zfs-tests/runfiles/smartos.run
+++ b/usr/src/test/zfs-tests/runfiles/smartos.run
@@ -23,6 +23,10 @@ post_user = root
post = cleanup
outputdir = /var/tmp/test_results
+[/opt/zfs-tests/tests/functional/cli_root/zpool_get]
+tests = ['zpool_get_001_pos', 'zpool_get_002_pos', 'zpool_get_003_pos',
+ 'zpool_get_004_neg']
+
[/opt/zfs-tests/tests/functional/cli_root/zpool_import]
tests = ['zpool_import_001_pos', 'zpool_import_002_pos',
'zpool_import_003_pos', 'zpool_import_004_pos', 'zpool_import_005_pos',
@@ -67,6 +71,9 @@ tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_002_pos',
'zpool_upgrade_006_neg', 'zpool_upgrade_008_pos',
'zpool_upgrade_009_neg']
+[/opt/zfs-tests/tests/functional/cli_root/zpool_sync]
+tests = ['zpool_sync_001_pos', 'zpool_sync_002_neg']
+
[/opt/zfs-tests/tests/functional/cli_user/misc]
tests = ['zdb_001_neg', 'zfs_001_neg', 'zfs_allow_001_neg',
'zfs_clone_001_neg', 'zfs_create_001_neg', 'zfs_destroy_001_neg',
@@ -132,6 +139,10 @@ tests = ['inuse_001_pos', 'inuse_003_pos', 'inuse_004_pos',
'inuse_009_pos']
post =
+[/opt/zfs-tests/tests/functional/large_dnode]
+tests = ['large_dnode_001_pos', 'large_dnode_003_pos',
+ 'large_dnode_004_neg', 'large_dnode_005_pos', 'large_dnode_007_neg']
+
[/opt/zfs-tests/tests/functional/large_files]
tests = ['large_files_001_pos']
@@ -214,12 +225,14 @@ tests = ['reservation_001_pos', 'reservation_002_pos', 'reservation_003_pos',
tests = ['rootpool_003_neg']
[/opt/zfs-tests/tests/functional/rsend]
-tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_006_pos',
- 'rsend_007_pos', 'rsend_013_pos', 'rsend_014_pos',
+tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos',
+ 'rsend_005_pos', 'rsend_006_pos', 'rsend_007_pos',
+ 'rsend_013_pos', 'rsend_014_pos',
'rsend_019_pos', 'rsend_020_pos',
'rsend_021_pos', 'rsend_022_pos', 'rsend_024_pos',
'send-c_verify_ratio', 'send-c_verify_contents',
'send-c_incremental',
+ 'send-c_resume',
'send-c_recv_dedup']
[/opt/zfs-tests/tests/functional/slog]
diff --git a/usr/src/test/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib b/usr/src/test/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib
index e88f6c4431..efe706fbb0 100644
--- a/usr/src/test/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib
+++ b/usr/src/test/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib
@@ -26,8 +26,10 @@
#
# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+# Copyright (c) 2017 Datto Inc.
#
+. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/clean_mirror/default.cfg
# Most of the code related to the clearing of mirrors is duplicated in all
@@ -36,32 +38,6 @@
# the contents of the mirror.
# This code is sourced into each of these test cases.
-#
-# Synchronize all the data in pool
-#
-# $1 pool name
-#
-function sync_pool #pool
-{
- typeset pool=$1
-
- log_must sync
- log_must sleep 2
- # Flush all the pool data.
- typeset -i ret
- zpool scrub $pool >/dev/null 2>&1
- ret=$?
- (( $ret != 0 )) && \
- log_fail "zpool scrub $pool failed."
-
- while ! is_pool_scrubbed $pool; do
- if is_pool_resilvered $pool ; then
- log_fail "$pool should not be resilver completed."
- fi
- log_must sleep 2
- done
-}
-
function overwrite_verify_mirror
{
typeset AFFECTED_DEVICE=$1
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
index 76b7a1582b..ebf4e77ba8 100644
--- a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
@@ -54,6 +54,8 @@ typeset -a properties=(
"freeing"
"fragmentation"
"leaked"
+ "bootsize"
+ "checkpoint"
"feature@async_destroy"
"feature@empty_bpobj"
"feature@lz4_compress"
@@ -66,9 +68,12 @@ typeset -a properties=(
"feature@bookmarks"
"feature@filesystem_limits"
"feature@large_blocks"
+ "feature@large_dnode"
"feature@sha512"
"feature@skein"
"feature@edonr"
"feature@device_removal"
- "feature@large_dnode"
+ "feature@obsolete_counts"
+ "feature@zpool_checkpoint"
+ "feature@spacemap_v2"
)
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/Makefile b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/Makefile
new file mode 100644
index 0000000000..4208e553b0
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/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 2019 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/zfs-tests
+TARGETDIR = $(ROOTOPTPKG)/tests/functional/cli_root/zpool_sync
+
+include $(SRC)/test/zfs-tests/Makefile.com
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh
new file mode 100755
index 0000000000..89c146249e
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh
@@ -0,0 +1,32 @@
+#!/bin/ksh -p
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh
new file mode 100755
index 0000000000..181e62b113
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh
@@ -0,0 +1,34 @@
+#!/bin/ksh -p
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh
new file mode 100755
index 0000000000..e72ca2157f
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh
@@ -0,0 +1,88 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2017 Datto Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify 'zpool sync' can sync txgs to the pool(s) main vdevs.
+#
+# STRATEGY:
+# 1. Create a pool
+# 2. Use zdb to obtain current txg
+# 3. Create a file in the pool if we're not using force sync
+# 4. Use zpool sync to sync pool
+# 5. Verify the new txg is now bigger than the saved one
+#
+
+verify_runnable "global"
+
+function get_txg {
+ typeset -i txg=$(zdb -u $1 | sed -n 's/^[ ][ ]*txg = \(.*\)$/\1/p')
+ echo $txg
+}
+
+set -A args "sync $TESTPOOL" "sync -f $TESTPOOL" "sync" "sync -f"
+
+log_assert "Verify 'zpool sync' can sync a pool"
+
+typeset -i i=0
+typeset -i orig_txg=0
+typeset -i new_txg=0
+while [[ $i -lt ${#args[*]} ]]; do
+ orig_txg=$(get_txg $TESTPOOL)
+ if ! [[ "${args[i]}" =~ "-f" ]]; then
+ log_must touch /$TESTPOOL/$i
+ fi
+ log_must zpool ${args[i]}
+ new_txg=$(get_txg $TESTPOOL)
+ if [[ $orig_txg -ge $new_txg ]]; then
+ log_fail "'zpool ${args[i]}' failed: txg $orig_txg >= $new_txg"
+ fi
+ ((i = i + 1))
+done
+
+# sync_pool is implemented using 'zpool sync' so let's test it as well
+
+# make sure we can use sync_pool with force sync explicitly not used
+orig_txg=$(get_txg $TESTPOOL)
+log_must touch /$TESTPOOL/$i
+log_must sync_pool $TESTPOOL false
+new_txg=$(get_txg $TESTPOOL)
+if [[ $orig_txg -ge $new_txg ]]; then
+ log_fail "'sync_pool $TESTPOOL false' failed: txg $orig_txg >= $new_txg"
+fi
+
+# make sure we can use sync_pool with force sync explicitly enabled
+orig_txg=$(get_txg $TESTPOOL)
+log_must sync_pool $TESTPOOL true
+new_txg=$(get_txg $TESTPOOL)
+if [[ $orig_txg -ge $new_txg ]]; then
+ log_fail "'sync_pool $TESTPOOL true' failed: txg $orig_txg >= $new_txg"
+fi
+
+# make sure we can use sync_pool with force sync implicitly not used
+orig_txg=$(get_txg $TESTPOOL)
+log_must touch /$TESTPOOL/$i
+log_must sync_pool $TESTPOOL
+new_txg=$(get_txg $TESTPOOL)
+if [[ $orig_txg -ge $new_txg ]]; then
+ log_fail "'sync_pool $TESTPOOL' failed: txg $orig_txg >= $new_txg"
+fi
+
+log_pass "'zpool sync' syncs pool as expected."
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh
new file mode 100755
index 0000000000..e35a29130c
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh
@@ -0,0 +1,44 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2017 Datto Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# A badly formed parameter passed to 'zpool sync' should
+# return an error.
+#
+# STRATEGY:
+# 1. Create an array containing bad 'zpool sync' parameters.
+# 2. For each element, execute the sub-command.
+# 3. Verify it returns an error.
+#
+
+verify_runnable "global"
+
+set -A args "1" "-a" "-?" "--%" "-123456" "0.5" "-o" "-b" "-b no" "-z 2"
+
+log_assert "Execute 'zpool sync' using invalid parameters."
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+ log_mustnot zpool sync ${args[i]}
+ ((i = i + 1))
+done
+
+log_pass "Invalid parameters to 'zpool sync' fail as expected."
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/cleanup.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/cleanup.ksh
index 61caf39100..60e481d998 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/cleanup.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/cleanup.ksh
@@ -20,6 +20,11 @@
# CDDL HEADER END
#
+#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
. $STF_SUITE/include/libtest.shlib
default_cleanup
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_001_pos.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_001_pos.ksh
index c07f4e8d74..d3530292e8 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_001_pos.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_001_pos.ksh
@@ -20,6 +20,11 @@
# CDDL HEADER END
#
+#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
. $STF_SUITE/include/libtest.shlib
#
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_002_pos.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_002_pos.ksh
index 1dd8d888c3..c2b32ad662 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_002_pos.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_002_pos.ksh
@@ -20,6 +20,11 @@
# CDDL HEADER END
#
+#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
. $STF_SUITE/include/libtest.shlib
#
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_003_pos.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_003_pos.ksh
index a938c7de7c..20989e1d77 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_003_pos.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_003_pos.ksh
@@ -20,6 +20,11 @@
# CDDL HEADER END
#
+#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
. $STF_SUITE/include/libtest.shlib
verify_runnable "both"
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_004_neg.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_004_neg.ksh
index 1006ae6af5..3fa1cabe06 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_004_neg.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_004_neg.ksh
@@ -21,6 +21,11 @@
#
#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
+#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_005_pos.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_005_pos.ksh
index 13f1288e4e..a2d92673b1 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_005_pos.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_005_pos.ksh
@@ -20,6 +20,11 @@
# CDDL HEADER END
#
+#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
. $STF_SUITE/include/libtest.shlib
verify_runnable "both"
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_006_pos.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_006_pos.ksh
index 68fc5e3040..38b4ac52e5 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_006_pos.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_006_pos.ksh
@@ -21,6 +21,11 @@
#
#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
+#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_007_neg.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_007_neg.ksh
index fb4747839f..59364574b1 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_007_neg.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/large_dnode_007_neg.ksh
@@ -21,6 +21,11 @@
#
#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
+#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
diff --git a/usr/src/test/zfs-tests/tests/functional/large_dnode/setup.ksh b/usr/src/test/zfs-tests/tests/functional/large_dnode/setup.ksh
index d9b1a6ee85..a9425cca98 100755
--- a/usr/src/test/zfs-tests/tests/functional/large_dnode/setup.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/large_dnode/setup.ksh
@@ -20,6 +20,11 @@
# CDDL HEADER END
#
+#
+# Copyright (c) 2016 by Lawrence Livermore National Security, LLC.
+# Use is subject to license terms.
+#
+
. $STF_SUITE/include/libtest.shlib
DISK=${DISKS%% *}
diff --git a/usr/src/test/zfs-tests/tests/functional/rsend/send_freeobjects.ksh b/usr/src/test/zfs-tests/tests/functional/rsend/send_freeobjects.ksh
new file mode 100755
index 0000000000..6533352a9a
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/rsend/send_freeobjects.ksh
@@ -0,0 +1,81 @@
+#!/bin/ksh
+
+#
+# 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 (c) 2017 by Lawrence Livermore National Security, LLC.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify FREEOBJECTS record frees sequential objects (See
+# https://github.com/zfsonlinux/zfs/issues/6694)
+#
+# Strategy:
+# 1. Create three files with sequential object numbers, f1 f2 and f3
+# 2. Delete f2
+# 3. Take snapshot A
+# 4. Delete f3
+# 5. Take snapshot B
+# 6. Receive a full send of A
+# 7. Receive an incremental send of B
+# 8. Fail test if f3 exists on received snapshot B
+#
+
+verify_runnable "both"
+
+log_assert "Verify FREEOBJECTS record frees sequential objects"
+
+sendds=sendfo
+recvds=recvfo
+f1=/$POOL/$sendds/f1
+f2=/$POOL/$sendds/f2
+f3=/$POOL/$sendds/f3
+
+#
+# We need to set xattr=sa and dnodesize=legacy to guarantee sequential
+# object numbers for this test. Otherwise, if we used directory-based
+# xattrs, SELinux extended attributes might consume intervening object
+# numbers.
+#
+log_must zfs create -o xattr=sa -o dnodesize=legacy $POOL/$sendds
+
+tries=100
+for ((i=0; i<$tries; i++)); do
+ touch $f1 $f2 $f3
+ o1=$(ls -li $f1 | awk '{print $1}')
+ o2=$(ls -li $f2 | awk '{print $1}')
+ o3=$(ls -li $f3 | awk '{print $1}')
+
+ if [[ $o2 -ne $(( $o1 + 1 )) ]] || [[ $o3 -ne $(( $o2 + 1 )) ]]; then
+ rm -f $f1 $f2 $f3
+ else
+ break
+ fi
+done
+
+if [[ $i -eq $tries ]]; then
+ log_fail "Failed to create three sequential objects"
+fi
+
+log_must rm $f2
+log_must zfs snap $POOL/$sendds@A
+log_must rm $f3
+log_must zfs snap $POOL/$sendds@B
+log_must eval "zfs send $POOL/$sendds@A | zfs recv $POOL/$recvds"
+log_must eval "zfs send -i $POOL/$sendds@A $POOL/$sendds@B |" \
+ "zfs recv $POOL/$recvds"
+log_mustnot zdb $POOL/$recvds@B $o3
+log_pass "Verify FREEOBJECTS record frees sequential objects"
diff --git a/usr/src/test/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh b/usr/src/test/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh
new file mode 100755
index 0000000000..12a72fa092
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh
@@ -0,0 +1,111 @@
+#!/bin/ksh
+
+#
+# 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 (c) 2017 by Lawrence Livermore National Security, LLC.
+# Copyright (c) 2018 Datto Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify incremental receive properly handles objects with changed
+# dnode slot count.
+#
+# Strategy:
+# 1. Populate a dataset with 1k byte dnodes and snapshot
+# 2. Remove objects, set dnodesize=legacy, and remount dataset so new objects
+# get recycled numbers and formerly "interior" dnode slots get assigned
+# to new objects
+# 3. Remove objects, set dnodesize=2k, and remount dataset so new objects
+# overlap with recently recycled and formerly "normal" dnode slots get
+# assigned to new objects
+# 4. Create an empty file and add xattrs to it to exercise reclaiming a
+# dnode that requires more than 1 slot for its bonus buffer (Zol #7433)
+# 5. Generate initial and incremental streams
+# 6. Verify initial and incremental streams can be received
+#
+
+verify_runnable "both"
+
+log_assert "Verify incremental receive handles objects with changed dnode size"
+
+function cleanup
+{
+ rm -f $BACKDIR/fs-dn-legacy
+ rm -f $BACKDIR/fs-dn-1k
+ rm -f $BACKDIR/fs-dn-2k
+ rm -f $BACKDIR/fs-attr
+
+ if datasetexists $POOL/fs ; then
+ log_must zfs destroy -rR $POOL/fs
+ fi
+
+ if datasetexists $POOL/newfs ; then
+ log_must zfs destroy -rR $POOL/newfs
+ fi
+}
+
+log_onexit cleanup
+
+# 1. Populate a dataset with 1k byte dnodes and snapshot
+log_must zfs create -o dnodesize=1k $POOL/fs
+log_must mk_files 200 262144 0 $POOL/fs
+log_must zfs snapshot $POOL/fs@a
+
+# 2. Remove objects, set dnodesize=legacy, and remount dataset so new objects
+# get recycled numbers and formerly "interior" dnode slots get assigned
+# to new objects
+rm /$POOL/fs/*
+
+log_must zfs unmount $POOL/fs
+log_must zfs set dnodesize=legacy $POOL/fs
+log_must zfs mount $POOL/fs
+
+log_must mk_files 200 262144 0 $POOL/fs
+log_must zfs snapshot $POOL/fs@b
+
+# 3. Remove objects, set dnodesize=2k, and remount dataset so new objects
+# overlap with recently recycled and formerly "normal" dnode slots get
+# assigned to new objects
+rm /$POOL/fs/*
+
+log_must zfs unmount $POOL/fs
+log_must zfs set dnodesize=2k $POOL/fs
+log_must zfs mount $POOL/fs
+
+log_must touch /$POOL/fs/attrs
+mk_files 200 262144 0 $POOL/fs
+log_must zfs snapshot $POOL/fs@c
+
+# 4. Create an empty file and add xattrs to it to exercise reclaiming a
+# dnode that requires more than 1 slot for its bonus buffer (Zol #7433)
+log_must zfs set compression=on xattr=sa $POOL/fs
+log_must eval "python -c 'print \"a\" * 512' | attr -s bigval /$POOL/fs/attrs"
+log_must zfs snapshot $POOL/fs@d
+
+# 5. Generate initial and incremental streams
+log_must eval "zfs send $POOL/fs@a > $BACKDIR/fs-dn-1k"
+log_must eval "zfs send -i $POOL/fs@a $POOL/fs@b > $BACKDIR/fs-dn-legacy"
+log_must eval "zfs send -i $POOL/fs@b $POOL/fs@c > $BACKDIR/fs-dn-2k"
+log_must eval "zfs send -i $POOL/fs@c $POOL/fs@d > $BACKDIR/fs-attr"
+
+# 6. Verify initial and incremental streams can be received
+log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-1k"
+log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-legacy"
+log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-2k"
+log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-attr"
+
+log_pass "Verify incremental receive handles objects with changed dnode size"
diff --git a/usr/src/test/zfs-tests/tests/functional/slog/slog_014_pos.ksh b/usr/src/test/zfs-tests/tests/functional/slog/slog_014_pos.ksh
index 02e99fac45..9a2580d554 100644
--- a/usr/src/test/zfs-tests/tests/functional/slog/slog_014_pos.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/slog/slog_014_pos.ksh
@@ -28,6 +28,7 @@
#
# Copyright (c) 2013, 2018 by Delphix. All rights reserved.
# Copyright 2019 Joyent, Inc.
+# Copyright 2019 RackTop Systems.
#
. $STF_SUITE/tests/functional/slog/slog.kshlib
diff --git a/usr/src/test/zfs-tests/tests/functional/snapshot/deadlist_lock.ksh b/usr/src/test/zfs-tests/tests/functional/snapshot/deadlist_lock.ksh
index 47f912dc9c..a592916a61 100644
--- a/usr/src/test/zfs-tests/tests/functional/snapshot/deadlist_lock.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/snapshot/deadlist_lock.ksh
@@ -13,6 +13,7 @@
#
# Copyright (c) 2016 by Delphix. All rights reserved.
+# Copyright 2019 Joyent, Inc.
#
. $STF_SUITE/include/libtest.shlib
@@ -43,15 +44,15 @@
# snapshot right after you create a new test file.
# 2. Start DTrace in the background to put a delay in the
# sync thread after it closes the empty bpobj and before
-# it reopens it.
+# it reopens it. The dtrace process is set to exit when this
+# script exits.
# 3. Start a process in the backgroud that runs zfs-destroy
# dry-runs in an infinite loop. The idea is to keep calling
# dsl_deadlist_space_range().
# 4. Go ahead and start removing the test files. This should
# start populating the deadlist of each snapshot with
# entries and go through the dle_enqueue() target code.
-# 5. If the test passes, kill the process running on a loop
-# and dtrace, and cleanup the dataset.
+# 5. Kill the 'zfs destroy' loop and clean up the dataset.
#
verify_runnable "both"
@@ -61,7 +62,7 @@ DLDS="dl_race"
function cleanup
{
- log_must kill -9 $DLOOP_PID $DTRACE_PID
+ log_must kill -9 $DLOOP_PID
log_must zfs destroy -fR $TESTPOOL/$TESTFS/$DLDS
}
@@ -86,8 +87,7 @@ log_onexit cleanup
setup
log_must sync
-log_must dtrace -qwn "fbt::bpobj_decr_empty:entry { chill(500000000); }" &
-DTRACE_PID="$!"
+log_must dtrace -p "$PPID" -qwn "fbt::bpobj_decr_empty:entry { chill(500000000); }" &
sleep 1
destroy_nv_loop &
@@ -100,5 +100,5 @@ done
log_must sync
log_pass "There should be no race condition when an administrative command" \
- " attempts to read a deadlist's entries at the same time a that a sync" \
+ " attempts to read a deadlist's entries while a sync" \
" thread is manipulating it."
diff --git a/usr/src/tools/cpcgen/cpcgen.c b/usr/src/tools/cpcgen/cpcgen.c
index ef5b74b164..a7b0d2ca57 100644
--- a/usr/src/tools/cpcgen/cpcgen.c
+++ b/usr/src/tools/cpcgen/cpcgen.c
@@ -329,13 +329,13 @@ cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model, uint_t *nstepp,
errno = 0;
l = strtol(fam, &last, 16);
- if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
+ if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
}
*family = (uint_t)l;
l = strtol(mod, &last, 16);
- if (errno != 0 || l < 0 || l > UINT_MAX || *last != '\0') {
+ if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
}
*model = (uint_t)l;
diff --git a/usr/src/tools/onbld/Checks/Comments.py b/usr/src/tools/onbld/Checks/Comments.py
index 14e1f4a9da..0715bb1b40 100644
--- a/usr/src/tools/onbld/Checks/Comments.py
+++ b/usr/src/tools/onbld/Checks/Comments.py
@@ -26,17 +26,19 @@
#
# Copyright 2007, 2010 Richard Lowe
-# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
# Check delta comments:
# - Have the correct form.
# - Have a synopsis matching that of the bug
# - Appear only once.
+# - Do not contain common spelling errors.
#
import re, sys
from onbld.Checks.DbLookups import BugDB
+from onbld.Checks.SpellCheck import spellcheck_line
bugre = re.compile(r'^(\d{2,7}|[A-Z]{1,7}-\d{1,7}) (.*)$')
@@ -71,12 +73,16 @@ def comchk(comments, check_db=True, output=sys.stderr):
'mutant': [],
'dup': [],
'nomatch': [],
- 'nonexistent': [] }
+ 'nonexistent': [],
+ 'spelling': [] }
bugs = {}
ret = 0
blanks = False
+ lineno = 0
for com in comments:
+ lineno += 1
+
# Our input must be newline-free, comments are line-wise.
if com.find('\n') != -1:
raise ValueError("newline in comment '%s'" % com)
@@ -89,6 +95,10 @@ def comchk(comments, check_db=True, output=sys.stderr):
blanks = True
continue
+ for err in spellcheck_line(com):
+ errors['spelling'].append(
+ 'comment line {} - {}'.format(lineno, err))
+
match = bugre.search(com)
if match:
if match.group(1) not in bugs:
@@ -179,4 +189,10 @@ def comchk(comments, check_db=True, output=sys.stderr):
output.write(" should be: '%s'\n" % err[1])
output.write(" is: '%s'\n" % err[2])
+ if errors['spelling']:
+ ret = 1
+ output.write("Spellcheck:\n")
+ for err in errors['spelling']:
+ output.write('{}\n'.format(err))
+
return ret
diff --git a/usr/src/tools/onbld/Checks/SpellCheck.py b/usr/src/tools/onbld/Checks/SpellCheck.py
index 0d07017846..c858947fe6 100644
--- a/usr/src/tools/onbld/Checks/SpellCheck.py
+++ b/usr/src/tools/onbld/Checks/SpellCheck.py
@@ -26,8 +26,9 @@
import re, sys
-spellMsg = '%s: Line %d contains "%s", a common misspelling of "%s"\n'
-altMsg = '%s: Line %d contains "%s"; please use "%s" instead for consistency with other documentation\n'
+spellMsg = 'contains "{}", a common misspelling of "{}"'
+altMsg = 'contains "{}"; please use "{}" instead for consistency with other documentation'
+caseMsg = 'contains "{}"; please use "{}" instead'
misspellings = {
'absense': 'absence',
@@ -253,8 +254,13 @@ alternates = {
'writeable': 'writable'
}
+case = {
+ 'Illumos': 'illumos'
+}
+
misspellingREs = []
alternateREs = []
+caseREs = []
for misspelling, correct in misspellings.items():
regex = re.compile(r'\b%s\b' % (misspelling), re.IGNORECASE)
@@ -266,12 +272,23 @@ for alternate, correct in alternates.items():
entry = (regex, alternate, correct)
alternateREs.append(entry)
-def check(errmsg, output, filename, line, lineno, entry):
- if entry[0].search(line):
- output.write(errmsg % (filename, lineno, entry[1], entry[2]))
- return 1
- else:
- return 0
+for alternate, correct in case.items():
+ regex = re.compile(r'\b%s\b' % (alternate))
+ entry = (regex, alternate, correct)
+ caseREs.append(entry)
+
+def spellcheck_line(line):
+ errs = []
+ for entry in misspellingREs:
+ if entry[0].search(line):
+ errs.append(spellMsg.format(entry[1], entry[2]))
+ for entry in alternateREs:
+ if entry[0].search(line):
+ errs.append(altMsg.format(entry[1], entry[2]))
+ for entry in caseREs:
+ if entry[0].search(line):
+ errs.append(caseMsg.format(entry[1], entry[2]))
+ return errs
def spellcheck(fh, filename=None, output=sys.stderr, **opts):
lineno = 1
@@ -283,12 +300,10 @@ def spellcheck(fh, filename=None, output=sys.stderr, **opts):
fh.seek(0)
for line in fh:
line = line.decode(errors='replace')
- for entry in misspellingREs:
- ret |= check(spellMsg, output, filename, line,
- lineno, entry)
- for entry in alternateREs:
- ret |= check(altMsg, output, filename, line,
- lineno, entry)
+ for err in spellcheck_line(line):
+ output.write('{}: Line {} {}\n'.format(
+ filename, lineno, err))
+ ret = 1
lineno += 1
return ret
diff --git a/usr/src/tools/quick/make-smbclnt b/usr/src/tools/quick/make-smbclnt
index 1b65f50a71..e8c6bfeabc 100755
--- a/usr/src/tools/quick/make-smbclnt
+++ b/usr/src/tools/quick/make-smbclnt
@@ -11,14 +11,11 @@
#
#
-# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
#
-# Use distributed make (dmake) by default.
-make=${MAKE:-dmake}
-
-CLOSED_IS_PRESENT=no
-export CLOSED_IS_PRESENT
+# Use ordinary make (not dmake) by default.
+make=${MAKE:-make}
# Do this if you want to use dbx or gdb
# export SOURCEDEBUG=yes
@@ -97,7 +94,9 @@ fi
# Need some library headers too...
for lib in \
+ libcmdutils \
libcryptoutil \
+ libfakekernel \
libmlrpc \
libpam \
libsec \
@@ -128,7 +127,13 @@ do_kern() {
# skip these on clean (but still nuke them for clobber)
do_lib1() {
- :
+
+for lib in \
+ libavl \
+ libcmdutils
+do
+ (cd $SRC/lib/$lib && $make $1)
+done
}
# lib2 builds stuff we include in the tar file,
@@ -139,7 +144,16 @@ do_lib2() {
(cd $SRC/lib/libsmbfs && $make $1)
[ "$1" = install ] &&
(cd $SRC/lib/libsmbfs && $make _msg)
-(cd $SRC/lib/libmlrpc && $make $1)
+
+for lib in \
+ libfakekernel \
+ libsmbfs \
+ libmlrpc \
+ smbclnt
+do
+ (cd $SRC/lib/$lib && $make $1)
+done
+
(cd $SRC/lib/libshare && $make $1 PLUGINS=smbfs)
(cd $SRC/lib/passwdutil && $make $1)
(cd $SRC/lib/pam_modules/smbfs && $make $1)
@@ -184,6 +198,15 @@ do
(cd $SRC/cmd/mdb/$x/$a/smbfs &&
$make $1 KMDB_LINKTEST_ENABLE= )
done
+
+# mdb_arch is both 32-bit & 64-bit
+for a in $mdb_arch
+do
+ (cd $SRC/cmd/mdb/$x/$a/libfknsmb &&
+ $make $1 )
+ (cd $SRC/cmd/mdb/$x/$a/libfksmbfs &&
+ $make $1 )
+done
}
@@ -199,6 +222,7 @@ do_tags() {
find uts/common/netsmb -name '*.[ch]' -print |sort
find uts/common/fs/smbclnt -name '*.[ch]' -print |sort
find head -name '*.h' -print |sort
+ find lib/smbclnt -name '*.[ch]' -print |sort
find lib/libsmbfs -name '*.[ch]' -print |sort
find cmd/fs.d/smbclnt -name '*.[ch]' -print |sort
find common/smbclnt -name '*.[ch]' -print |sort
@@ -217,9 +241,6 @@ do_tar() {
files="
lib/svc/manifest/network/smb/client.xml
lib/svc/method/smb-client
-opt/smbcl-tests/tests/srvenum
-opt/smbcl-tests/tests/srvinfo
-opt/smbcl-tests/tests/tconn
usr/bin/smbutil
usr/kernel/drv/$arch64/nsmb
usr/kernel/fs/$arch64/smbfs
@@ -239,8 +260,6 @@ usr/lib/libmlrpc.so.2
usr/lib/libsmbfs.so.1
usr/lib/mdb/kvm/$arch64/nsmb.so
usr/lib/mdb/kvm/$arch64/smbfs.so
-usr/lib/mdb/kvm/nsmb.so
-usr/lib/mdb/kvm/smbfs.so
usr/lib/security/$arch64/pam_smbfs_login.so.1
usr/lib/security/pam_smbfs_login.so.1
usr/lib/smbfs/smbiod
diff --git a/usr/src/tools/quick/make-zfs b/usr/src/tools/quick/make-zfs
index f88deeff35..987b5627d2 100755
--- a/usr/src/tools/quick/make-zfs
+++ b/usr/src/tools/quick/make-zfs
@@ -266,13 +266,14 @@ do_mans() {
$ROOT/usr/share/man/man1m/zdb.1m \
$ROOT/usr/share/man/man1m/zfs.1m \
$ROOT/usr/share/man/man1m/zfs-program.1m \
- $ROOT/usr/share/man/man1m/zpool.1m )
+ $ROOT/usr/share/man/man1m/zpool.1m \
+ $ROOT/usr/share/man/man1m/ztest.1m )
(cd $SRC/man/man5 && make \
$ROOT/usr/share/man/man5/zpool-features.5 )
;;
lint)
(cd $SRC/man/man1m && make zdb.1m.check zfs.1m.check zfs-program.1m.check \
- zpool.1m.check)
+ zpool.1m.check ztest.1m.check)
(cd $SRC/man/man5 && make zpool-features.5.check)
;;
*)
@@ -348,6 +349,7 @@ usr/share/man/man1m/zdb.1m
usr/share/man/man1m/zfs.1m
usr/share/man/man1m/zfs-program.1m
usr/share/man/man1m/zpool.1m
+usr/share/man/man1m/ztest.1m
usr/share/man/man5/zpool-features.5
"
(cd $ROOT && tar cfj ../../zfs-${git_rev}.tar.bz2 $files)
diff --git a/usr/src/tools/scripts/cstyle.pl b/usr/src/tools/scripts/cstyle.pl
index c515dce980..5c474cfe28 100644
--- a/usr/src/tools/scripts/cstyle.pl
+++ b/usr/src/tools/scripts/cstyle.pl
@@ -135,6 +135,11 @@ my %old2posix = (
'u_short' => 'ushort_t',
'u_long' => 'ulong_t',
'u_char' => 'uchar_t',
+ 'u_int8_t' => 'uint8_t',
+ 'u_int16_t' => 'uint16_t',
+ 'u_int32_t' => 'uint32_t',
+ 'u_int64_t' => 'uint64_t',
+ 'u_quad_t' => 'uint64_t',
'quad' => 'quad_t'
);
@@ -712,7 +717,8 @@ line: while (<$filehandle>) {
# try to detect old non-POSIX types.
# POSIX requires all non-standard typedefs to end in _t,
# but historically these have been used.
- if (/\b(unchar|ushort|uint|ulong|u_int|u_short|u_long|u_char|quad)\b/) {
+ my $types = join '|', keys %old2posix;
+ if (/\b($types)\b/) {
err("non-POSIX typedef $1 used: use $old2posix{$1} instead");
}
}
diff --git a/usr/src/tools/scripts/wsdiff.py b/usr/src/tools/scripts/wsdiff.py
index 78347ea3b5..aaab371708 100644
--- a/usr/src/tools/scripts/wsdiff.py
+++ b/usr/src/tools/scripts/wsdiff.py
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
#
@@ -46,8 +46,8 @@
# and details about why wsdiff(1) thinks they are different will be logged to
# the results file.
#
-# By invoking nightly(1) with the -w option to NIGHTLY_FLAGS, nightly(1) will use
-# wsdiff(1) to report on what objects changed since the last build.
+# By invoking nightly(1) with the -w option to NIGHTLY_FLAGS, nightly(1) will
+# use wsdiff(1) to report on what objects changed since the last build.
#
# For patch deliverable purposes, it's advised to have nightly do a clobber,
# non-debug build.
@@ -55,8 +55,8 @@
# Think about the results. Was something flagged that you don't expect? Go look
# at the results file to see details about the differences.
#
-# Use the -i option in conjunction with -v and -V to dive deeper and have wsdiff(1)
-# report with more verbosity.
+# Use the -i option in conjunction with -v and -V to dive deeper and have
+# wsdiff(1) report with more verbosity.
#
# Usage: wsdiff [-vVt] [-r results ] [-i filelist ] old new
#
@@ -75,7 +75,11 @@ import datetime, fnmatch, getopt, os, profile, io, subprocess
import re, resource, select, shutil, signal, string, struct, sys, tempfile
import time, threading
from stat import *
-from subprocess import Popen, PIPE
+
+PY3 = sys.version_info[0] == 3
+
+if not PY3:
+ import commands
# Human readable diffs truncated by default if longer than this
# Specifying -v on the command line will override
@@ -116,9 +120,10 @@ wsdiff_exceptions = [
]
def getoutput(cmd):
- p = Popen(cmd, shell=True, stdout=PIPE)
- output, x = p.communicate()
- return (p.returncode, output.decode(errors='replace'))
+ if PY3:
+ return subprocess.getstatusoutput(cmd)
+ else:
+ return commands.getstatusoutput(cmd)
#####
# Logging routines
@@ -224,7 +229,7 @@ def log_difference(f, dtype, diffs) :
#
#
-# Return human readable diffs from two temporary files
+# Return human readable diffs from two files
#
def diffFileData(tmpf1, tmpf2) :
@@ -267,34 +272,6 @@ def diffFileData(tmpf1, tmpf2) :
return data
-#
-# Return human readable diffs betweeen two datasets
-#
-def diffData(base, ptch, d1, d2) :
-
- t = threading.currentThread()
- tmpFile1 = tmpDir1 + os.path.basename(base) + t.getName()
- tmpFile2 = tmpDir2 + os.path.basename(ptch) + t.getName()
-
- try:
- fd1 = io.open(tmpFile1, mode='w', errors='ignore')
- except:
- error("failed to open: " + tmpFile1)
- cleanup(1)
-
- try:
- fd2 = io.open(tmpFile2, mode='w', errors='ignore')
- except:
- error("failed to open: " + tmpFile2)
- cleanup(1)
-
- fd1.write(d1)
- fd2.write(d2)
- fd1.close()
- fd2.close()
-
- return diffFileData(tmpFile1, tmpFile2)
-
#####
# Misc utility functions
#
@@ -456,7 +433,7 @@ def getTheFileType(f) :
elfmagic = b'\177ELF'
def isELF(f) :
try:
- with io.open(f, mode='rb') as fd:
+ with open(f, mode='rb') as fd:
magic = fd.read(len(elfmagic))
if magic == elfmagic :
@@ -471,7 +448,7 @@ def isELF(f) :
#
def isBinary(f) :
try:
- with io.open(f, mode='rb') as fd:
+ with open(f, mode='rb') as fd:
s = fd.read()
if s.find(b'\0') == -1 :
@@ -1056,8 +1033,6 @@ def compareArchives(base, ptch, fileType) :
#####
# (Basic) file comparison
#
-# There's some special case code here for Javadoc HTML files
-#
# Returns 1 if difference detected
# 0 if no difference detected
# -1 on error
@@ -1070,44 +1045,25 @@ def compareBasic(base, ptch, quiet, fileType) :
return 1
try:
- baseFile = io.open(base, errors='replace')
+ with open(base, 'rb') as fh:
+ baseData = fh.read()
except:
error("could not open " + base)
return -1
+
try:
- ptchFile = io.open(ptch, errors='replace')
+ with open(ptch, 'rb') as fh:
+ ptchData = fh.read()
except:
error("could not open " + ptch)
return -1
- baseData = baseFile.read()
- ptchData = ptchFile.read()
-
- baseFile.close()
- ptchFile.close()
-
- needToSnip = False
- if fileType == "HTML" :
- needToSnip = True
- toSnipBeginStr = "<!-- Generated by javadoc"
- toSnipEndStr = "-->\n"
-
- if needToSnip :
- toSnipBegin = baseData.find(toSnipBeginStr)
- if toSnipBegin != -1 :
- toSnipEnd = (baseData[toSnipBegin:].find(toSnipEndStr) +
- len(toSnipEndStr))
- baseData = (baseData[:toSnipBegin] +
- baseData[toSnipBegin + toSnipEnd:])
- ptchData = (ptchData[:toSnipBegin] +
- ptchData[toSnipBegin + toSnipEnd:])
-
if quiet :
if baseData != ptchData :
return 1
else :
if len(baseData) != len(ptchData) or baseData != ptchData :
- diffs = diffData(base, ptch, baseData, ptchData)
+ diffs = diffFileData(base, ptch)
difference(fileName, fileType, diffs)
return 1
return 0
@@ -1147,35 +1103,25 @@ def compareByDumping(base, ptch, quiet, fileType) :
os.system(ptchCmd)
try:
- baseFile = open(tmpFile1)
+ with open(tmpFile1, 'rb') as fh:
+ baseData = fh.read()
except:
error("could not open: " + tmpFile1)
return
+
try:
- ptchFile = open(tmpFile2)
+ with open(tmpFile2, 'rb') as fh:
+ ptchData = fh.read()
except:
error("could not open: " + tmpFile2)
return
- baseData = baseFile.read()
- ptchData = ptchFile.read()
-
- baseFile.close()
- ptchFile.close()
+ ret = 0
if len(baseData) != len(ptchData) or baseData != ptchData :
if not quiet :
data = diffFileData(tmpFile1, tmpFile2);
- try:
- os.unlink(tmpFile1)
- except OSError as e:
- error("compareByDumping: unlink failed %s" % e)
- try:
- os.unlink(tmpFile2)
- except OSError as e:
- error("compareByDumping: unlink failed %s" % e)
- difference(fileName, fileType, data)
- return 1
+ ret = 1
# Remove the temporary files now.
try:
@@ -1187,7 +1133,7 @@ def compareByDumping(base, ptch, quiet, fileType) :
except OSError as e:
error("compareByDumping: unlink failed %s" % e)
- return 0
+ return ret
#####
#
@@ -1487,7 +1433,7 @@ def main() :
if max_threads == -1 :
max_threads = 1
else :
- max_threads += max_threads/5
+ max_threads += int(max_threads/5)
# Set signal handler to attempt graceful exit
debug("Setting signal handler")
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 0c734ff062..1ddfacb0cd 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -25,7 +25,7 @@
# Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
# Copyright 2018 Nexenta Systems, Inc.
# Copyright 2016 Garrett D'Amore <garrett@damore.org>
-# Copyright 2017 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
# Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
#
@@ -1301,11 +1301,13 @@ VSCAN_OBJS += vscan_drv.o vscan_svc.o vscan_door.o
NSMB_OBJS += smb_conn.o smb_dev.o smb_iod.o smb_pass.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
+ smb2_rq.o smb2_sign.o smb2_smb.o subr_mchain.o \
+ nsmb_sign_kcf.o
SMBFS_COMMON_OBJS += smbfs_ntacl.o
SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node.o \
smbfs_acl.o smbfs_client.o smbfs_smb.o \
+ smbfs_smb1.o smbfs_smb2.o \
smbfs_subr.o smbfs_subr2.o \
smbfs_rwlock.o smbfs_xattr.o \
$(SMBFS_COMMON_OBJS)
@@ -1356,6 +1358,7 @@ ZFS_COMMON_OBJS += \
ddt_zap.o \
dmu.o \
dmu_diff.o \
+ dmu_recv.o \
dmu_send.o \
dmu_object.o \
dmu_objset.o \
diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c
index d388b14c70..0f78bca605 100644
--- a/usr/src/uts/common/brand/lx/os/lx_brand.c
+++ b/usr/src/uts/common/brand/lx/os/lx_brand.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright 2018, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -235,7 +235,7 @@ void (*lx_cgrp_freelwp)(vfs_t *, uint_t, id_t, pid_t);
uint64_t lx_maxstack64 = LX_MAXSTACK64;
static int lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
- struct intpdata *idata, int level, long *execsz, int setid,
+ struct intpdata *idata, int level, size_t *execsz, int setid,
caddr_t exec_file, struct cred *cred, int *brand_action);
static boolean_t lx_native_exec(uint8_t, const char **);
@@ -2043,12 +2043,6 @@ restoreexecenv(struct execenv *ep, stack_t *sp)
lwp->lwp_sigaltstack.ss_flags = sp->ss_flags;
}
-extern int elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
-
-extern int elf32exec(struct vnode *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
-
static uintptr_t
lx_map_vdso(struct uarg *args, struct cred *cred)
{
@@ -2113,10 +2107,10 @@ lx_map_vdso(struct uarg *args, struct cred *cred)
/* ARGSUSED4 */
static int
lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
- struct intpdata *idata, int level, long *execsz, int setid,
+ struct intpdata *idata, int level, size_t *execsz, int setid,
caddr_t exec_file, struct cred *cred, int *brand_action)
{
- int error, i;
+ int error;
vnode_t *nvp;
Ehdr ehdr;
Addr uphdr_vaddr;
@@ -2183,8 +2177,8 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
Ehdr ehdr;
Phdr *phdrp;
caddr_t phdrbase = NULL;
- ssize_t phdrsize = 0;
- int nphdrs, hsize;
+ size_t phdrsize = 0;
+ uint_t nphdrs, hsize;
if ((error = elfreadhdr(vp, cred, &ehdr, &nphdrs, &phdrbase,
&phdrsize)) != 0) {
@@ -2194,7 +2188,7 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
hsize = ehdr.e_phentsize;
/* LINTED: alignment */
phdrp = (Phdr *)phdrbase;
- for (i = nphdrs; i > 0; i--) {
+ for (uint_t i = nphdrs; i > 0; i--) {
switch (phdrp->p_type) {
case PT_GNU_STACK:
if ((phdrp->p_flags & PF_X) == 0) {
@@ -2212,8 +2206,8 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
Elf32_Ehdr ehdr;
Elf32_Phdr *phdrp;
caddr_t phdrbase = NULL;
- ssize_t phdrsize = 0;
- int nphdrs, hsize;
+ size_t phdrsize = 0;
+ uint_t nphdrs, hsize;
if ((error = elf32readhdr(vp, cred, &ehdr, &nphdrs, &phdrbase,
&phdrsize)) != 0) {
@@ -2223,7 +2217,7 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
hsize = ehdr.e_phentsize;
/* LINTED: alignment */
phdrp = (Elf32_Phdr *)phdrbase;
- for (i = nphdrs; i > 0; i--) {
+ for (uint_t i = nphdrs; i > 0; i--) {
switch (phdrp->p_type) {
case PT_GNU_STACK:
if ((phdrp->p_flags & PF_X) == 0) {
@@ -2538,7 +2532,7 @@ lx_elfexec(struct vnode *vp, struct execa *uap, struct uarg *args,
* So we set AT_ENTRY to be the entry point of the linux executable,
* but leave AT_BASE to be the address of the Solaris linker.
*/
- for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
+ for (uint_t i = 0; i < __KERN_NAUXV_IMPL; i++) {
switch (up->u_auxv[i].a_type) {
case AT_ENTRY:
up->u_auxv[i].a_un.a_val = edp.ed_entry;
diff --git a/usr/src/uts/common/brand/lx/syscall/lx_open.c b/usr/src/uts/common/brand/lx/syscall/lx_open.c
index f26f2d1fa6..4ee355eb70 100644
--- a/usr/src/uts/common/brand/lx/syscall/lx_open.c
+++ b/usr/src/uts/common/brand/lx/syscall/lx_open.c
@@ -147,7 +147,7 @@ lx_open_postprocess(int fd, int fmode)
* While the O_PATH flag has no direct analog in SunOS, it is
* emulated by removing both FREAD and FWRITE from f_flag.
* This causes read(2) and write(2) result in EBADF and can be
- * checked for in other syscalls to tigger the correct behavior
+ * checked for in other syscalls to trigger the correct behavior
* there.
*/
mutex_enter(&fp->f_tlock);
@@ -244,6 +244,29 @@ lx_openat(int atfd, char *path, int fmode, int cmode)
return (set_errno(ENOTDIR));
(void) set_errno(oerror);
+ } else if ((fmode & LX_O_NOFOLLOW) && (fmode & LX_O_PATH) &&
+ ttolwp(curthread)->lwp_errno == ELOOP) {
+ /*
+ * On Linux, if O_NOFOLLOW and O_PATH are set together
+ * and the target is a symbolic link, then openat
+ * should return a file descriptor referring to the
+ * symbolic link.
+ *
+ * This file descriptor can be used with fchownat(2),
+ * fstatat(2), linkat(2), and readlinkat(2) alongside
+ * an empty pathname.
+ *
+ * We do not have a way to return such a file
+ * descriptor in illumos so open it without NO_FOLLOW
+ * and allow the postprocess to emulate O_PATH by
+ * removing the read and write flags.
+ * This is enough to keep recent systemd happy
+ * although any attempt to use the fd for the above
+ * listed calls without a pathname will fail or modify
+ * the symlink target.
+ */
+ return (lx_openat(atfd, path, fmode & ~LX_O_NOFOLLOW,
+ cmode));
}
if (ttolwp(curthread)->lwp_errno == EINTR)
diff --git a/usr/src/uts/common/brand/sn1/sn1_brand.c b/usr/src/uts/common/brand/sn1/sn1_brand.c
index a2383ca076..ebdabce2b5 100644
--- a/usr/src/uts/common/brand/sn1/sn1_brand.c
+++ b/usr/src/uts/common/brand/sn1/sn1_brand.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/errno.h>
@@ -58,7 +58,7 @@ void sn1_forklwp(klwp_t *, klwp_t *);
void sn1_freelwp(klwp_t *);
void sn1_lwpexit(klwp_t *);
int sn1_elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
/* sn1 brand */
struct brand_ops sn1_brops = {
@@ -254,7 +254,7 @@ sn1_init_brand_data(zone_t *zone, kmutex_t *zsl)
int
sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
- int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
+ int level, size_t *execsz, int setid, caddr_t exec_file, cred_t *cred,
int *brand_action)
{
return (brand_solaris_elfexec(vp, uap, args, idatap, level, execsz,
diff --git a/usr/src/uts/common/brand/solaris10/s10_brand.c b/usr/src/uts/common/brand/solaris10/s10_brand.c
index c5a9d10f58..4de7cbcc05 100644
--- a/usr/src/uts/common/brand/solaris10/s10_brand.c
+++ b/usr/src/uts/common/brand/solaris10/s10_brand.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/errno.h>
@@ -61,7 +61,7 @@ void s10_forklwp(klwp_t *, klwp_t *);
void s10_freelwp(klwp_t *);
void s10_lwpexit(klwp_t *);
int s10_elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
void s10_sigset_native_to_s10(sigset_t *);
void s10_sigset_s10_to_native(sigset_t *);
@@ -423,7 +423,7 @@ s10_init_brand_data(zone_t *zone, kmutex_t *zsl)
int
s10_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
- int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
+ int level, size_t *execsz, int setid, caddr_t exec_file, cred_t *cred,
int *brand_action)
{
return (brand_solaris_elfexec(vp, uap, args, idatap, level, execsz,
diff --git a/usr/src/uts/common/crypto/io/dca.c b/usr/src/uts/common/crypto/io/dca.c
index b76cbaeb55..015112ade4 100644
--- a/usr/src/uts/common/crypto/io/dca.c
+++ b/usr/src/uts/common/crypto/io/dca.c
@@ -664,8 +664,8 @@ dca_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
dca = ddi_get_soft_state(dca_state, instance);
ASSERT(dca != NULL);
dca->dca_dip = dip;
- WORKLIST(dca, MCR1)->dwl_prov = NULL;
- WORKLIST(dca, MCR2)->dwl_prov = NULL;
+ WORKLIST(dca, MCR1)->dwl_prov = 0;
+ WORKLIST(dca, MCR2)->dwl_prov = 0;
/* figure pagesize */
dca->dca_pagesize = ddi_ptob(dip, 1);
@@ -856,11 +856,11 @@ dca_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
failed:
/* unregister from the crypto framework */
- if (WORKLIST(dca, MCR1)->dwl_prov != NULL) {
+ if (WORKLIST(dca, MCR1)->dwl_prov != 0) {
(void) crypto_unregister_provider(
WORKLIST(dca, MCR1)->dwl_prov);
}
- if (WORKLIST(dca, MCR2)->dwl_prov != NULL) {
+ if (WORKLIST(dca, MCR2)->dwl_prov != 0) {
(void) crypto_unregister_provider(
WORKLIST(dca, MCR2)->dwl_prov);
}
@@ -925,7 +925,7 @@ dca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
* Unregister from kCF.
* This needs to be done at the beginning of detach.
*/
- if (WORKLIST(dca, MCR1)->dwl_prov != NULL) {
+ if (WORKLIST(dca, MCR1)->dwl_prov != 0) {
if (crypto_unregister_provider(
WORKLIST(dca, MCR1)->dwl_prov) != CRYPTO_SUCCESS) {
dca_error(dca, "unable to unregister MCR1 from kcf");
@@ -933,7 +933,7 @@ dca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
}
}
- if (WORKLIST(dca, MCR2)->dwl_prov != NULL) {
+ if (WORKLIST(dca, MCR2)->dwl_prov != 0) {
if (crypto_unregister_provider(
WORKLIST(dca, MCR2)->dwl_prov) != CRYPTO_SUCCESS) {
dca_error(dca, "unable to unregister MCR2 from kcf");
@@ -1243,7 +1243,7 @@ dca_uninit(dca_t *dca)
mutex_destroy(&wlp->dwl_freereqslock);
mutex_destroy(&wlp->dwl_freelock);
cv_destroy(&wlp->dwl_cv);
- wlp->dwl_prov = NULL;
+ wlp->dwl_prov = 0;
}
}
@@ -1927,7 +1927,7 @@ dca_bindchains(dca_request_t *reqp, size_t incnt, size_t outcnt)
reqp->dr_in_next = reqp->dr_chain_in_head.dc_next_paddr;
reqp->dr_in_len = reqp->dr_chain_in_head.dc_buffer_length;
} else {
- reqp->dr_in_paddr = NULL;
+ reqp->dr_in_paddr = 0;
reqp->dr_in_next = 0;
reqp->dr_in_len = 0;
}
@@ -1960,7 +1960,7 @@ dca_bindchains(dca_request_t *reqp, size_t incnt, size_t outcnt)
reqp->dr_out_next = reqp->dr_chain_out_head.dc_next_paddr;
reqp->dr_out_len = reqp->dr_chain_out_head.dc_buffer_length;
} else {
- reqp->dr_out_paddr = NULL;
+ reqp->dr_out_paddr = 0;
reqp->dr_out_next = 0;
reqp->dr_out_len = 0;
}
@@ -1978,7 +1978,7 @@ dca_unbindchains(dca_request_t *reqp)
int rv1 = DDI_SUCCESS;
/* Clear the input chain */
- if (reqp->dr_chain_in_head.dc_buffer_paddr != NULL) {
+ if (reqp->dr_chain_in_head.dc_buffer_paddr != 0) {
(void) ddi_dma_unbind_handle(reqp->dr_chain_in_dmah);
reqp->dr_chain_in_head.dc_buffer_paddr = 0;
}
@@ -1988,7 +1988,7 @@ dca_unbindchains(dca_request_t *reqp)
}
/* Clear the output chain */
- if (reqp->dr_chain_out_head.dc_buffer_paddr != NULL) {
+ if (reqp->dr_chain_out_head.dc_buffer_paddr != 0) {
(void) ddi_dma_unbind_handle(reqp->dr_chain_out_dmah);
reqp->dr_chain_out_head.dc_buffer_paddr = 0;
}
@@ -2011,7 +2011,7 @@ dca_bindchains_one(dca_request_t *reqp, size_t cnt, int dr_offset,
caddr_t chain_kaddr_pre;
caddr_t chain_kaddr;
uint32_t chain_paddr;
- int i;
+ int i;
/* Advance past the context structure to the starting address */
chain_paddr = reqp->dr_ctx_paddr + dr_offset;
diff --git a/usr/src/uts/common/exec/elf/elf.c b/usr/src/uts/common/exec/elf/elf.c
index 87bf950a30..cf5e0bdfd9 100644
--- a/usr/src/uts/common/exec/elf/elf.c
+++ b/usr/src/uts/common/exec/elf/elf.c
@@ -26,7 +26,7 @@
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <sys/types.h>
@@ -80,15 +80,32 @@ extern volatile size_t aslr_max_brk_skew;
#define ORIGIN_STR "ORIGIN"
#define ORIGIN_STR_SIZE 6
-static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *);
-static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *,
- ssize_t *);
-static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *,
- ssize_t *, caddr_t *, ssize_t *);
-static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *);
-static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t,
- Phdr **, Phdr **, Phdr **, Phdr **, Phdr *,
- caddr_t *, caddr_t *, intptr_t *, intptr_t *, size_t, long *, size_t *);
+static int getelfhead(vnode_t *, cred_t *, Ehdr *, uint_t *, uint_t *,
+ uint_t *);
+static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, uint_t, caddr_t *,
+ size_t *);
+static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, uint_t, uint_t,
+ caddr_t *, size_t *, caddr_t *, size_t *);
+static size_t elfsize(const Ehdr *, uint_t, const caddr_t, uintptr_t *);
+static int mapelfexec(vnode_t *, Ehdr *, uint_t, caddr_t, Phdr **, Phdr **,
+ Phdr **, Phdr **, Phdr *, caddr_t *, caddr_t *, intptr_t *, uintptr_t *,
+ size_t, size_t *, size_t *);
+
+#ifdef _ELF32_COMPAT
+/* Link against the non-compat instances when compiling the 32-bit version. */
+extern size_t elf_datasz_max;
+extern void elf_ctx_resize_scratch(elf_core_ctx_t *, size_t);
+extern uint_t elf_nphdr_max;
+extern uint_t elf_nshdr_max;
+extern size_t elf_shstrtab_max;
+#else
+size_t elf_datasz_max = 1 * 1024 * 1024;
+uint_t elf_nphdr_max = 1000;
+uint_t elf_nshdr_max = 10000;
+size_t elf_shstrtab_max = 100 * 1024;
+#endif
+
+
typedef enum {
STR_CTF,
@@ -110,8 +127,8 @@ static const char *shstrtab_data[] = {
};
typedef struct shstrtab {
- int sst_ndx[STR_NUM];
- int sst_cur;
+ uint_t sst_ndx[STR_NUM];
+ uint_t sst_cur;
} shstrtab_t;
static void
@@ -121,10 +138,10 @@ shstrtab_init(shstrtab_t *s)
s->sst_cur = 1;
}
-static int
+static uint_t
shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
{
- int ret;
+ uint_t ret;
if ((ret = s->sst_ndx[type]) != 0)
return (ret);
@@ -144,7 +161,7 @@ shstrtab_size(const shstrtab_t *s)
static void
shstrtab_dump(const shstrtab_t *s, char *buf)
{
- int i, ndx;
+ uint_t i, ndx;
*buf = '\0';
for (i = 0; i < STR_NUM; i++) {
@@ -206,6 +223,23 @@ handle_secflag_dt(proc_t *p, uint_t dt, uint_t val)
return (0);
}
+
+#ifndef _ELF32_COMPAT
+void
+elf_ctx_resize_scratch(elf_core_ctx_t *ctx, size_t sz)
+{
+ size_t target = MIN(sz, elf_datasz_max);
+
+ if (target > ctx->ecc_bufsz) {
+ if (ctx->ecc_buf != NULL) {
+ kmem_free(ctx->ecc_buf, ctx->ecc_bufsz);
+ }
+ ctx->ecc_buf = kmem_alloc(target, KM_SLEEP);
+ ctx->ecc_bufsz = target;
+ }
+}
+#endif /* _ELF32_COMPAT */
+
/*
* Map in the executable pointed to by vp. Returns 0 on success. Note that
* this function currently has the maximum number of arguments allowed by
@@ -218,20 +252,18 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
intptr_t *voffset, caddr_t exec_file, char **interpp, caddr_t *bssbase,
caddr_t *brkbase, size_t *brksize, uintptr_t *lddatap, uintptr_t *minaddrp)
{
- size_t len;
+ size_t len, phdrsize;
struct vattr vat;
caddr_t phdrbase = NULL;
- ssize_t phdrsize;
- int nshdrs, shstrndx, nphdrs;
+ uint_t nshdrs, shstrndx, nphdrs;
int error = 0;
Phdr *uphdr = NULL;
Phdr *junk = NULL;
Phdr *dynphdr = NULL;
Phdr *dtrphdr = NULL;
char *interp = NULL;
- uintptr_t lddata;
- long execsz;
- intptr_t minaddr;
+ uintptr_t lddata, minaddr;
+ size_t execsz;
if (lddatap != NULL)
*lddatap = NULL;
@@ -287,7 +319,8 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
interp = kmem_alloc(MAXPATHLEN, KM_SLEEP);
- if ((error = vn_rdwr(UIO_READ, vp, interp, dynphdr->p_filesz,
+ if ((error = vn_rdwr(UIO_READ, vp, interp,
+ (ssize_t)dynphdr->p_filesz,
(offset_t)dynphdr->p_offset, UIO_SYSSPACE, 0,
(rlim64_t)0, CRED(), &resid)) != 0 || resid != 0 ||
interp[dynphdr->p_filesz - 1] != '\0') {
@@ -329,8 +362,9 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
* in mapelfexec() and use the p_vaddr of the first PT_LOAD
* section as the base address of the object.
*/
- Phdr *phdr = (Phdr *)phdrbase;
- int i, hsize = ehdr->e_phentsize;
+ const Phdr *phdr = (Phdr *)phdrbase;
+ const uint_t hsize = ehdr->e_phentsize;
+ uint_t i;
for (i = nphdrs; i > 0; i--) {
if (phdr->p_type == PT_LOAD) {
@@ -358,14 +392,14 @@ mapexec_brand(vnode_t *vp, uarg_t *args, Ehdr *ehdr, Addr *uphdr_vaddr,
/*ARGSUSED*/
int
elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
- int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
+ int level, size_t *execsz, int setid, caddr_t exec_file, cred_t *cred,
int *brand_action)
{
caddr_t phdrbase = NULL;
caddr_t bssbase = 0;
caddr_t brkbase = 0;
size_t brksize = 0;
- ssize_t dlnsize, nsize = 0;
+ size_t dlnsize, nsize = 0;
aux_entry_t *aux;
int error;
ssize_t resid;
@@ -377,16 +411,14 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
Phdr *uphdr = NULL;
Phdr *junk = NULL;
size_t len;
- ssize_t phdrsize;
- int postfixsize = 0;
- int i, hsize;
+ size_t postfixsize = 0;
+ size_t i;
Phdr *phdrp;
Phdr *dataphdrp = NULL;
Phdr *dtrphdr;
Phdr *capphdr = NULL;
Cap *cap = NULL;
- ssize_t capsize;
- Dyn *dyn = NULL;
+ size_t capsize;
int hasu = 0;
int hasauxv = 0;
int hasintp = 0;
@@ -404,7 +436,8 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
struct execenv exenv;
} *bigwad; /* kmem_alloc this behemoth so we don't blow stack */
Ehdr *ehdrp;
- int nshdrs, shstrndx, nphdrs;
+ uint_t nshdrs, shstrndx, nphdrs;
+ size_t phdrsize;
char *dlnp;
char *pathbufp;
rlim64_t limit;
@@ -512,7 +545,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* determine any non-default stack protections,
* and still have this code be machine independent.
*/
- hsize = ehdrp->e_phentsize;
+ const uint_t hsize = ehdrp->e_phentsize;
phdrp = (Phdr *)phdrbase;
for (i = nphdrs; i > 0; i--) {
switch (phdrp->p_type) {
@@ -663,26 +696,32 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
}
/* If the binary has an explicit ASLR flag, it must be honoured */
- if ((dynamicphdr != NULL) &&
- (dynamicphdr->p_filesz > 0)) {
- Dyn *dp;
- off_t i = 0;
+ if ((dynamicphdr != NULL) && (dynamicphdr->p_filesz > 0)) {
+ const size_t dynfilesz = dynamicphdr->p_filesz;
+ const size_t dynoffset = dynamicphdr->p_offset;
+ Dyn *dyn, *dp;
+
+ if (dynoffset > MAXOFFSET_T ||
+ dynfilesz > MAXOFFSET_T ||
+ dynoffset + dynfilesz > MAXOFFSET_T) {
+ uprintf("%s: cannot read full .dynamic section\n",
+ exec_file);
+ error = EINVAL;
+ goto out;
+ }
#define DYN_STRIDE 100
- for (i = 0; i < dynamicphdr->p_filesz;
- i += sizeof (*dyn) * DYN_STRIDE) {
- int ndyns = (dynamicphdr->p_filesz - i) / sizeof (*dyn);
- size_t dynsize;
-
- ndyns = MIN(DYN_STRIDE, ndyns);
- dynsize = ndyns * sizeof (*dyn);
+ for (i = 0; i < dynfilesz; i += sizeof (*dyn) * DYN_STRIDE) {
+ const size_t remdyns = (dynfilesz - i) / sizeof (*dyn);
+ const size_t ndyns = MIN(DYN_STRIDE, remdyns);
+ const size_t dynsize = ndyns * sizeof (*dyn);
dyn = kmem_alloc(dynsize, KM_SLEEP);
if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)dyn,
- dynsize, (offset_t)(dynamicphdr->p_offset + i),
+ (ssize_t)dynsize, (offset_t)(dynoffset + i),
UIO_SYSSPACE, 0, (rlim64_t)0,
- CRED(), &resid)) != 0) {
+ CRED(), NULL)) != 0) {
uprintf("%s: cannot read .dynamic section\n",
exec_file);
goto out;
@@ -710,13 +749,13 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
if (capphdr != NULL &&
(capsize = capphdr->p_filesz) > 0 &&
capsize <= 16 * sizeof (*cap)) {
- int ncaps = capsize / sizeof (*cap);
+ const uint_t ncaps = capsize / sizeof (*cap);
Cap *cp;
cap = kmem_alloc(capsize, KM_SLEEP);
if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)cap,
- capsize, (offset_t)capphdr->p_offset,
- UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
+ (ssize_t)capsize, (offset_t)capphdr->p_offset,
+ UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), NULL)) != 0) {
uprintf("%s: Cannot read capabilities section\n",
exec_file);
goto out;
@@ -757,17 +796,18 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
dtrphdr = NULL;
- if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
+ error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &intphdr,
&stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, NULL,
- len, execsz, &brksize)) != 0)
- goto bad;
+ len, execsz, &brksize);
+ /*
+ * Our uphdr has been dynamically allocated if (and only if) its
+ * program header flags are clear. To avoid leaks, this must be
+ * checked regardless of whether mapelfexec() emitted an error.
+ */
+ dynuphdr = (uphdr != NULL && uphdr->p_flags == 0);
- if (uphdr != NULL) {
- /*
- * Our uphdr has been dynamically allocated if (and only if)
- * its program header flags are clear.
- */
- dynuphdr = (uphdr->p_flags == 0);
+ if (error != 0) {
+ goto bad;
}
if (uphdr != NULL && intphdr == NULL)
@@ -786,8 +826,14 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
dlnsize = intphdr->p_filesz + nsize;
- if (dlnsize > MAXPATHLEN || dlnsize <= 0)
+ /*
+ * Make sure none of the component pieces of dlnsize result in
+ * an oversized or zeroed result.
+ */
+ if (intphdr->p_filesz > MAXPATHLEN || dlnsize > MAXPATHLEN ||
+ dlnsize == 0 || dlnsize < intphdr->p_filesz) {
goto bad;
+ }
if (nsize != 0) {
bcopy(args->brand_nroot, dlnp, nsize - 1);
@@ -798,7 +844,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* Read in "interpreter" pathname.
*/
if ((error = vn_rdwr(UIO_READ, vp, dlnp + nsize,
- intphdr->p_filesz, (offset_t)intphdr->p_offset,
+ (ssize_t)intphdr->p_filesz, (offset_t)intphdr->p_offset,
UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) != 0) {
uprintf("%s: Cannot obtain interpreter pathname\n",
exec_file);
@@ -1094,7 +1140,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
#endif /* defined(__amd64) */
ADDAUX(aux, AT_NULL, 0)
- postfixsize = (char *)aux - (char *)bigwad->elfargs;
+ postfixsize = (uintptr_t)aux - (uintptr_t)bigwad->elfargs;
/*
* We make assumptions above when we determine how many aux
@@ -1105,8 +1151,8 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
* We detect that now and error out.
*/
if (postfixsize != args->auxsize) {
- DTRACE_PROBE2(elfexec_badaux, int, postfixsize,
- int, args->auxsize);
+ DTRACE_PROBE2(elfexec_badaux, size_t, postfixsize,
+ size_t, args->auxsize);
goto bad;
}
ASSERT(postfixsize <= __KERN_NAUXV_IMPL * sizeof (aux_entry_t));
@@ -1134,7 +1180,7 @@ elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
bzero(up->u_auxv, sizeof (up->u_auxv));
up->u_commpagep = args->commpage;
if (postfixsize) {
- int num_auxv;
+ size_t num_auxv;
/*
* Copy the aux vector to the user stack.
@@ -1213,32 +1259,23 @@ out:
* Compute the memory size requirement for the ELF file.
*/
static size_t
-elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
+elfsize(const Ehdr *ehdrp, uint_t nphdrs, const caddr_t phdrbase,
+ uintptr_t *lddata)
{
- size_t len;
- Phdr *phdrp = (Phdr *)phdrbase;
- int hsize = ehdrp->e_phentsize;
- int first = 1;
- int dfirst = 1; /* first data segment */
- uintptr_t loaddr = 0;
+ const Phdr *phdrp = (Phdr *)phdrbase;
+ const uint_t hsize = ehdrp->e_phentsize;
+ boolean_t dfirst = B_TRUE;
+ uintptr_t loaddr = UINTPTR_MAX;
uintptr_t hiaddr = 0;
- uintptr_t lo, hi;
- int i;
+ uint_t i;
for (i = nphdrs; i > 0; i--) {
if (phdrp->p_type == PT_LOAD) {
- lo = phdrp->p_vaddr;
- hi = lo + phdrp->p_memsz;
- if (first) {
- loaddr = lo;
- hiaddr = hi;
- first = 0;
- } else {
- if (loaddr > lo)
- loaddr = lo;
- if (hiaddr < hi)
- hiaddr = hi;
- }
+ const uintptr_t lo = phdrp->p_vaddr;
+ const uintptr_t hi = lo + phdrp->p_memsz;
+
+ loaddr = MIN(lo, loaddr);
+ hiaddr = MAX(hi, hiaddr);
/*
* save the address of the first data segment
@@ -1248,16 +1285,18 @@ elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
if ((lddata != NULL) && dfirst &&
(phdrp->p_flags & PF_W)) {
*lddata = lo;
- dfirst = 0;
+ dfirst = B_FALSE;
}
}
phdrp = (Phdr *)((caddr_t)phdrp + hsize);
}
- len = hiaddr - (loaddr & PAGEMASK);
- len = roundup(len, PAGESIZE);
+ if (hiaddr <= loaddr) {
+ /* No non-zero PT_LOAD segment found */
+ return (0);
+ }
- return (len);
+ return (roundup(hiaddr - (loaddr & PAGEMASK), PAGESIZE));
}
/*
@@ -1267,8 +1306,8 @@ elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata)
* EINVAL Format recognized but execution not supported
*/
static int
-getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
- int *nphdrs)
+getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, uint_t *nshdrs,
+ uint_t *shstrndx, uint_t *nphdrs)
{
int error;
ssize_t resid;
@@ -1277,10 +1316,10 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
* We got here by the first two bytes in ident,
* now read the entire ELF header.
*/
- if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)ehdr,
- sizeof (Ehdr), (offset_t)0, UIO_SYSSPACE, 0,
- (rlim64_t)0, credp, &resid)) != 0)
+ if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)ehdr, sizeof (Ehdr),
+ (offset_t)0, UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid)) != 0) {
return (error);
+ }
/*
* Since a separate version is compiled for handling 32-bit and
@@ -1289,8 +1328,9 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
*/
if (resid != 0 ||
ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
- ehdr->e_ident[EI_MAG3] != ELFMAG3)
+ ehdr->e_ident[EI_MAG3] != ELFMAG3) {
return (ENOEXEC);
+ }
if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) ||
#if defined(_ILP32) || defined(_ELF32_COMPAT)
@@ -1299,8 +1339,9 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
#endif
!elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine,
- ehdr->e_flags))
+ ehdr->e_flags)) {
return (EINVAL);
+ }
*nshdrs = ehdr->e_shnum;
*shstrndx = ehdr->e_shstrndx;
@@ -1308,7 +1349,7 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
/*
* If e_shnum, e_shstrndx, or e_phnum is its sentinel value, we need
- * to read in the section header at index zero to acces the true
+ * to read in the section header at index zero to access the true
* values for those fields.
*/
if ((*nshdrs == 0 && ehdr->e_shoff != 0) ||
@@ -1320,7 +1361,7 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&shdr,
sizeof (shdr), (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0,
- (rlim64_t)0, credp, &resid)) != 0)
+ (rlim64_t)0, credp, NULL)) != 0)
return (error);
if (*nshdrs == 0)
@@ -1334,33 +1375,29 @@ getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx,
return (0);
}
-#ifdef _ELF32_COMPAT
-extern size_t elf_nphdr_max;
+/*
+ * We use members through p_flags on 32-bit files and p_memsz on 64-bit files,
+ * so e_phentsize must be at least large enough to include those members.
+ */
+#if !defined(_LP64) || defined(_ELF32_COMPAT)
+#define MINPHENTSZ (offsetof(Phdr, p_flags) + \
+ sizeof (((Phdr *)NULL)->p_flags))
#else
-size_t elf_nphdr_max = 1000;
+#define MINPHENTSZ (offsetof(Phdr, p_memsz) + \
+ sizeof (((Phdr *)NULL)->p_memsz))
#endif
static int
-getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
- caddr_t *phbasep, ssize_t *phsizep)
+getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, uint_t nphdrs,
+ caddr_t *phbasep, size_t *phsizep)
{
- ssize_t resid, minsize;
int err;
/*
- * Since we're going to be using e_phentsize to iterate down the
- * array of program headers, it must be 8-byte aligned or else
- * a we might cause a misaligned access. We use all members through
- * p_flags on 32-bit ELF files and p_memsz on 64-bit ELF files so
- * e_phentsize must be at least large enough to include those
- * members.
+ * Ensure that e_phentsize is large enough for required fields to be
+ * accessible and will maintain 8-byte alignment.
*/
-#if !defined(_LP64) || defined(_ELF32_COMPAT)
- minsize = offsetof(Phdr, p_flags) + sizeof (((Phdr *)NULL)->p_flags);
-#else
- minsize = offsetof(Phdr, p_memsz) + sizeof (((Phdr *)NULL)->p_memsz);
-#endif
- if (ehdr->e_phentsize < minsize || (ehdr->e_phentsize & 3))
+ if (ehdr->e_phentsize < MINPHENTSZ || (ehdr->e_phentsize & 3))
return (EINVAL);
*phsizep = nphdrs * ehdr->e_phentsize;
@@ -1372,9 +1409,9 @@ getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
*phbasep = kmem_alloc(*phsizep, KM_SLEEP);
}
- if ((err = vn_rdwr(UIO_READ, vp, *phbasep, *phsizep,
+ if ((err = vn_rdwr(UIO_READ, vp, *phbasep, (ssize_t)*phsizep,
(offset_t)ehdr->e_phoff, UIO_SYSSPACE, 0, (rlim64_t)0,
- credp, &resid)) != 0) {
+ credp, NULL)) != 0) {
kmem_free(*phbasep, *phsizep);
*phbasep = NULL;
return (err);
@@ -1383,21 +1420,14 @@ getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs,
return (0);
}
-#ifdef _ELF32_COMPAT
-extern size_t elf_nshdr_max;
-extern size_t elf_shstrtab_max;
-#else
-size_t elf_nshdr_max = 10000;
-size_t elf_shstrtab_max = 100 * 1024;
-#endif
-
+#define MINSHDRSZ (offsetof(Shdr, sh_entsize) + \
+ sizeof (((Shdr *)NULL)->sh_entsize))
static int
-getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
- int nshdrs, int shstrndx, caddr_t *shbasep, ssize_t *shsizep,
- char **shstrbasep, ssize_t *shstrsizep)
+getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, uint_t nshdrs,
+ uint_t shstrndx, caddr_t *shbasep, size_t *shsizep, char **shstrbasep,
+ size_t *shstrsizep)
{
- ssize_t resid, minsize;
int err;
Shdr *shdr;
@@ -1409,9 +1439,8 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
* must be at least large enough to include that member. The index
* of the string table section must also be valid.
*/
- minsize = offsetof(Shdr, sh_entsize) + sizeof (shdr->sh_entsize);
- if (ehdr->e_shentsize < minsize || (ehdr->e_shentsize & 3) ||
- shstrndx >= nshdrs)
+ if (ehdr->e_shentsize < MINSHDRSZ || (ehdr->e_shentsize & 3) ||
+ nshdrs == 0 || shstrndx >= nshdrs)
return (EINVAL);
*shsizep = nshdrs * ehdr->e_shentsize;
@@ -1423,16 +1452,16 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
*shbasep = kmem_alloc(*shsizep, KM_SLEEP);
}
- if ((err = vn_rdwr(UIO_READ, vp, *shbasep, *shsizep,
+ if ((err = vn_rdwr(UIO_READ, vp, *shbasep, (ssize_t)*shsizep,
(offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, (rlim64_t)0,
- credp, &resid)) != 0) {
+ credp, NULL)) != 0) {
kmem_free(*shbasep, *shsizep);
return (err);
}
/*
- * Pull the section string table out of the vnode; fail if the size
- * is zero.
+ * Grab the section string table. Walking through the shdrs is
+ * pointless if their names cannot be interrogated.
*/
shdr = (Shdr *)(*shbasep + shstrndx * ehdr->e_shentsize);
if ((*shstrsizep = shdr->sh_size) == 0) {
@@ -1450,9 +1479,9 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
*shstrbasep = kmem_alloc(*shstrsizep, KM_SLEEP);
}
- if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, *shstrsizep,
+ if ((err = vn_rdwr(UIO_READ, vp, *shstrbasep, (ssize_t)*shstrsizep,
(offset_t)shdr->sh_offset, UIO_SYSSPACE, 0, (rlim64_t)0,
- credp, &resid)) != 0) {
+ credp, NULL)) != 0) {
kmem_free(*shbasep, *shsizep);
kmem_free(*shstrbasep, *shstrsizep);
return (err);
@@ -1468,17 +1497,12 @@ getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr,
}
-#ifdef _ELF32_COMPAT
-int
-elf32readhdr(vnode_t *vp, cred_t *credp, Ehdr *ehdrp, int *nphdrs,
- caddr_t *phbasep, ssize_t *phsizep)
-#else
int
-elfreadhdr(vnode_t *vp, cred_t *credp, Ehdr *ehdrp, int *nphdrs,
- caddr_t *phbasep, ssize_t *phsizep)
-#endif
+elfreadhdr(vnode_t *vp, cred_t *credp, Ehdr *ehdrp, uint_t *nphdrs,
+ caddr_t *phbasep, size_t *phsizep)
{
- int error, nshdrs, shstrndx;
+ int error;
+ uint_t nshdrs, shstrndx;
if ((error = getelfhead(vp, credp, ehdrp, &nshdrs, &shstrndx,
nphdrs)) != 0 ||
@@ -1494,7 +1518,7 @@ static int
mapelfexec(
vnode_t *vp,
Ehdr *ehdr,
- int nphdrs,
+ uint_t nphdrs,
caddr_t phdrbase,
Phdr **uphdr,
Phdr **intphdr,
@@ -1504,21 +1528,21 @@ mapelfexec(
caddr_t *bssbase,
caddr_t *brkbase,
intptr_t *voffset,
- intptr_t *minaddr,
+ uintptr_t *minaddrp,
size_t len,
- long *execsz,
+ size_t *execsz,
size_t *brksize)
{
Phdr *phdr;
- int i, prot, error, lastprot = 0;
+ int error, page, prot, lastprot = 0;
caddr_t addr = NULL;
- size_t zfodsz;
- int ptload = 0;
- int page;
+ caddr_t minaddr = (caddr_t)UINTPTR_MAX;
+ uint_t i;
+ size_t zfodsz, memsz;
+ boolean_t ptload = B_FALSE;
off_t offset;
- int hsize = ehdr->e_phentsize;
- caddr_t mintmp = (caddr_t)-1;
- uintptr_t lastaddr = NULL;
+ const uint_t hsize = ehdr->e_phentsize;
+ uintptr_t lastaddr = 0;
extern int use_brk_lpg;
if (ehdr->e_type == ET_DYN) {
@@ -1534,7 +1558,6 @@ mapelfexec(
map_addr(&addr, len, (offset_t)0, 1, flags);
if (addr == NULL)
return (ENOMEM);
- *voffset = (intptr_t)addr;
/*
* Despite the fact that mmapobj(2) refuses to load them, we
@@ -1569,8 +1592,8 @@ mapelfexec(
* prelink(8) contraption -- goggles on!
*/
if ((vaddr = addr) != NULL) {
- if (as_gap(curproc->p_as, len,
- &addr, &len, AH_LO, NULL) == -1 || addr != vaddr) {
+ if (as_gap(curproc->p_as, len, &addr, &len,
+ AH_LO, NULL) == -1 || addr != vaddr) {
addr = NULL;
}
}
@@ -1602,7 +1625,7 @@ mapelfexec(
for (i = nphdrs; i > 0; i--) {
switch (phdr->p_type) {
case PT_LOAD:
- ptload = 1;
+ ptload = B_TRUE;
prot = PROT_USER;
if (phdr->p_flags & PF_R)
prot |= PROT_READ;
@@ -1642,11 +1665,20 @@ mapelfexec(
}
/*
+ * The ELF spec dictates that p_filesz may not be
+ * larger than p_memsz in PT_LOAD segments.
+ */
+ if (phdr->p_filesz > phdr->p_memsz) {
+ error = EINVAL;
+ goto bad;
+ }
+
+ /*
* Keep track of the segment with the lowest starting
* address.
*/
- if (addr < mintmp)
- mintmp = addr;
+ if (addr < minaddr)
+ minaddr = addr;
/*
* Segments need not correspond to page boundaries:
@@ -1701,14 +1733,22 @@ mapelfexec(
if (brksize != NULL && use_brk_lpg &&
zfodsz != 0 && phdr == dataphdrp &&
(prot & PROT_WRITE)) {
- size_t tlen = P2NPHASE((uintptr_t)addr +
+ const size_t tlen = P2NPHASE((uintptr_t)addr +
phdr->p_filesz, PAGESIZE);
if (zfodsz > tlen) {
+ const caddr_t taddr = addr +
+ phdr->p_filesz + tlen;
+
+ /*
+ * Since a hole in the AS large enough
+ * for this object as calculated by
+ * elfsize() is available, we do not
+ * need to fear overflow for 'taddr'.
+ */
curproc->p_brkpageszc =
page_szc(map_pgsz(MAPPGSZ_HEAP,
- curproc, addr + phdr->p_filesz +
- tlen, zfodsz - tlen, 0));
+ curproc, taddr, zfodsz - tlen, 0));
}
}
@@ -1750,7 +1790,12 @@ mapelfexec(
*brkbase = addr + phdr->p_memsz;
}
- *execsz += btopr(phdr->p_memsz);
+ memsz = btopr(phdr->p_memsz);
+ if ((*execsz + memsz) < *execsz) {
+ error = ENOMEM;
+ goto bad;
+ }
+ *execsz += memsz;
break;
case PT_INTERP:
@@ -1802,9 +1847,9 @@ mapelfexec(
phdr = (Phdr *)((caddr_t)phdr + hsize);
}
- if (minaddr != NULL) {
- ASSERT(mintmp != (caddr_t)-1);
- *minaddr = (intptr_t)mintmp;
+ if (minaddrp != NULL) {
+ ASSERT(minaddr != (caddr_t)UINTPTR_MAX);
+ *minaddrp = (uintptr_t)minaddr;
}
if (brkbase != NULL && secflag_enabled(curproc, PROC_SEC_ASLR)) {
@@ -1876,24 +1921,39 @@ elfnote(vnode_t *vp, offset_t *offsetp, int type, int descsz, void *desc,
return (0);
}
+
/*
* Copy the section data from one vnode to the section of another vnode.
*/
static void
-copy_scn(Shdr *src, vnode_t *src_vp, Shdr *dst, vnode_t *dst_vp, Off *doffset,
- void *buf, size_t size, cred_t *credp, rlim64_t rlimit)
+elf_copy_scn(elf_core_ctx_t *ctx, const Shdr *src, vnode_t *src_vp, Shdr *dst)
{
- ssize_t resid;
- size_t len, n = src->sh_size;
- offset_t off = 0;
+ size_t n = src->sh_size;
+ u_offset_t off = 0;
+ const u_offset_t soff = src->sh_offset;
+ const u_offset_t doff = ctx->ecc_doffset;
+ void *buf = ctx->ecc_buf;
+ vnode_t *dst_vp = ctx->ecc_vp;
+ cred_t *credp = ctx->ecc_credp;
+
+ /* Protect the copy loop below from overflow on the offsets */
+ if (n > OFF_MAX || (n + soff) > OFF_MAX || (n + doff) > OFF_MAX ||
+ (n + soff) < n || (n + doff) < n) {
+ dst->sh_size = 0;
+ dst->sh_offset = 0;
+ return;
+ }
while (n != 0) {
- len = MIN(size, n);
- if (vn_rdwr(UIO_READ, src_vp, buf, len, src->sh_offset + off,
+ const size_t len = MIN(ctx->ecc_bufsz, n);
+ ssize_t resid;
+
+ if (vn_rdwr(UIO_READ, src_vp, buf, (ssize_t)len,
+ (offset_t)(soff + off),
UIO_SYSSPACE, 0, (rlim64_t)0, credp, &resid) != 0 ||
- resid >= len ||
- core_write(dst_vp, UIO_SYSSPACE, *doffset + off,
- buf, len - resid, rlimit, credp) != 0) {
+ resid >= len || resid < 0 ||
+ core_write(dst_vp, UIO_SYSSPACE, (offset_t)(doff + off),
+ buf, len - resid, ctx->ecc_rlimit, credp) != 0) {
dst->sh_size = 0;
dst->sh_offset = 0;
return;
@@ -1905,62 +1965,222 @@ copy_scn(Shdr *src, vnode_t *src_vp, Shdr *dst, vnode_t *dst_vp, Off *doffset,
off += len - resid;
}
- *doffset += src->sh_size;
+ ctx->ecc_doffset += src->sh_size;
}
-#ifdef _ELF32_COMPAT
-extern size_t elf_datasz_max;
-#else
-size_t elf_datasz_max = 1 * 1024 * 1024;
-#endif
+/*
+ * Walk sections for a given ELF object, counting (or copying) those of
+ * interest (CTF, symtab, strtab).
+ */
+static uint_t
+elf_process_obj_scns(elf_core_ctx_t *ctx, vnode_t *mvp, caddr_t saddr,
+ Shdr *v, uint_t idx, uint_t remain, shstrtab_t *shstrtab)
+{
+ Ehdr ehdr;
+ const core_content_t content = ctx->ecc_content;
+ cred_t *credp = ctx->ecc_credp;
+ Shdr *ctf = NULL, *symtab = NULL, *strtab = NULL;
+ uintptr_t off = 0;
+ uint_t nshdrs, shstrndx, nphdrs, count = 0;
+ u_offset_t *doffp = &ctx->ecc_doffset;
+ boolean_t ctf_link = B_FALSE;
+ caddr_t shbase;
+ size_t shsize, shstrsize;
+ char *shstrbase;
+
+ if ((content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) == 0) {
+ return (0);
+ }
+
+ if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx, &nphdrs) != 0 ||
+ getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx, &shbase, &shsize,
+ &shstrbase, &shstrsize) != 0) {
+ return (0);
+ }
+
+ /* Starting at index 1 skips SHT_NULL which is expected at index 0 */
+ off = ehdr.e_shentsize;
+ for (uint_t i = 1; i < nshdrs; i++, off += ehdr.e_shentsize) {
+ Shdr *shdr, *symchk = NULL, *strchk;
+ const char *name;
+
+ shdr = (Shdr *)(shbase + off);
+ if (shdr->sh_name >= shstrsize || shdr->sh_type == SHT_NULL)
+ continue;
+
+ name = shstrbase + shdr->sh_name;
+
+ if (ctf == NULL &&
+ (content & CC_CONTENT_CTF) != 0 &&
+ strcmp(name, shstrtab_data[STR_CTF]) == 0) {
+ ctf = shdr;
+ if (ctf->sh_link != 0 && ctf->sh_link < nshdrs) {
+ /* check linked symtab below */
+ symchk = (Shdr *)(shbase +
+ shdr->sh_link * ehdr.e_shentsize);
+ ctf_link = B_TRUE;
+ } else {
+ continue;
+ }
+ } else if (symtab == NULL &&
+ (content & CC_CONTENT_SYMTAB) != 0 &&
+ strcmp(name, shstrtab_data[STR_SYMTAB]) == 0) {
+ symchk = shdr;
+ } else {
+ continue;
+ }
+
+ ASSERT(symchk != NULL);
+ if ((symchk->sh_type != SHT_DYNSYM &&
+ symchk->sh_type != SHT_SYMTAB) ||
+ symchk->sh_link == 0 || symchk->sh_link >= nshdrs) {
+ ctf_link = B_FALSE;
+ continue;
+ }
+ strchk = (Shdr *)(shbase + symchk->sh_link * ehdr.e_shentsize);
+ if (strchk->sh_type != SHT_STRTAB) {
+ ctf_link = B_FALSE;
+ continue;
+ }
+ symtab = symchk;
+ strtab = strchk;
+
+ if (symtab != NULL && ctf != NULL) {
+ /* No other shdrs are of interest at this point */
+ break;
+ }
+ }
+
+ if (ctf != NULL)
+ count += 1;
+ if (symtab != NULL)
+ count += 2;
+ if (v == NULL || count == 0 || count > remain) {
+ count = MIN(count, remain);
+ goto done;
+ }
+
+ /* output CTF section */
+ if (ctf != NULL) {
+ elf_ctx_resize_scratch(ctx, ctf->sh_size);
+
+ v[idx].sh_name = shstrtab_ndx(shstrtab, STR_CTF);
+ v[idx].sh_addr = (Addr)(uintptr_t)saddr;
+ v[idx].sh_type = SHT_PROGBITS;
+ v[idx].sh_addralign = 4;
+ *doffp = roundup(*doffp, v[idx].sh_addralign);
+ v[idx].sh_offset = *doffp;
+ v[idx].sh_size = ctf->sh_size;
+
+ if (ctf_link) {
+ /*
+ * The linked symtab (and strtab) will be output
+ * immediately after this CTF section. Its shdr index
+ * directly follows this one.
+ */
+ v[idx].sh_link = idx + 1;
+ ASSERT(symtab != NULL);
+ } else {
+ v[idx].sh_link = 0;
+ }
+ elf_copy_scn(ctx, ctf, mvp, &v[idx]);
+ idx++;
+ }
+
+ /* output SYMTAB/STRTAB sections */
+ if (symtab != NULL) {
+ uint_t symtab_name, strtab_name;
+
+ elf_ctx_resize_scratch(ctx,
+ MAX(symtab->sh_size, strtab->sh_size));
+
+ if (symtab->sh_type == SHT_DYNSYM) {
+ symtab_name = shstrtab_ndx(shstrtab, STR_DYNSYM);
+ strtab_name = shstrtab_ndx(shstrtab, STR_DYNSTR);
+ } else {
+ symtab_name = shstrtab_ndx(shstrtab, STR_SYMTAB);
+ strtab_name = shstrtab_ndx(shstrtab, STR_STRTAB);
+ }
+
+ v[idx].sh_name = symtab_name;
+ v[idx].sh_type = symtab->sh_type;
+ v[idx].sh_addr = symtab->sh_addr;
+ if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
+ v[idx].sh_addr += (Addr)(uintptr_t)saddr;
+ v[idx].sh_addralign = symtab->sh_addralign;
+ *doffp = roundup(*doffp, v[idx].sh_addralign);
+ v[idx].sh_offset = *doffp;
+ v[idx].sh_size = symtab->sh_size;
+ v[idx].sh_link = idx + 1;
+ v[idx].sh_entsize = symtab->sh_entsize;
+ v[idx].sh_info = symtab->sh_info;
+
+ elf_copy_scn(ctx, symtab, mvp, &v[idx]);
+ idx++;
+
+ v[idx].sh_name = strtab_name;
+ v[idx].sh_type = SHT_STRTAB;
+ v[idx].sh_flags = SHF_STRINGS;
+ v[idx].sh_addr = strtab->sh_addr;
+ if (ehdr.e_type == ET_DYN || v[idx].sh_addr == 0)
+ v[idx].sh_addr += (Addr)(uintptr_t)saddr;
+ v[idx].sh_addralign = strtab->sh_addralign;
+ *doffp = roundup(*doffp, v[idx].sh_addralign);
+ v[idx].sh_offset = *doffp;
+ v[idx].sh_size = strtab->sh_size;
+
+ elf_copy_scn(ctx, strtab, mvp, &v[idx]);
+ idx++;
+ }
+
+done:
+ kmem_free(shstrbase, shstrsize);
+ kmem_free(shbase, shsize);
+ return (count);
+}
/*
- * This function processes mappings that correspond to load objects to
- * examine their respective sections for elfcore(). It's called once with
- * v set to NULL to count the number of sections that we're going to need
- * and then again with v set to some allocated buffer that we fill in with
- * all the section data.
+ * Walk mappings in process address space, examining those which correspond to
+ * loaded objects. It is called twice from elfcore: Once to simply count
+ * relevant sections, and again later to copy those sections once an adequate
+ * buffer has been allocated for the shdr details.
*/
static int
-process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
- Shdr *v, int nv, rlim64_t rlimit, Off *doffsetp, int *nshdrsp)
+elf_process_scns(elf_core_ctx_t *ctx, Shdr *v, uint_t nv, uint_t *nshdrsp)
{
vnode_t *lastvp = NULL;
struct seg *seg;
- int i, j;
- void *data = NULL;
- size_t datasz = 0;
+ uint_t idx = 0, remain;
shstrtab_t shstrtab;
- struct as *as = p->p_as;
+ struct as *as = ctx->ecc_p->p_as;
int error = 0;
- if (v != NULL)
+ ASSERT(AS_WRITE_HELD(as));
+
+ if (v != NULL) {
+ ASSERT(nv != 0);
+
shstrtab_init(&shstrtab);
+ remain = nv;
+ } else {
+ ASSERT(nv == 0);
- i = 1;
+ /*
+ * The shdrs are being counted, rather than outputting them
+ * into a buffer. Leave room for two entries: the SHT_NULL at
+ * index 0 and the shstrtab at the end.
+ */
+ remain = UINT_MAX - 2;
+ }
+
+ /* Per the ELF spec, shdr index 0 is reserved. */
+ idx = 1;
for (seg = AS_SEGFIRST(as); seg != NULL; seg = AS_SEGNEXT(as, seg)) {
- uint_t prot;
vnode_t *mvp;
void *tmp = NULL;
- caddr_t saddr = seg->s_base;
- caddr_t naddr;
- caddr_t eaddr;
+ caddr_t saddr = seg->s_base, naddr, eaddr;
size_t segsize;
-
- Ehdr ehdr;
- int nshdrs, shstrndx, nphdrs;
- caddr_t shbase;
- ssize_t shsize;
- char *shstrbase;
- ssize_t shstrsize;
-
- Shdr *shdr;
- const char *name;
- size_t sz;
- uintptr_t off;
-
- int ctf_ndx = 0;
- int symtab_ndx = 0;
+ uint_t count, prot;
/*
* Since we're just looking for text segments of load
@@ -1986,222 +2206,51 @@ process_scns(core_content_t content, proc_t *p, cred_t *credp, vnode_t *vp,
if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC)
continue;
- if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx,
- &nphdrs) != 0 ||
- getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx,
- &shbase, &shsize, &shstrbase, &shstrsize) != 0)
- continue;
-
- off = ehdr.e_shentsize;
- for (j = 1; j < nshdrs; j++, off += ehdr.e_shentsize) {
- Shdr *symtab = NULL, *strtab;
-
- shdr = (Shdr *)(shbase + off);
-
- if (shdr->sh_name >= shstrsize)
- continue;
-
- name = shstrbase + shdr->sh_name;
-
- if (strcmp(name, shstrtab_data[STR_CTF]) == 0) {
- if ((content & CC_CONTENT_CTF) == 0 ||
- ctf_ndx != 0)
- continue;
-
- if (shdr->sh_link > 0 &&
- shdr->sh_link < nshdrs) {
- symtab = (Shdr *)(shbase +
- shdr->sh_link * ehdr.e_shentsize);
- }
+ count = elf_process_obj_scns(ctx, mvp, saddr, v, idx, remain,
+ &shstrtab);
- if (v != NULL && i < nv - 1) {
- if (shdr->sh_size > datasz &&
- shdr->sh_size <= elf_datasz_max) {
- if (data != NULL)
- kmem_free(data, datasz);
-
- datasz = shdr->sh_size;
- data = kmem_alloc(datasz,
- KM_SLEEP);
- }
-
- v[i].sh_name = shstrtab_ndx(&shstrtab,
- STR_CTF);
- v[i].sh_addr = (Addr)(uintptr_t)saddr;
- v[i].sh_type = SHT_PROGBITS;
- v[i].sh_addralign = 4;
- *doffsetp = roundup(*doffsetp,
- v[i].sh_addralign);
- v[i].sh_offset = *doffsetp;
- v[i].sh_size = shdr->sh_size;
- if (symtab == NULL) {
- v[i].sh_link = 0;
- } else if (symtab->sh_type ==
- SHT_SYMTAB &&
- symtab_ndx != 0) {
- v[i].sh_link =
- symtab_ndx;
- } else {
- v[i].sh_link = i + 1;
- }
-
- copy_scn(shdr, mvp, &v[i], vp,
- doffsetp, data, datasz, credp,
- rlimit);
- }
-
- ctf_ndx = i++;
-
- /*
- * We've already dumped the symtab.
- */
- if (symtab != NULL &&
- symtab->sh_type == SHT_SYMTAB &&
- symtab_ndx != 0)
- continue;
-
- } else if (strcmp(name,
- shstrtab_data[STR_SYMTAB]) == 0) {
- if ((content & CC_CONTENT_SYMTAB) == 0 ||
- symtab != 0)
- continue;
-
- symtab = shdr;
- }
-
- if (symtab != NULL) {
- if ((symtab->sh_type != SHT_DYNSYM &&
- symtab->sh_type != SHT_SYMTAB) ||
- symtab->sh_link == 0 ||
- symtab->sh_link >= nshdrs)
- continue;
-
- strtab = (Shdr *)(shbase +
- symtab->sh_link * ehdr.e_shentsize);
-
- if (strtab->sh_type != SHT_STRTAB)
- continue;
-
- if (v != NULL && i < nv - 2) {
- sz = MAX(symtab->sh_size,
- strtab->sh_size);
- if (sz > datasz &&
- sz <= elf_datasz_max) {
- if (data != NULL)
- kmem_free(data, datasz);
-
- datasz = sz;
- data = kmem_alloc(datasz,
- KM_SLEEP);
- }
-
- if (symtab->sh_type == SHT_DYNSYM) {
- v[i].sh_name = shstrtab_ndx(
- &shstrtab, STR_DYNSYM);
- v[i + 1].sh_name = shstrtab_ndx(
- &shstrtab, STR_DYNSTR);
- } else {
- v[i].sh_name = shstrtab_ndx(
- &shstrtab, STR_SYMTAB);
- v[i + 1].sh_name = shstrtab_ndx(
- &shstrtab, STR_STRTAB);
- }
-
- v[i].sh_type = symtab->sh_type;
- v[i].sh_addr = symtab->sh_addr;
- if (ehdr.e_type == ET_DYN ||
- v[i].sh_addr == 0)
- v[i].sh_addr +=
- (Addr)(uintptr_t)saddr;
- v[i].sh_addralign =
- symtab->sh_addralign;
- *doffsetp = roundup(*doffsetp,
- v[i].sh_addralign);
- v[i].sh_offset = *doffsetp;
- v[i].sh_size = symtab->sh_size;
- v[i].sh_link = i + 1;
- v[i].sh_entsize = symtab->sh_entsize;
- v[i].sh_info = symtab->sh_info;
-
- copy_scn(symtab, mvp, &v[i], vp,
- doffsetp, data, datasz, credp,
- rlimit);
-
- v[i + 1].sh_type = SHT_STRTAB;
- v[i + 1].sh_flags = SHF_STRINGS;
- v[i + 1].sh_addr = symtab->sh_addr;
- if (ehdr.e_type == ET_DYN ||
- v[i + 1].sh_addr == 0)
- v[i + 1].sh_addr +=
- (Addr)(uintptr_t)saddr;
- v[i + 1].sh_addralign =
- strtab->sh_addralign;
- *doffsetp = roundup(*doffsetp,
- v[i + 1].sh_addralign);
- v[i + 1].sh_offset = *doffsetp;
- v[i + 1].sh_size = strtab->sh_size;
-
- copy_scn(strtab, mvp, &v[i + 1], vp,
- doffsetp, data, datasz, credp,
- rlimit);
- }
-
- if (symtab->sh_type == SHT_SYMTAB)
- symtab_ndx = i;
- i += 2;
- }
- }
-
- kmem_free(shstrbase, shstrsize);
- kmem_free(shbase, shsize);
+ ASSERT(count <= remain);
+ ASSERT(v == NULL || (idx + count) < nv);
+ remain -= count;
+ idx += count;
lastvp = mvp;
}
if (v == NULL) {
- if (i == 1)
+ if (idx == 1) {
*nshdrsp = 0;
- else
- *nshdrsp = i + 1;
- goto done;
+ } else {
+ /* Include room for the shrstrtab at the end */
+ *nshdrsp = idx + 1;
+ }
+ return (0);
}
- if (i != nv - 1) {
+ if (idx != nv - 1) {
cmn_err(CE_WARN, "elfcore: core dump failed for "
- "process %d; address space is changing", p->p_pid);
- error = EIO;
- goto done;
+ "process %d; address space is changing",
+ ctx->ecc_p->p_pid);
+ return (EIO);
}
- v[i].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
- v[i].sh_size = shstrtab_size(&shstrtab);
- v[i].sh_addralign = 1;
- *doffsetp = roundup(*doffsetp, v[i].sh_addralign);
- v[i].sh_offset = *doffsetp;
- v[i].sh_flags = SHF_STRINGS;
- v[i].sh_type = SHT_STRTAB;
-
- if (v[i].sh_size > datasz) {
- if (data != NULL)
- kmem_free(data, datasz);
-
- datasz = v[i].sh_size;
- data = kmem_alloc(datasz,
- KM_SLEEP);
+ v[idx].sh_name = shstrtab_ndx(&shstrtab, STR_SHSTRTAB);
+ v[idx].sh_size = shstrtab_size(&shstrtab);
+ v[idx].sh_addralign = 1;
+ v[idx].sh_offset = ctx->ecc_doffset;
+ v[idx].sh_flags = SHF_STRINGS;
+ v[idx].sh_type = SHT_STRTAB;
+
+ elf_ctx_resize_scratch(ctx, v[idx].sh_size);
+ VERIFY3U(ctx->ecc_bufsz, >=, v[idx].sh_size);
+ shstrtab_dump(&shstrtab, ctx->ecc_buf);
+
+ error = core_write(ctx->ecc_vp, UIO_SYSSPACE, ctx->ecc_doffset,
+ ctx->ecc_buf, v[idx].sh_size, ctx->ecc_rlimit, ctx->ecc_credp);
+ if (error == 0) {
+ ctx->ecc_doffset += v[idx].sh_size;
}
- shstrtab_dump(&shstrtab, data);
-
- if ((error = core_write(vp, UIO_SYSSPACE, *doffsetp,
- data, v[i].sh_size, rlimit, credp)) != 0)
- goto done;
-
- *doffsetp += v[i].sh_size;
-
-done:
- if (data != NULL)
- kmem_free(data, datasz);
-
return (error);
}
@@ -2209,27 +2258,30 @@ int
elfcore(vnode_t *vp, proc_t *p, cred_t *credp, rlim64_t rlimit, int sig,
core_content_t content)
{
- offset_t poffset, soffset;
- Off doffset;
- int error, i, nphdrs, nshdrs;
- int overflow = 0;
+ u_offset_t poffset, soffset, doffset;
+ int error;
+ uint_t i, nphdrs, nshdrs;
struct seg *seg;
struct as *as = p->p_as;
- union {
- Ehdr ehdr;
- Phdr phdr[1];
- Shdr shdr[1];
- } *bigwad;
- size_t bigsize;
- size_t phdrsz, shdrsz;
+ void *bigwad;
+ size_t bigsize, phdrsz, shdrsz;
Ehdr *ehdr;
- Phdr *v;
- caddr_t brkbase;
- size_t brksize;
- caddr_t stkbase;
- size_t stksize;
- int ntries = 0;
+ Phdr *phdr;
+ Shdr shdr0;
+ caddr_t brkbase, stkbase;
+ size_t brksize, stksize;
+ boolean_t overflowed = B_FALSE, retried = B_FALSE;
klwp_t *lwp = ttolwp(curthread);
+ elf_core_ctx_t ctx = {
+ .ecc_vp = vp,
+ .ecc_p = p,
+ .ecc_credp = credp,
+ .ecc_rlimit = rlimit,
+ .ecc_content = content,
+ .ecc_doffset = 0,
+ .ecc_buf = NULL,
+ .ecc_bufsz = 0
+ };
top:
/*
@@ -2247,28 +2299,32 @@ top:
*/
nshdrs = 0;
if (content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)) {
- (void) process_scns(content, p, credp, NULL, NULL, NULL, 0,
- NULL, &nshdrs);
+ VERIFY0(elf_process_scns(&ctx, NULL, 0, &nshdrs));
}
AS_LOCK_EXIT(as);
- ASSERT(nshdrs == 0 || nshdrs > 1);
-
/*
- * The core file contents may required zero section headers, but if
+ * The core file contents may require zero section headers, but if
* we overflow the 16 bits allotted to the program header count in
* the ELF header, we'll need that program header at index zero.
*/
- if (nshdrs == 0 && nphdrs >= PN_XNUM)
+ if (nshdrs == 0 && nphdrs >= PN_XNUM) {
nshdrs = 1;
+ }
+ /*
+ * Allocate a buffer which is sized adequately to hold the ehdr, phdrs
+ * or shdrs needed to produce the core file. It is used for the three
+ * tasks sequentially, not simultaneously, so it does not need space
+ * for all three data at once, only the largest one.
+ */
+ VERIFY(nphdrs >= 2);
phdrsz = nphdrs * sizeof (Phdr);
shdrsz = nshdrs * sizeof (Shdr);
-
- bigsize = MAX(sizeof (*bigwad), MAX(phdrsz, shdrsz));
+ bigsize = MAX(sizeof (Ehdr), MAX(phdrsz, shdrsz));
bigwad = kmem_alloc(bigsize, KM_SLEEP);
- ehdr = &bigwad->ehdr;
+ ehdr = (Ehdr *)bigwad;
bzero(ehdr, sizeof (*ehdr));
ehdr->e_ident[EI_MAG0] = ELFMAG0;
@@ -2304,6 +2360,11 @@ top:
#endif /* !defined(_LP64) || defined(_ELF32_COMPAT) */
+ poffset = sizeof (Ehdr);
+ soffset = sizeof (Ehdr) + phdrsz;
+ doffset = sizeof (Ehdr) + phdrsz + shdrsz;
+ bzero(&shdr0, sizeof (shdr0));
+
/*
* If the count of program headers or section headers or the index
* of the section string table can't fit in the mere 16 bits
@@ -2311,50 +2372,52 @@ top:
* extended formats and put the real values in the section header
* as index 0.
*/
- ehdr->e_version = EV_CURRENT;
- ehdr->e_ehsize = sizeof (Ehdr);
-
- if (nphdrs >= PN_XNUM)
+ if (nphdrs >= PN_XNUM) {
ehdr->e_phnum = PN_XNUM;
- else
+ shdr0.sh_info = nphdrs;
+ } else {
ehdr->e_phnum = (unsigned short)nphdrs;
-
- ehdr->e_phoff = sizeof (Ehdr);
- ehdr->e_phentsize = sizeof (Phdr);
+ }
if (nshdrs > 0) {
- if (nshdrs >= SHN_LORESERVE)
+ if (nshdrs >= SHN_LORESERVE) {
ehdr->e_shnum = 0;
- else
+ shdr0.sh_size = nshdrs;
+ } else {
ehdr->e_shnum = (unsigned short)nshdrs;
+ }
- if (nshdrs - 1 >= SHN_LORESERVE)
+ if (nshdrs - 1 >= SHN_LORESERVE) {
ehdr->e_shstrndx = SHN_XINDEX;
- else
+ shdr0.sh_link = nshdrs - 1;
+ } else {
ehdr->e_shstrndx = (unsigned short)(nshdrs - 1);
+ }
- ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * nphdrs;
+ ehdr->e_shoff = soffset;
ehdr->e_shentsize = sizeof (Shdr);
}
+ ehdr->e_version = EV_CURRENT;
+ ehdr->e_ehsize = sizeof (Ehdr);
+ ehdr->e_phoff = poffset;
+ ehdr->e_phentsize = sizeof (Phdr);
+
if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr,
- sizeof (Ehdr), rlimit, credp))
+ sizeof (Ehdr), rlimit, credp)) {
goto done;
+ }
- poffset = sizeof (Ehdr);
- soffset = sizeof (Ehdr) + phdrsz;
- doffset = sizeof (Ehdr) + phdrsz + shdrsz;
-
- v = &bigwad->phdr[0];
- bzero(v, phdrsz);
+ phdr = (Phdr *)bigwad;
+ bzero(phdr, phdrsz);
- setup_old_note_header(&v[0], p);
- v[0].p_offset = doffset = roundup(doffset, sizeof (Word));
- doffset += v[0].p_filesz;
+ setup_old_note_header(&phdr[0], p);
+ phdr[0].p_offset = doffset = roundup(doffset, sizeof (Word));
+ doffset += phdr[0].p_filesz;
- setup_note_header(&v[1], p);
- v[1].p_offset = doffset = roundup(doffset, sizeof (Word));
- doffset += v[1].p_filesz;
+ setup_note_header(&phdr[1], p);
+ phdr[1].p_offset = doffset = roundup(doffset, sizeof (Word));
+ doffset += phdr[1].p_filesz;
mutex_enter(&p->p_lock);
@@ -2386,21 +2449,23 @@ top:
prot = pr_getprot(seg, 0, &tmp, &saddr, &naddr, eaddr);
prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
- if ((size = (size_t)(naddr - saddr)) == 0)
- continue;
- if (i == nphdrs) {
- overflow++;
+ if ((size = (size_t)(naddr - saddr)) == 0) {
+ ASSERT(tmp == NULL);
continue;
+ } else if (i == nphdrs) {
+ pr_getprot_done(&tmp);
+ overflowed = B_TRUE;
+ break;
}
- v[i].p_type = PT_LOAD;
- v[i].p_vaddr = (Addr)(uintptr_t)saddr;
- v[i].p_memsz = size;
+ phdr[i].p_type = PT_LOAD;
+ phdr[i].p_vaddr = (Addr)(uintptr_t)saddr;
+ phdr[i].p_memsz = size;
if (prot & PROT_READ)
- v[i].p_flags |= PF_R;
+ phdr[i].p_flags |= PF_R;
if (prot & PROT_WRITE)
- v[i].p_flags |= PF_W;
+ phdr[i].p_flags |= PF_W;
if (prot & PROT_EXEC)
- v[i].p_flags |= PF_X;
+ phdr[i].p_flags |= PF_X;
/*
* Figure out which mappings to include in the core.
@@ -2462,20 +2527,23 @@ top:
}
doffset = roundup(doffset, sizeof (Word));
- v[i].p_offset = doffset;
- v[i].p_filesz = size;
+ phdr[i].p_offset = doffset;
+ phdr[i].p_filesz = size;
doffset += size;
exclude:
i++;
}
- ASSERT(tmp == NULL);
+ VERIFY(tmp == NULL);
+ if (overflowed)
+ break;
}
AS_LOCK_EXIT(as);
- if (overflow || i != nphdrs) {
- if (ntries++ == 0) {
+ if (overflowed || i != nphdrs) {
+ if (!retried) {
+ retried = B_TRUE;
+ overflowed = B_FALSE;
kmem_free(bigwad, bigsize);
- overflow = 0;
goto top;
}
cmn_err(CE_WARN, "elfcore: core dump failed for "
@@ -2485,23 +2553,25 @@ exclude:
}
if ((error = core_write(vp, UIO_SYSSPACE, poffset,
- v, phdrsz, rlimit, credp)) != 0)
+ phdr, phdrsz, rlimit, credp)) != 0) {
goto done;
+ }
- if ((error = write_old_elfnotes(p, sig, vp, v[0].p_offset, rlimit,
- credp)) != 0)
+ if ((error = write_old_elfnotes(p, sig, vp, phdr[0].p_offset, rlimit,
+ credp)) != 0) {
goto done;
-
- if ((error = write_elfnotes(p, sig, vp, v[1].p_offset, rlimit,
- credp, content)) != 0)
+ }
+ if ((error = write_elfnotes(p, sig, vp, phdr[1].p_offset, rlimit,
+ credp, content)) != 0) {
goto done;
+ }
for (i = 2; i < nphdrs; i++) {
prkillinfo_t killinfo;
sigqueue_t *sq;
int sig, j;
- if (v[i].p_filesz == 0)
+ if (phdr[i].p_filesz == 0)
continue;
/*
@@ -2512,8 +2582,8 @@ exclude:
* this from mappings that were excluded due to the core file
* content settings.
*/
- if ((error = core_seg(p, vp, v[i].p_offset,
- (caddr_t)(uintptr_t)v[i].p_vaddr, v[i].p_filesz,
+ if ((error = core_seg(p, vp, phdr[i].p_offset,
+ (caddr_t)(uintptr_t)phdr[i].p_vaddr, phdr[i].p_filesz,
rlimit, credp)) == 0) {
continue;
}
@@ -2526,14 +2596,14 @@ exclude:
* bytes. This undocumented interface will let us
* understand the nature of the failure.
*/
- (void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
+ (void) core_write(vp, UIO_SYSSPACE, phdr[i].p_offset,
&error, sizeof (error), rlimit, credp);
- v[i].p_filesz = 0;
- v[i].p_flags |= PF_SUNW_FAILURE;
+ phdr[i].p_filesz = 0;
+ phdr[i].p_flags |= PF_SUNW_FAILURE;
if ((error = core_write(vp, UIO_SYSSPACE,
- poffset + sizeof (v[i]) * i, &v[i], sizeof (v[i]),
- rlimit, credp)) != 0)
+ poffset + sizeof (Phdr) * i, &phdr[i],
+ sizeof (Phdr), rlimit, credp)) != 0)
goto done;
continue;
@@ -2575,15 +2645,15 @@ exclude:
}
#endif
- (void) core_write(vp, UIO_SYSSPACE, v[i].p_offset,
+ (void) core_write(vp, UIO_SYSSPACE, phdr[i].p_offset,
&killinfo, sizeof (killinfo), rlimit, credp);
/*
* For the segment on which we took the signal, indicate that
* its data now refers to a siginfo.
*/
- v[i].p_filesz = 0;
- v[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED |
+ phdr[i].p_filesz = 0;
+ phdr[i].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED |
PF_SUNW_SIGINFO;
/*
@@ -2591,50 +2661,46 @@ exclude:
* is due to a signal.
*/
for (j = i + 1; j < nphdrs; j++) {
- v[j].p_filesz = 0;
- v[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED;
+ phdr[j].p_filesz = 0;
+ phdr[j].p_flags |= PF_SUNW_FAILURE | PF_SUNW_KILLED;
}
/*
* Finally, write out our modified program headers.
*/
if ((error = core_write(vp, UIO_SYSSPACE,
- poffset + sizeof (v[i]) * i, &v[i],
- sizeof (v[i]) * (nphdrs - i), rlimit, credp)) != 0)
+ poffset + sizeof (Phdr) * i, &phdr[i],
+ sizeof (Phdr) * (nphdrs - i), rlimit, credp)) != 0) {
goto done;
+ }
break;
}
if (nshdrs > 0) {
- bzero(&bigwad->shdr[0], shdrsz);
-
- if (nshdrs >= SHN_LORESERVE)
- bigwad->shdr[0].sh_size = nshdrs;
-
- if (nshdrs - 1 >= SHN_LORESERVE)
- bigwad->shdr[0].sh_link = nshdrs - 1;
-
- if (nphdrs >= PN_XNUM)
- bigwad->shdr[0].sh_info = nphdrs;
+ Shdr *shdr = (Shdr *)bigwad;
+ bzero(shdr, shdrsz);
if (nshdrs > 1) {
+ ctx.ecc_doffset = doffset;
AS_LOCK_ENTER(as, RW_WRITER);
- if ((error = process_scns(content, p, credp, vp,
- &bigwad->shdr[0], nshdrs, rlimit, &doffset,
- NULL)) != 0) {
- AS_LOCK_EXIT(as);
+ error = elf_process_scns(&ctx, shdr, nshdrs, NULL);
+ AS_LOCK_EXIT(as);
+ if (error != 0) {
goto done;
}
- AS_LOCK_EXIT(as);
}
+ /* Copy any extended format data destined for the first shdr */
+ bcopy(&shdr0, shdr, sizeof (shdr0));
- if ((error = core_write(vp, UIO_SYSSPACE, soffset,
- &bigwad->shdr[0], shdrsz, rlimit, credp)) != 0)
- goto done;
+ error = core_write(vp, UIO_SYSSPACE, soffset, shdr, shdrsz,
+ rlimit, credp);
}
done:
+ if (ctx.ecc_bufsz != 0) {
+ kmem_free(ctx.ecc_buf, ctx.ecc_bufsz);
+ }
kmem_free(bigwad, bigsize);
return (error);
}
@@ -2659,7 +2725,7 @@ static struct modlexec modlexec = {
#ifdef _LP64
extern int elf32exec(vnode_t *vp, execa_t *uap, uarg_t *args,
- intpdata_t *idatap, int level, long *execsz,
+ intpdata_t *idatap, int level, size_t *execsz,
int setid, caddr_t exec_file, cred_t *cred,
int *brand_action);
extern int elf32core(vnode_t *vp, proc_t *p, cred_t *credp,
diff --git a/usr/src/uts/common/exec/elf/elf_impl.h b/usr/src/uts/common/exec/elf/elf_impl.h
index 010d5e6256..504cf84dd2 100644
--- a/usr/src/uts/common/exec/elf/elf_impl.h
+++ b/usr/src/uts/common/exec/elf/elf_impl.h
@@ -22,12 +22,13 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
#ifndef _ELF_ELF_IMPL_H
#define _ELF_ELF_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -71,6 +72,17 @@ typedef struct {
char name[8];
} Note;
+typedef struct {
+ vnode_t *ecc_vp;
+ proc_t *ecc_p;
+ cred_t *ecc_credp;
+ rlim64_t ecc_rlimit;
+ core_content_t ecc_content;
+ u_offset_t ecc_doffset;
+ void *ecc_buf;
+ size_t ecc_bufsz;
+} elf_core_ctx_t;
+
#ifdef _ELF32_COMPAT
/*
* These are defined only for the 32-bit compatibility
@@ -79,6 +91,7 @@ typedef struct {
#define elfexec elf32exec
#define elfnote elf32note
#define elfcore elf32core
+#define elfreadhdr elf32readhdr
#define mapexec_brand mapexec32_brand
#define setup_note_header setup_note_header32
#define write_elfnotes write_elfnotes32
diff --git a/usr/src/uts/common/exec/intp/intp.c b/usr/src/uts/common/exec/intp/intp.c
index 512cab2b66..388d913ea0 100644
--- a/usr/src/uts/common/exec/intp/intp.c
+++ b/usr/src/uts/common/exec/intp/intp.c
@@ -22,7 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
- * Copyright 2016, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -56,7 +56,7 @@
#include <sys/modctl.h>
extern int intpexec(struct vnode *, struct execa *, struct uarg *,
- struct intpdata *, int, long *, int, caddr_t, struct cred *, int *);
+ struct intpdata *, int, size_t *, int, caddr_t, struct cred *, int *);
static struct execsw esw = {
intpmagicstr,
@@ -196,7 +196,7 @@ intpexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred,
diff --git a/usr/src/uts/common/exec/java/java.c b/usr/src/uts/common/exec/java/java.c
index 5170fda5cb..a61a6f105f 100644
--- a/usr/src/uts/common/exec/java/java.c
+++ b/usr/src/uts/common/exec/java/java.c
@@ -21,7 +21,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2015, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -85,7 +85,7 @@ char *jexec_arg = "-jar";
/*ARGSUSED3*/
static int
javaexec(vnode_t *vp, struct execa *uap, struct uarg *args,
- struct intpdata *idatap, int level, long *execsz, int setid,
+ struct intpdata *idatap, int level, size_t *execsz, int setid,
caddr_t execfile, cred_t *cred, int *brand_action)
{
struct intpdata idata;
diff --git a/usr/src/uts/common/exec/shbin/shbin.c b/usr/src/uts/common/exec/shbin/shbin.c
index 016d87b9ef..7b653a4c98 100644
--- a/usr/src/uts/common/exec/shbin/shbin.c
+++ b/usr/src/uts/common/exec/shbin/shbin.c
@@ -22,7 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2015, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/types.h>
@@ -55,7 +55,7 @@ shbinexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred,
@@ -159,7 +159,7 @@ shbinexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred,
diff --git a/usr/src/uts/common/fs/fs_subr.h b/usr/src/uts/common/fs/fs_subr.h
index d25bf0213f..877dc36f9c 100644
--- a/usr/src/uts/common/fs/fs_subr.h
+++ b/usr/src/uts/common/fs/fs_subr.h
@@ -49,7 +49,7 @@ extern "C" {
* Utilities shared among file system implementations.
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern int fs_nosys();
extern int fs_inval();
diff --git a/usr/src/uts/common/fs/proc/prioctl.c b/usr/src/uts/common/fs/proc/prioctl.c
index 470c66362b..6aabe28200 100644
--- a/usr/src/uts/common/fs/proc/prioctl.c
+++ b/usr/src/uts/common/fs/proc/prioctl.c
@@ -22,7 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -943,7 +943,7 @@ startover:
case PIOCNMAP: /* get number of memory mappings */
{
- int n;
+ uint_t n;
struct as *as = p->p_as;
if ((p->p_flag & SSYS) || as == &kas)
@@ -956,7 +956,7 @@ startover:
mutex_enter(&p->p_lock);
}
prunlock(pnp);
- if (copyout(&n, cmaddr, sizeof (int)))
+ if (copyout(&n, cmaddr, sizeof (uint_t)))
error = EFAULT;
break;
}
@@ -2562,7 +2562,7 @@ startover:
case PIOCNMAP: /* get number of memory mappings */
{
- int n;
+ uint_t n;
struct as *as = p->p_as;
if ((p->p_flag & SSYS) || as == &kas)
@@ -2575,7 +2575,7 @@ startover:
mutex_enter(&p->p_lock);
}
prunlock(pnp);
- if (copyout(&n, cmaddr, sizeof (int)))
+ if (copyout(&n, cmaddr, sizeof (uint_t)))
error = EFAULT;
break;
}
diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c
index 2062970885..3b4a7f36d0 100644
--- a/usr/src/uts/common/fs/proc/prsubr.c
+++ b/usr/src/uts/common/fs/proc/prsubr.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -1403,10 +1403,10 @@ prgetaction32(proc_t *p, user_t *up, uint_t sig, struct sigaction32 *sp)
/*
* Count the number of segments in this process's address space.
*/
-int
+uint_t
prnsegs(struct as *as, int reserved)
{
- int n = 0;
+ uint_t n = 0;
struct seg *seg;
ASSERT(as != &kas && AS_WRITE_HELD(as));
@@ -1423,8 +1423,21 @@ prnsegs(struct as *as, int reserved)
for (saddr = seg->s_base; saddr < eaddr; saddr = naddr) {
(void) pr_getprot(seg, reserved, &tmp,
&saddr, &naddr, eaddr);
- if (saddr != naddr)
+ if (saddr != naddr) {
n++;
+ /*
+ * prnsegs() was formerly designated to return
+ * an 'int' despite having no ability or use
+ * for negative results. As part of changing
+ * it to 'uint_t', keep the old effective limit
+ * of INT_MAX in place.
+ */
+ if (n == INT_MAX) {
+ pr_getprot_done(&tmp);
+ ASSERT(tmp == NULL);
+ return (n);
+ }
+ }
}
ASSERT(tmp == NULL);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple
new file mode 100644
index 0000000000..a42fec94d8
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2001 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip
new file mode 100644
index 0000000000..96b9771514
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.apple.descrip
@@ -0,0 +1 @@
+PORTIONS OF NSMB DRIVER IN SMB CLIENT
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov
new file mode 100644
index 0000000000..583923c355
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov
@@ -0,0 +1,29 @@
+ Copyright (c) 2000, 2001 Boris Popov
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Boris Popov.
+ 4. Neither the name of the author nor the names of any co-contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip
new file mode 100644
index 0000000000..96b9771514
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/THIRDPARTYLICENSE.boris_popov.descrip
@@ -0,0 +1 @@
+PORTIONS OF NSMB DRIVER IN SMB CLIENT
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
new file mode 100644
index 0000000000..2be033a8fc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb_sign_kcf.c
@@ -0,0 +1,180 @@
+/*
+ * 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 the
+ * Kernel Cryptographic Framework (KCF)
+ *
+ * There are two implementations of these functions:
+ * This one (for kernel) and another for user space:
+ * See: lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
+ */
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#include <sys/crypto/api.h>
+#include <netsmb/smb_signing.h>
+
+/*
+ * SMB1 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb_md5_getmech(smb_sign_mech_t *mech)
+{
+ crypto_mech_type_t t;
+
+ t = crypto_mech2id(SUN_CKM_MD5);
+ if (t == CRYPTO_MECH_INVALID)
+ return (-1);
+ mech->cm_type = t;
+ return (0);
+}
+
+/*
+ * Start the KCF session, load the key
+ */
+int
+smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
+{
+ int rv;
+
+ rv = crypto_digest_init(mech, ctxp, NULL);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
+{
+ crypto_data_t data;
+ int rv;
+
+ bzero(&data, sizeof (data));
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_length = len;
+ data.cd_raw.iov_base = buf;
+ data.cd_raw.iov_len = len;
+
+ rv = crypto_digest_update(ctx, &data, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Get the final digest.
+ */
+int
+smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
+{
+ crypto_data_t out;
+ int rv;
+
+ bzero(&out, sizeof (out));
+ out.cd_format = CRYPTO_DATA_RAW;
+ out.cd_length = MD5_DIGEST_LENGTH;
+ out.cd_raw.iov_len = MD5_DIGEST_LENGTH;
+ out.cd_raw.iov_base = (void *)digest16;
+
+ rv = crypto_digest_final(ctx, &out, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * SMB2 signing helpers:
+ * (getmech, init, update, final)
+ */
+
+int
+smb2_hmac_getmech(smb_sign_mech_t *mech)
+{
+ crypto_mech_type_t t;
+
+ t = crypto_mech2id(SUN_CKM_SHA256_HMAC);
+ if (t == CRYPTO_MECH_INVALID)
+ return (-1);
+ mech->cm_type = t;
+ return (0);
+}
+
+/*
+ * Start the KCF 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)
+{
+ crypto_key_t ckey;
+ int rv;
+
+ bzero(&ckey, sizeof (ckey));
+ ckey.ck_format = CRYPTO_KEY_RAW;
+ ckey.ck_data = key;
+ ckey.ck_length = key_len * 8; /* in bits */
+
+ rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
+
+/*
+ * Digest one segment
+ */
+int
+smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
+{
+ crypto_data_t data;
+ int rv;
+
+ bzero(&data, sizeof (data));
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_length = len;
+ data.cd_raw.iov_base = (void *)in;
+ data.cd_raw.iov_len = len;
+
+ rv = crypto_mac_update(ctx, &data, 0);
+
+ return (rv == CRYPTO_SUCCESS ? 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];
+ crypto_data_t out;
+ int rv;
+
+ bzero(&out, sizeof (out));
+ out.cd_format = CRYPTO_DATA_RAW;
+ out.cd_length = SHA256_DIGEST_LENGTH;
+ out.cd_raw.iov_len = SHA256_DIGEST_LENGTH;
+ out.cd_raw.iov_base = (void *)full_digest;
+
+ rv = crypto_mac_final(ctx, &out, 0);
+ if (rv == CRYPTO_SUCCESS)
+ bcopy(full_digest, digest16, 16);
+
+ return (rv == CRYPTO_SUCCESS ? 0 : -1);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
index 993bdd61a8..a78b08bba0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in
@@ -20,7 +20,7 @@
\
\
-\ Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+\ Copyright 2018 Nexenta Systems, Inc. All rights reserved.
\ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
\ Use is subject to license terms.
\
@@ -52,8 +52,10 @@ smbioc_ssn_ident
id_user
smbioc_ossn
- ssn_vopt
ssn_owner
+ ssn_vopt
+ ssn_minver
+ ssn_maxver
ssn_id
ssn_srvname
@@ -68,77 +70,30 @@ smbioc_tcon
tc_opt
tc_sh
-smb_sopt
- sv_proto
- sv_sm
- sv_tz
- sv_maxmux
- sv_maxvcs
- sv_rawmode
- sv_maxtx
- sv_maxraw
- sv_skey
- sv_caps
-
-smb_iods
- is_tran_fd
- is_vcflags
- is_hflags
- is_hflags2
- is_smbuid
- is_next_mid
- is_txmax
- is_rwmax
- is_rxmax
- is_wxmax
- is_ssn_key
- is_next_seq
- is_u_maclen
- is_u_mackey
-
smbioc_ssn_work
- wk_iods
- wk_sopt
wk_out_state
-
-smbioc_rq SIZEOF_SMBIOC_RQ
- ioc_cmd
- ioc_errclass IOC_RQ_ERRCLASS
- ioc_serror IOC_RQ_SERROR
- ioc_error IOC_RQ_ERROR
- ioc_tbufsz
- ioc_rbufsz
- _ioc_tbuf
- _ioc_rbuf
-
-smbioc_t2rq SIZEOF_SMBIOC_T2RQ
- ioc_setup
- ioc_setupcnt
- ioc_name IOC_T2_NAME
- ioc_tparamcnt
- ioc_tdatacnt
- ioc_rparamcnt
- ioc_rdatacnt
- ioc_errclass IOC_T2_ERRCLASS
- ioc_serror IOC_T2_SERROR
- ioc_error IOC_T2_ERROR
- ioc_rpflags2
- _ioc_tparam
- _ioc_tdata
- _ioc_rparam
- _ioc_rdata
-
-smbioc_flags SIZEOF_SMBIOC_FLAGS
- ioc_level
- ioc_mask
- ioc_flags
+ wk_u_ssnkey_len
+ wk_u_ssnkey_buf
+ wk_u_auth_rlen
+ wk_u_auth_wlen
+ wk_u_auth_rbuf
+ wk_u_auth_wbuf
+ wk_cl_guid
smbioc_rw SIZEOF_SMBIOC_RW
- ioc_fh
ioc_cnt
+ ioc_flags
_ioc_offset
_ioc_base
+smbioc_xnp SIZEOF_SMBIOC_XNP
+ ioc_tdlen
+ ioc_rdlen
+ ioc_more
+ ioc_pad1
+ _ioc_tdata
+ _ioc_rdata
+
smbioc_ntcreate SIZEOF_NTCREATE
ioc_req_acc
ioc_efattr
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c
new file mode 100644
index 0000000000..44041ad975
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/atomic.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+static const uint8_t SMB2_SIGNATURE[4] = SMB2_PROTOCOL_ID;
+
+static int smb2_rq_enqueue(struct smb_rq *rqp);
+static int smb2_rq_reply(struct smb_rq *rqp);
+
+/*
+ * Given a request with it's body already composed,
+ * rewind to the start and fill in the SMB2 header.
+ * This is called when the request is enqueued,
+ * so we have the final message ID etc.
+ */
+void
+smb2_rq_fillhdr(struct smb_rq *rqp)
+{
+ struct mbchain mbtmp, *mbp = &mbtmp;
+ uint16_t creditcharge, creditrequest;
+ size_t len;
+ mblk_t *m;
+
+ ASSERT((rqp->sr2_nextcmd & 7) == 0);
+ if (rqp->sr2_nextcmd != 0) {
+ len = msgdsize(rqp->sr_rq.mb_top);
+ ASSERT((len & 7) == 0);
+ }
+
+ /*
+ * When sending negotiate, we don't technically know yet
+ * if the server handles SMB 2.1 or later and credits.
+ * Negotiate is supposed to set these to zero.
+ */
+ if (rqp->sr2_command == SMB2_NEGOTIATE) {
+ creditcharge = creditrequest = 0;
+ } else {
+ creditcharge = rqp->sr2_creditcharge;
+ creditrequest = rqp->sr2_creditsrequested;
+ }
+
+ /*
+ * Fill in the SMB2 header using a dup of the first mblk,
+ * which points at the same data but has its own wptr,
+ * so we can rewind without trashing the message.
+ */
+ m = dupb(rqp->sr_rq.mb_top);
+ m->b_wptr = m->b_rptr; /* rewind */
+ mb_initm(mbp, m);
+
+ mb_put_mem(mbp, SMB2_SIGNATURE, 4, MB_MSYSTEM);
+ mb_put_uint16le(mbp, SMB2_HDR_SIZE); /* Struct Size */
+ mb_put_uint16le(mbp, creditcharge);
+ mb_put_uint32le(mbp, 0); /* Status */
+ mb_put_uint16le(mbp, rqp->sr2_command);
+ mb_put_uint16le(mbp, creditrequest);
+ mb_put_uint32le(mbp, rqp->sr2_rqflags);
+ mb_put_uint32le(mbp, rqp->sr2_nextcmd);
+ mb_put_uint64le(mbp, rqp->sr2_messageid);
+
+ mb_put_uint32le(mbp, rqp->sr_pid); /* Process ID */
+ mb_put_uint32le(mbp, rqp->sr2_rqtreeid); /* Tree ID */
+ mb_put_uint64le(mbp, rqp->sr2_rqsessionid); /* Session ID */
+ /* The MAC signature is filled in by smb2_vc_sign() */
+
+ /* This will free the mblk from dupb. */
+ mb_done(mbp);
+}
+
+int
+smb2_rq_simple(struct smb_rq *rqp)
+{
+ return (smb2_rq_simple_timed(rqp, smb2_timo_default));
+}
+
+/*
+ * Simple request-reply exchange
+ */
+int
+smb2_rq_simple_timed(struct smb_rq *rqp, int timeout)
+{
+ int error;
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ error = smb2_rq_enqueue(rqp);
+ if (error == 0)
+ error = smb2_rq_reply(rqp);
+
+ return (error);
+}
+
+
+static int
+smb2_rq_enqueue(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_share *ssp = rqp->sr_share;
+ int error = 0;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ /*
+ * Normal requests may initiate a reconnect,
+ * and/or wait for state changes to finish.
+ * Some requests set the NORECONNECT flag
+ * to avoid all that (i.e. tree discon)
+ */
+ if (rqp->sr_flags & SMBR_NORECONNECT) {
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
+ return (ENOTCONN);
+ }
+ if (ssp != NULL &&
+ ((ssp->ss_flags & SMBS_CONNECTED) == 0))
+ return (ENOTCONN);
+ goto ok_out;
+ }
+
+ /*
+ * If we're not connected, initiate a reconnect
+ * and/or wait for an existing one to finish.
+ */
+ if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ error = smb_iod_reconnect(vcp);
+ if (error != 0)
+ return (error);
+ }
+
+ /*
+ * If this request has a "share" object
+ * that needs a tree connect, do it now.
+ */
+ if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) {
+ error = smb_share_tcon(ssp, rqp->sr_cred);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * We now know what UID + TID to use.
+ * Store them in the request.
+ */
+ok_out:
+ rqp->sr2_rqsessionid = vcp->vc2_session_id;
+ rqp->sr2_rqtreeid = ssp ? ssp->ss2_tree_id : SMB2_TID_UNKNOWN;
+ error = smb2_iod_addrq(rqp);
+
+ return (error);
+}
+
+/*
+ * Used by the IOD thread during connection setup,
+ * and for smb2_echo after network timeouts. Note that
+ * unlike smb2_rq_simple, callers must check sr_error.
+ */
+int
+smb2_rq_internal(struct smb_rq *rqp, int timeout)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int error;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ /*
+ * In-line smb2_rq_enqueue(rqp) here, as we don't want it
+ * trying to reconnect etc. for an internal request.
+ */
+ rqp->sr2_rqsessionid = vcp->vc2_session_id;
+ rqp->sr2_rqtreeid = SMB2_TID_UNKNOWN;
+ rqp->sr_flags |= SMBR_INTERNAL;
+ error = smb2_iod_addrq(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * In-line a variant of smb2_rq_reply(rqp) here as we may
+ * need to do custom parsing for SMB1-to-SMB2 negotiate.
+ */
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq_int(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ error = smb2_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB2 header.
+ */
+ error = smb2_rq_parsehdr(rqp);
+
+ /*
+ * Skip the error translation smb2_rq_reply does.
+ * Callers of this expect "raw" NT status.
+ */
+
+ return (error);
+}
+
+/*
+ * Wait for a reply to this request, then parse it.
+ */
+static int
+smb2_rq_reply(struct smb_rq *rqp)
+{
+ int error;
+
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ error = smb2_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB2 header
+ */
+ error = smb2_rq_parsehdr(rqp);
+ if (error != 0)
+ return (error);
+
+ if (rqp->sr_error != 0) {
+ error = smb_maperr32(rqp->sr_error);
+ }
+
+ if (error != 0) {
+ /*
+ * Do a special check for STATUS_BUFFER_OVERFLOW;
+ * it's not an error.
+ */
+ if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) {
+ /*
+ * Don't report it as an error to our caller;
+ * they can look at rqp->sr_error if they
+ * need to know whether we got a
+ * STATUS_BUFFER_OVERFLOW.
+ */
+ rqp->sr_flags |= SMBR_MOREDATA;
+ error = 0;
+ }
+ } else {
+ rqp->sr_flags &= ~SMBR_MOREDATA;
+ }
+
+ return (error);
+}
+
+/*
+ * Parse the SMB 2+ Header
+ */
+int
+smb2_rq_parsehdr(struct smb_rq *rqp)
+{
+ struct mdchain *mdp = &rqp->sr_rp;
+ uint32_t protocol_id;
+ uint16_t length = 0;
+ uint16_t credit_charge;
+ uint16_t command;
+ uint64_t message_id = 0;
+ int error = 0;
+
+ /* Get Protocol ID */
+ md_get_uint32le(mdp, &protocol_id);
+
+ /* Get/Check structure size is 64 */
+ md_get_uint16le(mdp, &length);
+ if (length != 64)
+ return (EBADRPC);
+
+ md_get_uint16le(mdp, &credit_charge);
+ md_get_uint32le(mdp, &rqp->sr_error);
+ md_get_uint16le(mdp, &command);
+ md_get_uint16le(mdp, &rqp->sr2_rspcreditsgranted);
+ md_get_uint32le(mdp, &rqp->sr2_rspflags);
+ md_get_uint32le(mdp, &rqp->sr2_rspnextcmd);
+ md_get_uint64le(mdp, &message_id);
+
+ if ((rqp->sr2_rspflags & SMB2_FLAGS_ASYNC_COMMAND) == 0) {
+ /*
+ * Sync Header
+ */
+
+ /* Get Process ID */
+ md_get_uint32le(mdp, &rqp->sr2_rsppid);
+
+ /* Get Tree ID */
+ md_get_uint32le(mdp, &rqp->sr2_rsptreeid);
+ } else {
+ /*
+ * Async Header
+ */
+
+ /* Get Async ID */
+ md_get_uint64le(mdp, &rqp->sr2_rspasyncid);
+ }
+
+ /* Get Session ID */
+ error = md_get_uint64le(mdp, &rqp->sr2_rspsessionid);
+ if (error)
+ return (error);
+
+ /* Skip MAC Signature */
+ error = md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h
new file mode 100644
index 0000000000..812c679b2f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _NETSMB_SMB2_RQ_H_
+#define _NETSMB_SMB2_RQ_H_
+
+#include <sys/types.h>
+
+/*
+ * Note: Pad all structures to 8 byte boundaries
+ */
+
+int smb2_rq_parsehdr(struct smb_rq *rqp);
+void smb2_rq_fillhdr(struct smb_rq *rqp);
+
+int smb2_rq_simple(struct smb_rq *rqp);
+int smb2_rq_simple_timed(struct smb_rq *rqp, int timeout);
+int smb2_rq_internal(struct smb_rq *rqp, int timeout);
+
+#endif /* _NETSMB_SMB2_RQ_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
new file mode 100644
index 0000000000..46bf28c370
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c
@@ -0,0 +1,253 @@
+/*
+ * 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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * Support for SMB2 "signing" (message integrity)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/md4.h>
+#include <sys/md5.h>
+#include <sys/des.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_signing.h>
+
+#define SMB2_SIG_OFF 48
+#define SMB2_SIG_LEN 16
+
+/*
+ * smb2_sign_init
+ *
+ * Get the mechanism info and initilize SMB2 signing.
+ */
+int
+smb2_sign_init(smb_vc_t *vcp)
+{
+ uint_t copysize;
+ int rc;
+
+ ASSERT(vcp->vc_ssnkey != NULL);
+ ASSERT(vcp->vc_mackey == NULL);
+
+ rc = smb2_hmac_getmech(&vcp->vc_signmech);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "smb2 can't get signing mechanism");
+ return (EAUTH);
+ }
+
+ /*
+ * Convert the session key to the MAC key.
+ *
+ * For SMB2, the signing key is just the first 16 bytes
+ * of the session key (truncated or padded with zeros).
+ * [MS-SMB2] 3.2.5.3.1
+ *
+ * SMB3 would do KDF here.
+ */
+ vcp->vc_mackeylen = SMB2_SIG_LEN;
+ vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+ copysize = vcp->vc_ssnkeylen;
+ if (copysize > vcp->vc_mackeylen)
+ copysize = vcp->vc_mackeylen;
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize);
+
+ return (0);
+}
+
+
+/*
+ * Compute MAC signature of packet data, using the stored MAC key.
+ *
+ * The signature is in the last 16 bytes of the SMB2 header.
+ * The signature algorighm is to compute HMAC SHA256 over the
+ * entire command, with the signature field set to zeros.
+ *
+ * See similar code for the server side:
+ * uts/common/fs/smbsrv/smb2_signing.c : smb2_sign_calc
+ */
+static int
+smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
+{
+ uint8_t tmp_hdr[SMB2_HDR_SIZE];
+ smb_sign_ctx_t ctx = 0;
+ mblk_t *m = mp;
+ int size;
+ int rc;
+
+ if (vcp->vc_mackey == NULL)
+ return (-1);
+
+ rc = smb2_hmac_init(&ctx, &vcp->vc_signmech,
+ vcp->vc_mackey, vcp->vc_mackeylen);
+ if (rc != 0)
+ return (rc);
+
+ /* Our caller should ensure mp has a contiguous header */
+ ASSERT(m != NULL);
+ ASSERT(MBLKL(m) >= SMB2_HDRLEN);
+
+ /*
+ * Copy of the SMB2 header, zero out the signature, and digest.
+ */
+ size = SMB2_HDRLEN;
+ bcopy(m->b_rptr, tmp_hdr, size);
+ bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN);
+ rc = smb2_hmac_update(ctx, tmp_hdr, size);
+ if (rc != 0)
+ return (rc);
+
+ /*
+ * Digest the rest of the SMB2 header packet, starting at
+ * the data just after the SMB2 header.
+ */
+ size = MBLKL(m) - SMB2_HDRLEN;
+ rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size);
+ if (rc != 0)
+ return (rc);
+ m = m->b_cont;
+
+ /* Digest rest of the SMB2 message. */
+ while (m != NULL) {
+ size = MBLKL(m);
+ if (size > 0) {
+ rc = smb2_hmac_update(ctx, m->b_rptr, size);
+ if (rc != 0)
+ return (rc);
+ }
+ m = m->b_cont;
+ }
+ rc = smb2_hmac_final(ctx, signature);
+
+ return (rc);
+}
+
+/*
+ * Sign a request with HMAC-MD5.
+ */
+void
+smb2_rq_sign(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rq.mb_top;
+ uint8_t *sigloc;
+ int rc;
+
+ /*
+ * smb_rq_new() ensures this,
+ * but just in case..
+ */
+ ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
+ sigloc = mp->b_rptr + SMB2_SIG_OFF;
+
+ if (vcp->vc_mackey == NULL)
+ return;
+
+ /*
+ * This will compute the MAC and store it
+ * directly into the message at sigloc.
+ */
+ rc = smb2_compute_MAC(vcp, mp, sigloc);
+ if (rc != 0) {
+ SMBSDEBUG("Crypto error %d", rc);
+ bzero(sigloc, SMB2_SIG_LEN);
+ }
+}
+
+/*
+ * Verify reply signature.
+ */
+int
+smb2_rq_verify(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *mp = rqp->sr_rp.md_top;
+ uint8_t sigbuf[SMB2_SIG_LEN];
+ uint8_t *sigloc;
+ int rc;
+
+ /*
+ * Note vc_mackey and vc_mackeylen gets filled in by
+ * smb_usr_iod_work as the connection comes in.
+ */
+ if (vcp->vc_mackey == NULL) {
+ SMBSDEBUG("no mac key\n");
+ return (0);
+ }
+
+ /*
+ * Let caller deal with empty reply or short messages by
+ * returning zero. Caller will fail later, in parsing.
+ */
+ if (mp == NULL) {
+ SMBSDEBUG("empty reply\n");
+ return (0);
+ }
+
+ /* smb2_iod_process ensures this */
+ ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
+ sigloc = mp->b_rptr + SMB2_SIG_OFF;
+
+ /*
+ * Compute the expected signature in sigbuf.
+ */
+ rc = smb2_compute_MAC(vcp, mp, sigbuf);
+ if (rc != 0) {
+ SMBSDEBUG("Crypto error %d", rc);
+ /*
+ * If we can't compute a MAC, then there's
+ * no point trying other seqno values.
+ */
+ return (EBADRPC);
+ }
+
+ /*
+ * Compare the computed signature with the
+ * one found in the message (at sigloc)
+ */
+ if (bcmp(sigbuf, sigloc, SMB2_SIG_LEN) == 0)
+ return (0);
+
+ SMBERROR("BAD signature, Server=%s MID=0x%llx\n",
+ vcp->vc_srvname, (long long)rqp->sr2_messageid);
+
+ return (EBADRPC);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
new file mode 100644
index 0000000000..c3df18faa9
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb2_smb.c
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/random.h>
+#include <sys/note.h>
+#include <sys/errno.h>
+#include <sys/cmn_err.h>
+
+#include <smb/ntaccess.h>
+#include <smb/winioctl.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+#define NDIALECTS 1
+static const uint16_t smb2_dialects[1] = {
+ SMB2_DIALECT_0210
+};
+
+/* Optional capabilities we advertise (none yet). */
+uint32_t smb2_clnt_caps = 0;
+
+/* How many credits to ask for during ssn. setup. */
+uint16_t smb2_ss_req_credits = 64;
+
+/*
+ * Default timeout values, all in seconds.
+ * Make these tunable (only via mdb for now).
+ */
+int smb2_timo_notice = 15;
+int smb2_timo_default = 30;
+int smb2_timo_logon = 45;
+int smb2_timo_open = 45;
+int smb2_timo_read = 45;
+int smb2_timo_write = 60;
+int smb2_timo_append = 90;
+
+/*
+ * This is a special handler for the odd SMB1-to-SMB2 negotiate
+ * response, where an SMB1 request gets an SMB2 response.
+ *
+ * Unlike most parse functions here, this needs to parse both
+ * the SMB2 header and the nego. response body. Note that
+ * the only "SMB2" dialect our SMB1 negotiate offered was
+ * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid
+ * SMB2 dialect we should get is: SMB2_DIALECT_02ff
+ */
+int
+smb2_parse_smb1nego_resp(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_sopt *sp = &vcp->vc_sopt;
+ struct mdchain *mdp;
+ uint16_t length = 0;
+ int error;
+
+ /* Get pointer to response data */
+ smb_rq_getreply(rqp, &mdp);
+
+ error = smb2_rq_parsehdr(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Parse SMB 2/3 Negotiate Response
+ * We are already pointing to begining of Response data
+ */
+
+ /* Check structure size is 65 */
+ md_get_uint16le(mdp, &length);
+ if (length != 65)
+ return (EBADRPC);
+
+ /* Get Security Mode */
+ md_get_uint16le(mdp, &sp->sv2_security_mode);
+
+ /* Get Dialect. */
+ error = md_get_uint16le(mdp, &sp->sv2_dialect);
+ if (error != 0)
+ return (error);
+
+ /* What dialect did we get? */
+ if (sp->sv2_dialect != SMB2_DIALECT_02ff) {
+ SMBERROR("Unknown dialect 0x%x\n", sp->sv2_dialect);
+ return (EINVAL);
+ }
+ /* Set our (internal) SMB1 dialect also. */
+ sp->sv_proto = SMB_DIALECT_SMB2_FF;
+
+ /*
+ * This request did not go through smb2_iod_addrq and
+ * smb2_iod_process() so the SMB2 message ID state is
+ * behind what we need it to be. Fix that.
+ */
+ vcp->vc2_next_message_id = 1;
+ vcp->vc2_limit_message_id = 2;
+
+ /*
+ * Skip parsing the rest. We'll get a normal
+ * SMB2 negotiate next and do negotiate then.
+ */
+ return (0);
+}
+
+int
+smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ smb_sopt_t *sp = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ uint16_t ndialects = NDIALECTS;
+ boolean_t will_sign = B_FALSE;
+ uint16_t length = 0;
+ uint16_t security_mode;
+ uint16_t sec_buf_off;
+ uint16_t sec_buf_len;
+ int err, i;
+
+ /*
+ * Compute security mode
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ } else {
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ }
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp);
+ if (err)
+ return (err);
+
+ /*
+ * Build the SMB2 negotiate request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 36); /* Struct Size */
+ mb_put_uint16le(mbp, ndialects); /* Dialect Count */
+ mb_put_uint16le(mbp, security_mode);
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, smb2_clnt_caps);
+ mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
+ mb_put_uint64le(mbp, 0); /* Start Time */
+ for (i = 0; i < ndialects; i++) { /* Dialects */
+ mb_put_uint16le(mbp, smb2_dialects[i]);
+ }
+
+ /*
+ * Do the OTW call.
+ */
+ err = smb2_rq_internal(rqp, smb2_timo_default);
+ if (err) {
+ goto errout;
+ }
+ /* Should only get status success. */
+ if (rqp->sr_error != NT_STATUS_SUCCESS) {
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Decode the negotiate response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ md_get_uint16le(mdp, &length); /* Struct size */
+ if (length != 65) {
+ err = EBADRPC;
+ goto errout;
+ }
+
+ md_get_uint16le(mdp, &sp->sv2_security_mode);
+ md_get_uint16le(mdp, &sp->sv2_dialect);
+ md_get_uint16le(mdp, NULL); /* reserved */
+ md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
+ md_get_uint32le(mdp, &sp->sv2_capabilities);
+ md_get_uint32le(mdp, &sp->sv2_maxtransact);
+ md_get_uint32le(mdp, &sp->sv2_maxread);
+ md_get_uint32le(mdp, &sp->sv2_maxwrite);
+ md_get_uint64le(mdp, NULL); /* curr_time */
+ md_get_uint64le(mdp, NULL); /* boot_time */
+
+ /* Get Security Blob offset and length */
+ md_get_uint16le(mdp, &sec_buf_off);
+ err = md_get_uint16le(mdp, &sec_buf_len);
+ if (err != 0)
+ goto errout;
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /*
+ * Security buffer offset is from the beginning of SMB 2 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 64
+ */
+ if (sec_buf_len != 0) {
+ int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64);
+ if (skip < 0) {
+ err = EBADRPC;
+ goto errout;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sec_buf_len) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = EMSGSIZE;
+ goto errout;
+ }
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
+ sec_buf_len, MB_MUSER);
+ if (err) {
+ goto errout;
+ }
+ }
+
+ /*
+ * Decoded everything. Now decisions.
+ */
+
+ /*
+ * Turn on signing if either Server or client requires it,
+ * except: anonymous sessions can't sign.
+ */
+ if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
+ (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED))
+ will_sign = B_TRUE;
+ if (vcp->vc_vopt & SMBVOPT_ANONYMOUS)
+ will_sign = B_FALSE;
+ SMBSDEBUG("Security signatures: %d", (int)will_sign);
+ if (will_sign)
+ vcp->vc_flags |= SMBV_SIGNING;
+
+ /*
+ * ToDo - too many places are looking at sv_caps, so for now
+ * set the SMB1 capabilities too. Later we should use the
+ * sv2_capabilities for SMB 2+.
+ */
+ sp->sv_caps = (SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_LARGE_READX |
+ SMB_CAP_LARGE_WRITEX |
+ SMB_CAP_EXT_SECURITY);
+ if (sp->sv2_capabilities & SMB2_CAP_DFS)
+ sp->sv_caps |= SMB_CAP_DFS;
+
+ /*
+ * A few sanity checks on what we received,
+ * becuse we will send these in ssnsetup.
+ *
+ * Maximum outstanding requests (we care),
+ * and Max. VCs (we only use one). Also,
+ * MaxBufferSize lower limit per spec.
+ */
+ if (sp->sv2_maxread < 0x8000) {
+ SMBSDEBUG("maxread too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+ if (sp->sv2_maxwrite < 0x8000) {
+ SMBSDEBUG("maxwrite too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+ if (sp->sv2_maxtransact < 0x4000) {
+ SMBSDEBUG("maxtransact too small\n");
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /* Here too, fill SMB1 fields */
+ vcp->vc_rxmax = sp->sv2_maxread;
+ vcp->vc_wxmax = sp->sv2_maxwrite;
+ vcp->vc_txmax = sp->sv2_maxtransact;
+
+ smb_rq_done(rqp);
+ return (0);
+
+errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+}
+
+int
+smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ // smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ char *sb;
+ int err, ret;
+ uint16_t sblen;
+ uint16_t length = 0;
+ uint16_t session_flags;
+ uint16_t sec_buf_off;
+ uint16_t sec_buf_len;
+ uint8_t security_mode;
+
+ /*
+ * Compute security mode
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ } else {
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ }
+
+ sb = wk->wk_u_auth_wbuf.lp_ptr;
+ sblen = (uint16_t)wk->wk_u_auth_wlen;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Always ask for some credits. The server usually will
+ * only grant these credits once we've authenticated.
+ */
+ rqp->sr2_creditsrequested = smb2_ss_req_credits;
+
+ /*
+ * Build the SMB Session Setup request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+
+ mb_put_uint16le(mbp, 25); /* Struct size */
+ mb_put_uint8(mbp, 0); /* VcNumber */
+ mb_put_uint8(mbp, security_mode);
+ mb_put_uint32le(mbp, smb2_clnt_caps); /* Capabilities */
+ mb_put_uint32le(mbp, 0); /* Channel - always 0 */
+
+ /*
+ * Security buffer offset and length. Normally would use
+ * ptr = mb_reserve() and fill in later, but since only a
+ * small amount of fixed-size stuff follows (12 bytes)
+ * we can just compute the offset now.
+ */
+ mb_put_uint16le(mbp, mbp->mb_count + 12);
+ mb_put_uint16le(mbp, sblen);
+ mb_put_uint64le(mbp, vcp->vc2_prev_session_id);
+ err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Run the request. The return value here should be the
+ * return from this function, unless we fail decoding.
+ * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
+ * the caller expects EINPROGRESS for that case.
+ */
+ ret = smb2_rq_internal(rqp, smb2_timo_logon);
+ if (ret != 0)
+ goto out;
+ switch (rqp->sr_error) {
+ case NT_STATUS_SUCCESS:
+ break;
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ /* Keep going, but return... */
+ ret = EINPROGRESS;
+ break;
+ default:
+ ret = EAUTH;
+ goto out;
+ }
+
+ /*
+ * After the first Session Setup Response,
+ * save the session ID.
+ */
+ if (vcp->vc2_session_id == 0)
+ vcp->vc2_session_id = rqp->sr2_rspsessionid;
+
+ /*
+ * Decode the session setup response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ md_get_uint16le(mdp, &length); /* Struct size */
+ if (length != 9) {
+ ret = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint16le(mdp, &session_flags);
+ md_get_uint16le(mdp, &sec_buf_off);
+ err = md_get_uint16le(mdp, &sec_buf_len);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Security buffer offset is from the beginning of SMB 2 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 8
+ */
+ if (sec_buf_len != 0) {
+ int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ ret = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sec_buf_len) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sec_buf_len;
+ ret = EMSGSIZE;
+ goto out;
+ }
+ wk->wk_u_auth_rlen = sec_buf_len;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
+ sec_buf_len, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+ }
+
+out:
+ if (err != 0 && err != EINPROGRESS) {
+ /* Session ID no longer valid. */
+ vcp->vc2_session_id = 0;
+ }
+ if (rqp)
+ smb_rq_done(rqp);
+
+ return (ret);
+}
+
+int
+smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (vcp->vc2_session_id == 0)
+ return (0);
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Fill in Logoff part
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_internal(rqp, 5);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
+{
+ struct smb_vc *vcp;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ char *unc_name = NULL;
+ int error, unc_len;
+ uint16_t plen, *plenp;
+ uint16_t options = 0;
+ uint_t cnt0;
+ uint32_t net_stype;
+ uint16_t structure_size = 0;
+ uint8_t smb2stype;
+
+ vcp = SSTOVC(ssp);
+
+ /*
+ * Make this a "VC-level" request, so it will have
+ * rqp->sr_share == NULL, and smb_iod_sendrq()
+ * will send it with TID = SMB_TID_UNKNOWN
+ *
+ * This also serves to bypass the wait for
+ * share state changes, which this call is
+ * trying to carry out.
+ */
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the UNC name, i.e. "//server/share"
+ * but with backslashes of course.
+ * size math: three slashes, one null.
+ */
+ unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
+ unc_name = kmem_alloc(unc_len, KM_SLEEP);
+ (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
+ vcp->vc_srvname, ssp->ss_name);
+ SMBSDEBUG("unc_name: \"%s\"", unc_name);
+
+ /*
+ * Build the request.
+ */
+ mbp = &rqp->sr_rq;
+
+ mb_put_uint16le(mbp, 9); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint16le(mbp, 72); /* Path Offset */
+
+ /*
+ * Fill in path length after we put the string, so we know
+ * the length after conversion from UTF-8 to UCS-2.
+ */
+ plenp = mb_reserve(mbp, 2);
+ cnt0 = mbp->mb_count;
+
+ /* UNC resource name (without the null) */
+ error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1,
+ SMB_CS_NONE, NULL);
+ if (error)
+ goto out;
+
+ /* Now go back and fill in the path length. */
+ plen = (uint16_t)(mbp->mb_count - cnt0);
+ *plenp = htoles(plen);
+
+ /*
+ * Run the request.
+ *
+ * Using NOINTR_RECV because we don't want to risk
+ * missing a successful tree connect response,
+ * which would "leak" Tree IDs.
+ */
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+ error = smb2_rq_simple(rqp);
+ SMBSDEBUG("%d\n", error);
+ if (error) {
+ /*
+ * If we get the server name wrong, i.e. due to
+ * mis-configured name services, this will be
+ * NT_STATUS_DUPLICATE_NAME. Log this error.
+ */
+ SMBERROR("(%s) failed, status=0x%x",
+ unc_name, rqp->sr_error);
+ goto out;
+ }
+
+ /*
+ * Parse the tree connect response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 16 */
+ md_get_uint16le(mdp, &structure_size);
+ if (structure_size != 16) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint8(mdp, &smb2stype);
+ md_get_uint8(mdp, NULL); /* reserved */
+ md_get_uint32le(mdp, &ssp->ss2_share_flags);
+ md_get_uint32le(mdp, &ssp->ss2_share_caps);
+ error = md_get_uint32le(mdp, NULL); /* maxAccessRights */
+ if (error)
+ goto out;
+
+ /*
+ * Convert SMB2 share type to NetShareEnum share type
+ */
+ switch (smb2stype) {
+ case SMB2_SHARE_TYPE_DISK:
+ net_stype = STYPE_DISKTREE;
+ break;
+ case SMB2_SHARE_TYPE_PIPE:
+ net_stype = STYPE_IPC;
+ break;
+ case SMB2_SHARE_TYPE_PRINT:
+ net_stype = STYPE_PRINTQ;
+ break;
+ default:
+ net_stype = STYPE_UNKNOWN;
+ break;
+ }
+ ssp->ss_type = net_stype;
+
+ /*
+ * Map SMB 2/3 capabilities to SMB 1 options,
+ * for common code that looks there.
+ */
+ if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS)
+ options |= SMB_SHARE_IS_IN_DFS;
+
+ /* Update share state */
+ SMB_SS_LOCK(ssp);
+ ssp->ss2_tree_id = rqp->sr2_rsptreeid;
+ ssp->ss_vcgenid = vcp->vc_genid;
+ ssp->ss_options = options;
+ ssp->ss_flags |= SMBS_CONNECTED;
+ SMB_SS_UNLOCK(ssp);
+
+out:
+ if (unc_name)
+ kmem_free(unc_name, unc_len);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
+{
+ struct smb_vc *vcp;
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (ssp->ss2_tree_id == SMB2_TID_UNKNOWN)
+ return (0);
+
+ /*
+ * Build this as a "VC-level" request, so it will
+ * avoid testing the _GONE flag on the share,
+ * which has already been set at this point.
+ * Add the share pointer "by hand" below, so
+ * smb_iod_sendrq will plug in the TID.
+ */
+ vcp = SSTOVC(ssp);
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_DISCONNECT, scred, &rqp);
+ if (error)
+ return (error);
+ rqp->sr_share = ssp; /* See "by hand" above. */
+
+ /*
+ * Fill in SMB2 Tree Disconnect part
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here, but we
+ * do need to make sure we send this out, or we could
+ * "leak" active tree IDs on interrupt or timeout.
+ * The NOINTR_SEND flag makes this request immune to
+ * interrupt or timeout until the send is done.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
+ error = smb2_rq_simple_timed(rqp, 5);
+
+ smb_rq_done(rqp);
+
+ /* Whether we get an error or not... */
+ ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
+
+ return (error);
+}
+
+/*
+ * Put the name, first skipping a leading slash.
+ */
+static int
+put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp)
+{
+ mblk_t *m;
+
+ if (name_mbp == NULL)
+ return (0);
+ m = name_mbp->mb_top;
+ if (m == NULL)
+ return (0);
+
+ /* Use a dup of the message to leave the passed one untouched. */
+ m = dupmsg(m);
+ if (m == NULL)
+ return (ENOSR);
+
+ if (MBLKL(m) >= 2 &&
+ m->b_rptr[0] == '\\' &&
+ m->b_rptr[1] == '\0')
+ m->b_rptr += 2;
+
+ return (mb_put_mbuf(mbp, m));
+}
+
+/*
+ * Modern create/open of file or directory.
+ *
+ * The passed name is a full path relative to the share root.
+ * Callers prepare paths with a leading slash (backslash)
+ * because that's what SMB1 expected. SMB2 does not allow the
+ * leading slash here. To make life simpler for callers skip a
+ * leading slash here. That allows callers use use common logic
+ * for building paths without needing to know if the connection
+ * is using SMB1 or SMB2 (just build paths with a leading slash).
+ */
+int
+smb2_smb_ntcreate(
+ struct smb_share *ssp,
+ struct mbchain *name_mb,
+ struct mbchain *cctx_in,
+ struct mdchain *cctx_out,
+ uint32_t cr_flags, /* create flags */
+ uint32_t req_acc, /* requested access */
+ uint32_t efa, /* ext. file attrs (DOS attr +) */
+ uint32_t share_acc,
+ uint32_t open_disp, /* open disposition */
+ uint32_t createopt, /* NTCREATEX_OPTIONS_ */
+ uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */
+ struct smb_cred *scrp,
+ smb2fid_t *fidp, /* returned FID */
+ uint32_t *cr_act_p, /* optional create action */
+ struct smbfattr *fap) /* optional attributes */
+{
+ struct smbfattr fa;
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t *name_offp;
+ uint16_t *name_lenp;
+ uint32_t *cctx_offp;
+ uint32_t *cctx_lenp;
+ uint32_t rcc_off, rcc_len;
+ smb2fid_t smb2_fid;
+ uint64_t llongint;
+ uint32_t longint, createact;
+ uint_t off, len;
+ int error;
+ uint16_t StructSize = 57; // [MS-SMB2]
+
+ bzero(&fa, sizeof (fa));
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Todo: Assemble creat contexts (if needed)
+ * into an mbchain.
+ */
+
+ /*
+ * Build the SMB 2/3 Create Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, StructSize);
+ mb_put_uint8(mbp, 0); /* Security flags */
+ mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE); /* Oplock level */
+ mb_put_uint32le(mbp, impersonate); /* Impersonation Level */
+ mb_put_uint64le(mbp, cr_flags);
+ mb_put_uint64le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, req_acc);
+ mb_put_uint32le(mbp, efa); /* File attributes */
+ mb_put_uint32le(mbp, share_acc); /* Share access */
+ mb_put_uint32le(mbp, open_disp); /* Create disposition */
+ mb_put_uint32le(mbp, createopt); /* Create options */
+
+ name_offp = mb_reserve(mbp, 2); /* Name offset */
+ name_lenp = mb_reserve(mbp, 2); /* Name len */
+
+ cctx_offp = mb_reserve(mbp, 4); /* Context offset */
+ cctx_lenp = mb_reserve(mbp, 4); /* Context len */
+
+ /*
+ * Put the file name, which is provided in an mbchain.
+ * If there's a leading slash, skip it (see above).
+ */
+ off = mbp->mb_count;
+ *name_offp = htoles((uint16_t)off);
+ error = put_name_skip_slash(mbp, name_mb);
+ if (error)
+ goto out;
+ len = mbp->mb_count - off;
+ *name_lenp = htoles((uint16_t)len);
+
+ /*
+ * Now the create contexts (if provided)
+ */
+ if (cctx_in != NULL) {
+ off = mbp->mb_count;
+ *cctx_offp = htolel((uint32_t)off);
+ mb_put_mbchain(mbp, cctx_in);
+ len = mbp->mb_count - off;
+ *cctx_lenp = htolel((uint32_t)len);
+ } else {
+ *cctx_offp = 0;
+ *cctx_lenp = 0;
+ }
+
+ /*
+ * If we didn't put any variable-sized data, we'll have
+ * put exactly 56 bytes of data, and we need to pad out
+ * this request to the 57 bytes StructSize indicated.
+ */
+ if (mbp->mb_count < (StructSize + SMB2_HDRLEN))
+ mb_put_uint8(mbp, 0);
+
+ /*
+ * Don't want to risk missing a successful
+ * open response, or we could "leak" FIDs.
+ */
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+ error = smb2_rq_simple_timed(rqp, smb2_timo_open);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2/3 Create Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 89 */
+ error = md_get_uint16le(mdp, &StructSize);
+ if (StructSize != 89) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint8(mdp, NULL); /* oplock lvl granted */
+ md_get_uint8(mdp, NULL); /* mbz */
+ md_get_uint32le(mdp, &createact); /* create_action */
+ md_get_uint64le(mdp, &llongint); /* creation time */
+ smb_time_NT2local(llongint, &fa.fa_createtime);
+ md_get_uint64le(mdp, &llongint); /* access time */
+ smb_time_NT2local(llongint, &fa.fa_atime);
+ md_get_uint64le(mdp, &llongint); /* write time */
+ smb_time_NT2local(llongint, &fa.fa_mtime);
+ md_get_uint64le(mdp, &llongint); /* change time */
+ smb_time_NT2local(llongint, &fa.fa_ctime);
+ md_get_uint64le(mdp, &llongint); /* allocation size */
+ fa.fa_allocsz = llongint;
+ md_get_uint64le(mdp, &llongint); /* EOF position */
+ fa.fa_size = llongint;
+ md_get_uint32le(mdp, &longint); /* attributes */
+ fa.fa_attr = longint;
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /* Get SMB 2/3 File ID and create user fid to return */
+ md_get_uint64le(mdp, &smb2_fid.fid_persistent);
+ error = md_get_uint64le(mdp, &smb2_fid.fid_volatile);
+ if (error)
+ goto out;
+
+ /* Get Context Offset */
+ error = md_get_uint32le(mdp, &rcc_off);
+ if (error)
+ goto out;
+ /* Get Context Length */
+ error = md_get_uint32le(mdp, &rcc_len);
+ if (error)
+ goto out;
+
+ /*
+ * If the caller wants the returned create contexts, parse.
+ * Context offset is from the beginning of SMB 2/3 Header
+ * Calculate how much further we have to go to get to it.
+ * Current offset is: SMB2_HDRLEN + 88
+ */
+ if (rcc_len != 0) {
+ int skip = (int)rcc_off - (SMB2_HDRLEN + 88);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ if (cctx_out != NULL) {
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, rcc_len, &m);
+ if (error)
+ goto out;
+ md_initm(cctx_out, m);
+ }
+ }
+
+out:
+ smb_rq_done(rqp);
+ if (error)
+ return (error);
+
+ *fidp = smb2_fid;
+ if (cr_act_p)
+ *cr_act_p = createact;
+ if (fap)
+ *fap = fa; /* struct copy */
+
+ return (0);
+}
+
+int
+smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2/3 Close Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 24); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Flags */
+ mb_put_uint32le(mbp, 0); /* Reserved */
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ /* Make sure we send, but only if already connected */
+ rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
+ error = smb2_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_ioctl(
+ struct smb_share *ssp,
+ smb2fid_t *fid,
+ struct mbchain *data_in,
+ struct mdchain *data_out,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t ctl_code,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t *data_in_offp;
+ uint32_t *data_in_lenp;
+ uint32_t data_out_off;
+ uint32_t data_out_len;
+ uint16_t length = 0;
+ uint_t off, len;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 IOCTL Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 57); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+ mb_put_uint32le(mbp, ctl_code);
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ data_in_offp = mb_reserve(mbp, 4);
+ data_in_lenp = mb_reserve(mbp, 4);
+ mb_put_uint32le(mbp, 0); /* Max input resp */
+
+ mb_put_uint32le(mbp, 0); /* Output offset */
+ mb_put_uint32le(mbp, 0); /* Output count */
+ mb_put_uint32le(mbp, *data_out_sz);
+
+ mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */
+ mb_put_uint32le(mbp, 0); /* Reserved2 */
+
+ /*
+ * Now data_in (if provided)
+ */
+ if (data_in != NULL) {
+ off = mbp->mb_count;
+ *data_in_offp = htolel((uint32_t)off);
+ mb_put_mbchain(mbp, data_in);
+ len = mbp->mb_count - off;
+ *data_in_lenp = htolel((uint32_t)len);
+ } else {
+ *data_in_offp = 0;
+ *data_in_lenp = 0;
+ }
+
+ /*
+ * Run the request
+ */
+ error = smb2_rq_simple_timed(rqp, smb2_timo_default);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2 Ioctl Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 49 */
+ md_get_uint16le(mdp, &length);
+ if (length != 49) {
+ error = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* reserved */
+ md_get_uint32le(mdp, NULL); /* Get CtlCode */
+ md_get_uint64le(mdp, NULL); /* fid_persistent */
+ md_get_uint64le(mdp, NULL); /* fid_volatile */
+ md_get_uint32le(mdp, NULL); /* Get Input offset */
+ md_get_uint32le(mdp, NULL); /* Get Input count */
+
+ error = md_get_uint32le(mdp, &data_out_off);
+ if (error)
+ goto out;
+ error = md_get_uint32le(mdp, &data_out_len);
+ if (error)
+ goto out;
+
+ md_get_uint32le(mdp, NULL); /* Flags */
+ md_get_uint32le(mdp, NULL); /* reserved */
+
+ /*
+ * If the caller wants the ioctl output data, parse.
+ * Current offset is: SMB2_HDRLEN + 48
+ * Always return the received length.
+ */
+ *data_out_sz = data_out_len;
+ if (data_out_len != 0) {
+ int skip = (int)data_out_off - (SMB2_HDRLEN + 48);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ if (data_out != NULL) {
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, data_out_len, &m);
+ if (error)
+ goto out;
+ md_initm(data_out, m);
+ }
+ }
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+int
+smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+ uint64_t off64 = uiop->uio_loffset;
+ uint32_t rlen;
+ uint16_t length = 0;
+ uint8_t data_offset;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Read Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 49); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Padding and Reserved */
+
+ mb_put_uint32le(mbp, *lenp); /* Length of read */
+ mb_put_uint64le(mbp, off64); /* Offset */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint32le(mbp, 1); /* MinCount */
+ /* (only indicates blocking) */
+
+ mb_put_uint32le(mbp, 0); /* Channel */
+ mb_put_uint32le(mbp, 0); /* Remaining */
+ mb_put_uint32le(mbp, 0); /* Channel offset/len */
+ mb_put_uint8(mbp, 0); /* data "blob" (pad) */
+
+ if (timo == 0)
+ timo = smb2_timo_read;
+ error = smb2_rq_simple_timed(rqp, timo);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2 Read Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 17 */
+ md_get_uint16le(mdp, &length);
+ if (length != 17) {
+ error = EBADRPC;
+ goto out;
+ }
+ md_get_uint8(mdp, &data_offset);
+ md_get_uint8(mdp, NULL); /* reserved */
+
+ /* Get Data Length read */
+ error = md_get_uint32le(mdp, &rlen);
+ if (error)
+ goto out;
+
+ md_get_uint32le(mdp, NULL); /* Data Remaining (always 0) */
+ md_get_uint32le(mdp, NULL); /* Get Reserved2 (always 0) */
+
+ /*
+ * Data offset is from the beginning of SMB 2/3 Header
+ * Calculate how much further we have to go to get to it.
+ */
+ if (data_offset < (SMB2_HDRLEN + 16)) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (data_offset > (SMB2_HDRLEN + 16)) {
+ int skip = data_offset - (SMB2_HDRLEN + 16);
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+
+ /*
+ * Get the data
+ */
+ if (rlen == 0) {
+ *lenp = rlen;
+ goto out;
+ }
+ /* paranoid */
+ if (rlen > *lenp) {
+ SMBSDEBUG("bad server! rlen %d, len %d\n",
+ rlen, *lenp);
+ rlen = *lenp;
+ }
+
+ error = md_get_uio(mdp, uiop, rlen);
+ if (error)
+ goto out;
+
+ /* Success */
+ *lenp = rlen;
+
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+int
+smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+ uint64_t off64 = uiop->uio_loffset;
+ uint32_t rlen;
+ uint16_t data_offset;
+ uint16_t length = 0;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Write Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 49); /* Struct size */
+ data_offset = SMB2_HDRLEN + 48;
+ mb_put_uint16le(mbp, data_offset); /* Data Offset */
+ mb_put_uint32le(mbp, *lenp); /* Length of write */
+ mb_put_uint64le(mbp, off64); /* Offset */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint32le(mbp, 0); /* Channel */
+ mb_put_uint32le(mbp, 0); /* Remaining */
+ mb_put_uint32le(mbp, 0); /* Channel offset/len */
+ mb_put_uint32le(mbp, 0); /* Write flags */
+
+ error = mb_put_uio(mbp, uiop, *lenp);
+ if (error)
+ goto out;
+
+ if (timo == 0)
+ timo = smb2_timo_write;
+ error = smb2_rq_simple_timed(rqp, timo);
+ if (error)
+ goto out;
+
+ /*
+ * Parse SMB 2/3 Write Response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 17 */
+ md_get_uint16le(mdp, &length);
+ if (length != 17) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ md_get_uint16le(mdp, NULL); /* Get Reserved */
+
+ /* Get Data Length written */
+ error = md_get_uint32le(mdp, &rlen);
+ if (error)
+ goto out;
+
+ /* Get Data Remaining (always 0) */
+ md_get_uint32le(mdp, NULL);
+
+ /* Get Reserved2 (always 0) */
+ md_get_uint32le(mdp, NULL);
+
+ /* Success */
+ *lenp = rlen;
+
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*
+ * Note: the IOD calls this, so this request must not wait for
+ * connection state changes, etc. (uses smb2_rq_internal)
+ */
+int
+smb2_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB2_ECHO, scred, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Echo Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 4); /* Struct size */
+ mb_put_uint16le(mbp, 0); /* Reserved */
+
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_internal(rqp, timo);
+
+ smb_rq_done(rqp);
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
index d1e7efd60a..398be59709 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
@@ -34,6 +34,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -61,6 +63,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
@@ -80,6 +83,9 @@ static void smb_vc_gone(struct smb_connobj *cp);
static void smb_share_free(struct smb_connobj *cp);
static void smb_share_gone(struct smb_connobj *cp);
+static void smb_fh_free(struct smb_connobj *cp);
+static void smb_fh_gone(struct smb_connobj *cp);
+
int
smb_sm_init(void)
{
@@ -105,7 +111,7 @@ void
smb_sm_done(void)
{
/*
- * XXX Q4BP why are we not iterating on smb_vclist here?
+ * Why are we not iterating on smb_vclist here?
* Because the caller has just called smb_sm_idle() to
* make sure we have no VCs before calling this.
*/
@@ -181,6 +187,16 @@ smb_co_rele(struct smb_connobj *co)
int old_flags;
SMB_CO_LOCK(co);
+
+ /*
+ * When VC usecount goes from 2 to 1, signal the iod_idle CV.
+ * It's unfortunate to have object type-specific logic here,
+ * but it's hard to do this anywhere else.
+ */
+ if (co->co_level == SMBL_VC && co->co_usecount == 2) {
+ smb_vc_t *vcp = CPTOVC(co);
+ cv_signal(&vcp->iod_idle);
+ }
if (co->co_usecount > 1) {
co->co_usecount--;
SMB_CO_UNLOCK(co);
@@ -365,10 +381,12 @@ smb_vc_free(struct smb_connobj *cp)
if (vcp->vc_mackey != NULL)
kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ if (vcp->vc_ssnkey != NULL)
+ kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ cv_destroy(&vcp->iod_muxwait);
cv_destroy(&vcp->iod_idle);
rw_destroy(&vcp->iod_rqlock);
- sema_destroy(&vcp->vc_sendlock);
cv_destroy(&vcp->vc_statechg);
smb_co_done(VCTOCP(vcp));
kmem_free(vcp, sizeof (*vcp));
@@ -392,14 +410,15 @@ smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
vcp->vc_co.co_gone = smb_vc_gone;
cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
- sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
+ cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
/* Expanded TAILQ_HEAD_INITIALIZER */
vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
- vcp->vc_state = SMBIOD_ST_IDLE;
+ /* A brand new VC should connect. */
+ vcp->vc_state = SMBIOD_ST_RECONNECT;
/*
* These identify the connection.
@@ -612,10 +631,14 @@ smb_share_gone(struct smb_connobj *cp)
{
struct smb_cred scred;
struct smb_share *ssp = CPTOSS(cp);
+ smb_vc_t *vcp = SSTOVC(ssp);
smb_credinit(&scred, NULL);
smb_iod_shutdown_share(ssp);
- (void) smb_smb_treedisconnect(ssp, &scred);
+ if (vcp->vc_flags & SMBV_SMB2)
+ (void) smb2_smb_treedisconnect(ssp, &scred);
+ else
+ (void) smb_smb_treedisconnect(ssp, &scred);
smb_credrele(&scred);
}
@@ -655,6 +678,7 @@ smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
ssp->ss_tid = SMB_TID_UNKNOWN;
+ ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
bcopy(&tcon->tc_sh, &ssp->ss_ioc,
sizeof (smbioc_oshare_t));
@@ -770,6 +794,7 @@ smb_share_invalidate(struct smb_share *ssp)
int
smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
{
+ smb_vc_t *vcp = SSTOVC(ssp);
clock_t tmo;
int error;
@@ -813,7 +838,10 @@ smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
* and ss_flags |= SMBS_CONNECTED;
*/
SMB_SS_UNLOCK(ssp);
- error = smb_smb_treeconnect(ssp, scred);
+ if (vcp->vc_flags & SMBV_SMB2)
+ error = smb2_smb_treeconnect(ssp, scred);
+ else
+ error = smb_smb_treeconnect(ssp, scred);
SMB_SS_LOCK(ssp);
ssp->ss_flags &= ~SMBS_RECONNECTING;
@@ -829,6 +857,114 @@ out:
}
/*
+ * File handle level functions
+ */
+
+void
+smb_fh_hold(struct smb_fh *fhp)
+{
+ smb_co_hold(FHTOCP(fhp));
+}
+
+void
+smb_fh_rele(struct smb_fh *fhp)
+{
+ smb_co_rele(FHTOCP(fhp));
+}
+
+void
+smb_fh_close(struct smb_fh *fhp)
+{
+ smb_co_kill(FHTOCP(fhp));
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ * Also called via: smb_fh_kill()
+ */
+static void
+smb_fh_gone(struct smb_connobj *cp)
+{
+ struct smb_cred scred;
+ struct smb_fh *fhp = CPTOFH(cp);
+ smb_share_t *ssp = FHTOSS(fhp);
+ int err;
+
+ if ((fhp->fh_flags & SMBFH_VALID) == 0)
+ return;
+
+ /*
+ * We have no durable handles (yet) so if there has been a
+ * reconnect, don't bother to close this handle.
+ */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return;
+
+ smb_credinit(&scred, NULL);
+ err = smb_smb_close(ssp, fhp, &scred);
+ smb_credrele(&scred);
+ if (err) {
+ SMBSDEBUG("close err=%d\n", err);
+ }
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ */
+static void
+smb_fh_free(struct smb_connobj *cp)
+{
+ struct smb_fh *fhp = CPTOFH(cp);
+
+ smb_co_done(FHTOCP(fhp));
+ kmem_free(fhp, sizeof (*fhp));
+}
+
+/*
+ * Allocate fh structure and attach it to the given share.
+ * Share expected to be locked on entry.
+ */
+/*ARGSUSED*/
+int
+smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
+{
+ static char objtype[] = "smb_fh";
+ struct smb_fh *fhp;
+
+ fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
+ smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
+ fhp->fh_co.co_free = smb_fh_free;
+ fhp->fh_co.co_gone = smb_fh_gone;
+
+ SMB_SS_LOCK(ssp);
+ if ((ssp->ss_flags & SMBS_GONE) != 0) {
+ SMB_SS_UNLOCK(ssp);
+ smb_fh_free(FHTOCP(fhp));
+ return (ENOTCONN);
+ }
+
+ smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
+ *fhpp = fhp;
+ SMB_SS_UNLOCK(ssp);
+
+ return (0);
+}
+
+void
+smb_fh_opened(struct smb_fh *fhp)
+{
+ smb_share_t *ssp = FHTOSS(fhp);
+
+ SMB_FH_LOCK(fhp);
+ fhp->fh_vcgenid = ssp->ss_vcgenid;
+ fhp->fh_flags |= SMBFH_VALID;
+ SMB_FH_UNLOCK(fhp);
+}
+
+
+/*
* Solaris zones support
*/
/*ARGSUSED*/
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
index 42dfd687f9..d0a8a1dca0 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h
@@ -33,9 +33,11 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_CONN_H
@@ -46,6 +48,7 @@
#include <sys/queue.h> /* for SLIST below */
#include <sys/uio.h>
#include <netsmb/smb_dev.h>
+#include "smb_signing.h"
/*
* Credentials of user/process for processing in the connection procedures
@@ -61,14 +64,14 @@ typedef struct smb_cred {
/*
* Bits in vc_flags (a.k.a. vc_co.co_flags)
- * Many of these were duplicates of SMBVOPT_ flags
- * and we now keep those too instead of merging
- * them into vc_flags.
+ * Note: SMBO_GONE is also in vc_flags
*/
-
-#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
-#define SMBV_NT4 0x0020 /* used when NT4 issues invalid resp */
#define SMBV_UNICODE 0x0040 /* conn configured to use Unicode */
+#define SMBV_EXT_SEC 0x0080 /* conn to use extended security */
+#define SMBV_SIGNING 0x0100 /* negotiated signing */
+#define SMBV_SMB2 0x0200 /* VC using SMB 2 or 3 */
+#define SMBV_HAS_FILEIDS 0x0400 /* Use File IDs for hash and inode numbers */
+#define SMBV_NO_WRITE_THRU 0x0800 /* Can't use ... */
/*
* Note: the common "obj" level uses this GONE flag by
@@ -89,6 +92,16 @@ typedef struct smb_cred {
*/
#define SMBS_GONE SMBO_GONE
+/*
+ * bits in smb_fh fh_flags (a.k.a. ss_co.co_flags)
+ */
+#define SMBFH_VALID 0x0002 /* FID is valid */
+/*
+ * Note: the common "obj" level uses this GONE flag by
+ * the name SMBO_GONE. Keep this alias as a reminder.
+ */
+#define SMBFH_GONE SMBO_GONE
+
struct smb_rq;
/* This declares struct smb_rqhead */
TAILQ_HEAD(smb_rqhead, smb_rq);
@@ -141,9 +154,57 @@ typedef struct smb_connobj smb_connobj_t;
/*
* "Level" in the connection object hierarchy
*/
-#define SMBL_SM 0
-#define SMBL_VC 1
-#define SMBL_SHARE 2
+enum smbco_level {
+ SMBL_SM = 0,
+ SMBL_VC = 1,
+ SMBL_SHARE = 2,
+ SMBL_FH = 3
+};
+
+/*
+ * SMB1 Negotiated protocol parameters
+ */
+struct smb_sopt {
+ int16_t sv_proto; /* protocol dialect */
+ uchar_t sv_sm; /* security mode */
+ int16_t sv_tz; /* offset in min relative to UTC */
+ uint16_t sv_maxmux; /* max number of outstanding rq's */
+ uint16_t sv_maxvcs; /* max number of VCs */
+ uint16_t sv_rawmode;
+ uint32_t sv_maxtx; /* maximum transmit buf size */
+ uint32_t sv_maxraw; /* maximum raw-buffer size */
+ uint32_t sv_skey; /* session key */
+ uint32_t sv_caps; /* capabilites SMB_CAP_ */
+
+ /* SMB2+ fields */
+ uint32_t sv2_sessflags; /* final session setup reply flags */
+ uint16_t sv2_dialect; /* dialect (non zero for SMB 2/3 */
+ uint32_t sv2_capabilities; /* capabilities */
+ uint32_t sv2_maxtransact; /* max transact size */
+ uint32_t sv2_maxread; /* max read size */
+ uint32_t sv2_maxwrite; /* max write size */
+ uint8_t sv2_guid[16]; /* GUID */
+ uint16_t sv2_security_mode; /* security mode */
+};
+typedef struct smb_sopt smb_sopt_t;
+
+/*
+ * SMB1 I/O Deamon state
+ */
+struct smb_iods {
+ uint8_t is_hflags; /* SMB header flags */
+ uint16_t is_hflags2; /* SMB header flags2 */
+ uint16_t is_smbuid; /* SMB header UID */
+ uint16_t is_next_mid; /* SMB header MID */
+ uint32_t is_txmax; /* max tx/rx packet size */
+ uint32_t is_rwmax; /* max read/write data size */
+ uint32_t is_rxmax; /* max readx data size */
+ uint32_t is_wxmax; /* max writex data size */
+ /* Signing state */
+ uint32_t is_next_seq; /* my next sequence number */
+
+};
+typedef struct smb_iods smb_iods_t;
/*
* Virtual Circuit to a server (really connection + session).
@@ -160,20 +221,35 @@ typedef struct smb_vc {
uid_t vc_owner; /* Unix owner */
int vc_genid; /* "generation" ID */
- int vc_mackeylen; /* length of MAC key */
- uint8_t *vc_mackey; /* MAC key */
+ int vc_mackeylen; /* MAC key length */
+ int vc_ssnkeylen; /* session key length */
+ uint8_t *vc_mackey; /* MAC key buffer */
+ uint8_t *vc_ssnkey; /* session key buffer */
+ smb_sign_mech_t vc_signmech;
- ksema_t vc_sendlock;
struct smb_tran_desc *vc_tdesc; /* transport ops. vector */
void *vc_tdata; /* transport control block */
- kcondvar_t iod_idle; /* IOD thread idle CV */
+ /* SMB2+ fields */
+ uint64_t vc2_oldest_message_id;
+ uint64_t vc2_next_message_id;
+ uint64_t vc2_limit_message_id;
+ uint64_t vc2_session_id; /* session id */
+ uint64_t vc2_prev_session_id; /* for reconnect */
+ uint32_t vc2_lease_key; /* lease key gen */
+
+ kcondvar_t iod_idle; /* IOD thread idle CV */
krwlock_t iod_rqlock; /* iod_rqlist */
- struct smb_rqhead iod_rqlist; /* list of outstanding reqs */
- struct _kthread *iod_thr; /* the IOD (reader) thread */
+ struct smb_rqhead iod_rqlist; /* list of active reqs */
+ struct _kthread *iod_thr; /* the IOD (reader) thread */
int iod_flags; /* see SMBIOD_* below */
- int iod_newrq; /* send needed (iod_rqlock) */
- int iod_muxfull; /* maxmux limit reached */
+ uint_t iod_muxcnt; /* num. active requests */
+ uint_t iod_muxwant; /* waiting to be active */
+ kcondvar_t iod_muxwait;
+ boolean_t iod_noresp; /* Logged "not responding" */
+
+ smb_iods_t vc_iods;
+ smb_sopt_t vc_sopt;
/* This is copied in/out when IOD enters/returns */
smbioc_ssn_work_t vc_work;
@@ -187,33 +263,40 @@ typedef struct smb_vc {
/* defines for members in vc_ssn */
#define vc_owner vc_ssn.ssn_owner
+#define vc_vopt vc_ssn.ssn_vopt
+#define vc_minver vc_ssn.ssn_minver
+#define vc_maxver vc_ssn.ssn_maxver
#define vc_srvname vc_ssn.ssn_srvname
#define vc_srvaddr vc_ssn.ssn_id.id_srvaddr
#define vc_domain vc_ssn.ssn_id.id_domain
#define vc_username vc_ssn.ssn_id.id_user
-#define vc_vopt vc_ssn.ssn_vopt
/* defines for members in vc_work */
-#define vc_sopt vc_work.wk_sopt
-#define vc_maxmux vc_work.wk_sopt.sv_maxmux
-#define vc_tran_fd vc_work.wk_iods.is_tran_fd
-#define vc_hflags vc_work.wk_iods.is_hflags
-#define vc_hflags2 vc_work.wk_iods.is_hflags2
-#define vc_smbuid vc_work.wk_iods.is_smbuid
-#define vc_next_mid vc_work.wk_iods.is_next_mid
-#define vc_txmax vc_work.wk_iods.is_txmax
-#define vc_rwmax vc_work.wk_iods.is_rwmax
-#define vc_rxmax vc_work.wk_iods.is_rxmax
-#define vc_wxmax vc_work.wk_iods.is_wxmax
-#define vc_ssn_key vc_work.wk_iods.is_ssn_key
-#define vc_next_seq vc_work.wk_iods.is_next_seq
-#define vc_u_mackey vc_work.wk_iods.is_u_mackey
-#define vc_u_maclen vc_work.wk_iods.is_u_maclen
+#define vc_cl_guid vc_work.wk_cl_guid
+
+/* defines for members in vc_sopt ? */
+#define vc_maxmux vc_sopt.sv_maxmux
+
+/* defines for members in vc_iods */
+#define vc_hflags vc_iods.is_hflags
+#define vc_hflags2 vc_iods.is_hflags2
+#define vc_smbuid vc_iods.is_smbuid
+#define vc_next_mid vc_iods.is_next_mid
+#define vc_txmax vc_iods.is_txmax
+#define vc_rwmax vc_iods.is_rwmax
+#define vc_rxmax vc_iods.is_rxmax
+#define vc_wxmax vc_iods.is_wxmax
+#define vc_next_seq vc_iods.is_next_seq
#define SMB_VC_LOCK(vcp) mutex_enter(&(vcp)->vc_lock)
#define SMB_VC_UNLOCK(vcp) mutex_exit(&(vcp)->vc_lock)
-#define SMB_UNICODE_STRINGS(vcp) ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE)
+#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp)))
+#define VCTOCP(vcp) (&(vcp)->vc_co)
+
+#define SMB_UNICODE_STRINGS(vcp) \
+ (((vcp)->vc_flags & SMBV_SMB2) != 0 || \
+ ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0)
/* Bits in iod_flags */
#define SMBIOD_RUNNING 0x0001
@@ -231,6 +314,9 @@ typedef struct smb_share {
int ss_vcgenid; /* check VC generation ID */
uint16_t ss_tid; /* TID */
uint16_t ss_options; /* option support bits */
+ uint32_t ss2_tree_id;
+ uint32_t ss2_share_flags;
+ uint32_t ss2_share_caps;
smbioc_oshare_t ss_ioc;
} smb_share_t;
@@ -245,27 +331,47 @@ typedef struct smb_share {
#define SMB_SS_LOCK(ssp) mutex_enter(&(ssp)->ss_lock)
#define SMB_SS_UNLOCK(ssp) mutex_exit(&(ssp)->ss_lock)
-#define CPTOVC(cp) ((struct smb_vc *)((void *)(cp)))
-#define VCTOCP(vcp) (&(vcp)->vc_co)
-
#define CPTOSS(cp) ((struct smb_share *)((void *)(cp)))
-#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent))
#define SSTOCP(ssp) (&(ssp)->ss_co)
+#define SSTOVC(ssp) CPTOVC(((ssp)->ss_co.co_parent))
+
+typedef struct smb2fid {
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+} smb2fid_t;
+
+/*
+ * smb_fh struct describes an open file handle under some share.
+ */
+typedef struct smb_fh {
+ struct smb_connobj fh_co; /* keep first! See CPTOSS */
+ int fh_vcgenid; /* check VC generation ID */
+ uint32_t fh_rights; /* granted access */
+ smb2fid_t fh_fid2;
+ uint16_t fh_fid1;
+} smb_fh_t;
+
+#define fh_lock fh_co.co_lock
+#define fh_flags fh_co.co_flags
+
+#define SMB_FH_LOCK(fhp) mutex_enter(&(fhp)->fh_lock)
+#define SMB_FH_UNLOCK(fhp) mutex_exit(&(fhp)->fh_lock)
+
+#define CPTOFH(cp) ((struct smb_fh *)((void *)(cp)))
+#define FHTOCP(fhp) (&(fhp)->fh_co)
+#define FHTOSS(fhp) CPTOSS(((fhp)->fh_co.co_parent))
/*
* Call-back operations vector, so the netsmb module
* can notify smbfs about events affecting mounts.
* Installed in netsmb after smbfs loads.
+ * Note: smbfs only uses the fscb_discon hook.
*/
typedef struct smb_fscb {
/* Called when the VC has disconnected. */
void (*fscb_disconn)(smb_share_t *);
/* Called when the VC has reconnected. */
void (*fscb_connect)(smb_share_t *);
- /* Called when the server becomes unresponsive. */
- void (*fscb_down)(smb_share_t *);
- /* Called when the server is responding again. */
- void (*fscb_up)(smb_share_t *);
} smb_fscb_t;
/* Install the above vector, or pass NULL to clear it. */
void smb_fscb_set(smb_fscb_t *);
@@ -278,14 +384,14 @@ typedef struct smb_dev {
kmutex_t sd_lock;
struct smb_vc *sd_vc; /* Reference to VC */
struct smb_share *sd_share; /* Reference to share if any */
+ struct smb_fh *sd_fh; /* Reference to FH, if any */
int sd_level; /* SMBL_VC, ... */
int sd_vcgenid; /* Generation of share or VC */
int sd_poll; /* Future use */
int sd_flags; /* State of connection */
-#define NSMBFL_OPEN 0x0001
-#define NSMBFL_IOD 0x0002
-#define NSMBFL_IOCTL 0x0004
- int sd_smbfid; /* library read/write */
+#define NSMBFL_OPEN 0x0001 /* Device minor is open */
+#define NSMBFL_IOD 0x0004 /* Open by IOD */
+#define NSMBFL_IOCTL 0x0010 /* Serialize ioctl calls */
zoneid_t zoneid; /* Zone id */
} smb_dev_t;
@@ -300,6 +406,8 @@ int smb_dev2share(int fd, struct smb_share **sspp);
/*
* smb_usr.c
*/
+int smb_usr_ioctl(smb_dev_t *, int, intptr_t, int, cred_t *);
+
int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags);
int smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags);
@@ -319,7 +427,10 @@ int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *);
int smb_usr_drop_tree(smb_dev_t *sdp, int cmd);
int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
-int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
+int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags,
+ cred_t *cr);
+
+int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
/*
@@ -327,18 +438,23 @@ int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
*/
int smb_iod_create(smb_vc_t *vcp);
int smb_iod_destroy(smb_vc_t *vcp);
-int smb_iod_connect(smb_vc_t *vcp);
void smb_iod_disconnect(smb_vc_t *vcp);
-int smb_iod_addrq(struct smb_rq *rqp);
-int smb_iod_multirq(struct smb_rq *rqp);
+int smb2_iod_addrq(struct smb_rq *rqp);
+int smb1_iod_addrq(struct smb_rq *rqp);
+int smb1_iod_multirq(struct smb_rq *rqp);
int smb_iod_waitrq(struct smb_rq *rqp);
+int smb_iod_waitrq_int(struct smb_rq *rqp);
void smb_iod_removerq(struct smb_rq *rqp);
+int smb_iod_sendrecv(struct smb_rq *, int);
void smb_iod_shutdown_share(smb_share_t *ssp);
void smb_iod_sendall(smb_vc_t *);
-int smb_iod_recvall(smb_vc_t *);
+int smb_iod_recvall(smb_vc_t *, boolean_t);
-int smb_iod_vc_work(smb_vc_t *, cred_t *);
+int nsmb_iod_connect(smb_vc_t *vcp, cred_t *cr);
+int nsmb_iod_negotiate(smb_vc_t *vcp, cred_t *cr);
+int nsmb_iod_ssnsetup(smb_vc_t *vcp, cred_t *cr);
+int smb_iod_vc_work(smb_vc_t *, int, cred_t *);
int smb_iod_vc_idle(smb_vc_t *);
int smb_iod_vc_rcfail(smb_vc_t *);
int smb_iod_reconnect(smb_vc_t *);
@@ -381,4 +497,13 @@ void smb_share_kill(smb_share_t *ssp);
void smb_share_invalidate(smb_share_t *ssp);
int smb_share_tcon(smb_share_t *, smb_cred_t *);
+/*
+ * File handle level functions
+ */
+int smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp);
+void smb_fh_opened(struct smb_fh *fhp);
+void smb_fh_close(struct smb_fh *fhp);
+void smb_fh_hold(struct smb_fh *fhp);
+void smb_fh_rele(struct smb_fh *fhp);
+
#endif /* _SMB_CONN_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
index 489a1756ec..3f00ec24ed 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
@@ -31,9 +31,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -61,35 +62,42 @@
#include <sys/modctl.h>
#include <sys/devops.h>
#include <sys/thread.h>
-#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/zone.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/mchain.h> /* for "htoles()" */
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_pass.h>
+#ifndef _KERNEL
+#include <libfknsmb.h>
+
+#define _init(v) nsmb_drv_init(v)
+#define _fini(v) nsmb_drv_fini(v)
+
+#endif /* _KERNEL */
+
#define NSMB_MIN_MINOR 1
#define NSMB_MAX_MINOR L_MAXMIN32
/* for version checks */
const uint32_t nsmb_version = NSMB_VERSION;
+/* for smb_nbst_create() */
+dev_t nsmb_dev_tcp = NODEV;
+dev_t nsmb_dev_tcp6 = NODEV;
+
static void *statep;
static major_t nsmb_major;
static minor_t last_minor = NSMB_MIN_MINOR;
-static dev_info_t *nsmb_dip;
static kmutex_t dev_lck;
-/* Zone support */
-zone_key_t nsmb_zone_key;
-extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
-extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
-
/*
* cb_ops device operations.
*/
@@ -99,6 +107,15 @@ static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp);
static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
+#ifdef _KERNEL
+
+static dev_info_t *nsmb_dip;
+
+/* Zone support */
+zone_key_t nsmb_zone_key;
+extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
+extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
+
/* smbfs cb_ops */
static struct cb_ops nsmb_cbops = {
nsmb_open, /* open */
@@ -160,10 +177,14 @@ static struct modlinkage nsmb_modlinkage = {
NULL
};
+#endif /* _KERNEL */
+
int
_init(void)
{
+#ifdef _KERNEL
int error;
+#endif /* _KERNEL */
(void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
@@ -176,12 +197,7 @@ _init(void)
/* Initialize password Key chain DB. */
smb_pkey_init();
- /* Time conversion stuff. */
- smb_time_init();
-
- /* Initialize crypto mechanisms. */
- smb_crypto_mech_init();
-
+#ifdef _KERNEL
zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
nsmb_zone_destroy);
@@ -200,6 +216,14 @@ _init(void)
return (error);
}
+#else /* _KERNEL */
+ streams_msg_init();
+ /* No attach, so need to set major. */
+ nsmb_major = 1;
+ /* And these, for smb_nbst_create() */
+ nsmb_dev_tcp = AF_INET;
+ nsmb_dev_tcp6 = AF_INET6;
+#endif /* _KERNEL */
return (0);
}
@@ -218,6 +242,7 @@ _fini(void)
if ((status = smb_pkey_idle()) != 0)
return (status);
+#ifdef _KERNEL
/*
* Remove the module. Do this before destroying things,
* to prevent new entrances while we're destorying.
@@ -227,9 +252,7 @@ _fini(void)
}
(void) zone_key_delete(nsmb_zone_key);
-
- /* Time conversion stuff. */
- smb_time_fini();
+#endif /* _KERNEL */
/* Destroy password Key chain DB. */
smb_pkey_fini();
@@ -242,6 +265,8 @@ _fini(void)
return (status);
}
+#ifdef _KERNEL
+
int
_info(struct modinfo *modinfop)
{
@@ -270,6 +295,7 @@ nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
static int
nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
+ major_t tmaj;
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
@@ -294,6 +320,20 @@ nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
nsmb_major = ddi_name_to_major(NSMB_NAME);
+ /*
+ * We also need major numbers for t_kopen
+ */
+ tmaj = ddi_name_to_major("tcp");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp major?");
+ else
+ nsmb_dev_tcp = makedevice(tmaj, 0);
+ tmaj = ddi_name_to_major("tcp6");
+ if (tmaj == DDI_MAJOR_T_NONE)
+ cmn_err(CE_NOTE, "no tcp6 major?");
+ else
+ nsmb_dev_tcp6 = makedevice(tmaj, 0);
+
nsmb_dip = dip;
ddi_report_dev(dip);
return (DDI_SUCCESS);
@@ -315,6 +355,65 @@ nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
return (DDI_SUCCESS);
}
+#else /* _KERNEL */
+
+/*
+ * Wrappers for libfknsmb: ioctl, open, close, load
+ */
+
+/*ARGSUSED*/
+int
+nsmb_drv_ioctl(dev32_t dev32, int cmd, intptr_t arg, int flags)
+{
+ dev_t dev = expldev(dev32);
+ cred_t *cr = CRED();
+ int err;
+
+ err = nsmb_ioctl(dev, cmd, arg, flags, cr, NULL);
+ return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_open(dev32_t *dev32p, int flags, int otyp)
+{
+ dev_t dev = expldev(*dev32p);
+ int err;
+
+ err = nsmb_open(&dev, flags, otyp, CRED());
+ if (err == 0) {
+ /*
+ * We have NSMB_MAX_MINOR == L_MAXMIN32
+ * therefore cmpldev never fails.
+ */
+ VERIFY(cmpldev(dev32p, dev) != 0);
+ }
+ return (err);
+}
+
+/*ARGSUSED*/
+int
+nsmb_drv_close(dev32_t dev32, int flags, int otyp)
+{
+ dev_t dev = expldev(dev32);
+ int err;
+
+ err = nsmb_close(dev, flags, otyp, CRED());
+ return (err);
+}
+
+/*
+ * This function intentionally does nothing. It's used only to
+ * force libfknsmb to load at program start so one can set
+ * breakpoints etc. without debugger "force load" tricks.
+ */
+void
+nsmb_drv_load(void)
+{
+}
+
+#endif /* _KERNEL */
+
/*ARGSUSED*/
static int
nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
@@ -325,7 +424,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
sdp = ddi_get_soft_state(statep, getminor(dev));
if (sdp == NULL) {
- return (DDI_FAILURE);
+ return (EBADF);
}
if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
return (EBADF);
@@ -346,107 +445,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
* check the zone status here on every ioctl call.
*/
- /*
- * Serialize ioctl calls. The smb_usr_... functions
- * don't expect concurrent calls on a given sdp.
- */
- mutex_enter(&sdp->sd_lock);
- if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
- mutex_exit(&sdp->sd_lock);
- return (EBUSY);
- }
- sdp->sd_flags |= NSMBFL_IOCTL;
- mutex_exit(&sdp->sd_lock);
-
- err = 0;
- switch (cmd) {
- case SMBIOC_GETVERS:
- (void) ddi_copyout(&nsmb_version, (void *)arg,
- sizeof (nsmb_version), flags);
- break;
-
- case SMBIOC_FLAGS2:
- err = smb_usr_get_flags2(sdp, arg, flags);
- break;
-
- case SMBIOC_GETSSNKEY:
- err = smb_usr_get_ssnkey(sdp, arg, flags);
- break;
-
- case SMBIOC_DUP_DEV:
- err = smb_usr_dup_dev(sdp, arg, flags);
- break;
-
- case SMBIOC_REQUEST:
- err = smb_usr_simplerq(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_T2RQ:
- err = smb_usr_t2request(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_READ:
- case SMBIOC_WRITE:
- err = smb_usr_rw(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_NTCREATE:
- err = smb_usr_ntcreate(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_PRINTJOB:
- err = smb_usr_printjob(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_CLOSEFH:
- err = smb_usr_closefh(sdp, cr);
- break;
-
- case SMBIOC_SSN_CREATE:
- case SMBIOC_SSN_FIND:
- err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_SSN_KILL:
- case SMBIOC_SSN_RELE:
- err = smb_usr_drop_ssn(sdp, cmd);
- break;
-
- case SMBIOC_TREE_CONNECT:
- case SMBIOC_TREE_FIND:
- err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
- break;
-
- case SMBIOC_TREE_KILL:
- case SMBIOC_TREE_RELE:
- err = smb_usr_drop_tree(sdp, cmd);
- break;
-
- case SMBIOC_IOD_WORK:
- err = smb_usr_iod_work(sdp, arg, flags, cr);
- break;
-
- case SMBIOC_IOD_IDLE:
- case SMBIOC_IOD_RCFAIL:
- err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
- break;
-
- case SMBIOC_PK_ADD:
- case SMBIOC_PK_DEL:
- case SMBIOC_PK_CHK:
- case SMBIOC_PK_DEL_OWNER:
- case SMBIOC_PK_DEL_EVERYONE:
- err = smb_pkey_ioctl(cmd, arg, flags, cr);
- break;
-
- default:
- err = ENOTTY;
- break;
- }
-
- mutex_enter(&sdp->sd_lock);
- sdp->sd_flags &= ~NSMBFL_IOCTL;
- mutex_exit(&sdp->sd_lock);
+ err = smb_usr_ioctl(sdp, cmd, arg, flags, cr);
return (err);
}
@@ -491,7 +490,6 @@ found:
*dev = makedevice(nsmb_major, m);
mutex_exit(&dev_lck);
- sdp->sd_smbfid = -1;
sdp->sd_flags |= NSMBFL_OPEN;
sdp->zoneid = crgetzoneid(cr);
mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
@@ -529,14 +527,17 @@ nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
return (err);
}
+/*ARGSUSED*/
static int
nsmb_close2(smb_dev_t *sdp, cred_t *cr)
{
struct smb_vc *vcp;
struct smb_share *ssp;
+ struct smb_fh *fhp;
- if (sdp->sd_smbfid != -1)
- (void) smb_usr_closefh(sdp, cr);
+ fhp = sdp->sd_fh;
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
ssp = sdp->sd_share;
if (ssp != NULL)
@@ -566,8 +567,10 @@ nsmb_close2(smb_dev_t *sdp, cred_t *cr)
int
smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
{
+#ifdef _KERNEL
file_t *fp = NULL;
vnode_t *vp;
+#endif /* _KERNEL */
smb_dev_t *from_sdp;
dev_t dev;
int32_t ufd;
@@ -582,16 +585,24 @@ smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
*/
if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
return (EFAULT);
+#ifdef _KERNEL
if ((fp = getf(ufd)) == NULL)
return (EBADF);
/* rele fp below */
vp = fp->f_vnode;
dev = vp->v_rdev;
+#else /* _KERNEL */
+ /*
+ * No getf(ufd) -- ufd is really a dev32_t
+ */
+ dev = expldev((dev32_t)ufd);
+#endif /* _KERNEL */
if (dev == 0 || dev == NODEV ||
getmajor(dev) != nsmb_major) {
err = EINVAL;
goto out;
}
+
from_sdp = ddi_get_soft_state(statep, getminor(dev));
if (from_sdp == NULL) {
err = EINVAL;
@@ -609,8 +620,10 @@ smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
err = 0;
out:
+#ifdef _KERNEL
if (fp)
releasef(ufd);
+#endif /* _KERNEL */
return (err);
}
@@ -621,19 +634,27 @@ out:
int
smb_dev2share(int fd, struct smb_share **sspp)
{
+#ifdef _KERNEL
file_t *fp = NULL;
vnode_t *vp;
+#endif /* _KERNEL */
smb_dev_t *sdp;
smb_share_t *ssp;
dev_t dev;
int err;
+#ifdef _KERNEL
if ((fp = getf(fd)) == NULL)
return (EBADF);
/* rele fp below */
-
vp = fp->f_vnode;
dev = vp->v_rdev;
+#else /* _KERNEL */
+ /*
+ * No getf(ufd) -- fd is really a dev32_t
+ */
+ dev = expldev((dev32_t)fd);
+#endif /* _KERNEL */
if (dev == 0 || dev == NODEV ||
getmajor(dev) != nsmb_major) {
err = EINVAL;
@@ -660,7 +681,9 @@ smb_dev2share(int fd, struct smb_share **sspp)
err = 0;
out:
+#ifdef _KERNEL
if (fp)
releasef(fd);
+#endif /* _KERNEL */
return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
index db82fa0958..48c8ef591d 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c
@@ -35,6 +35,9 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifdef DEBUG
@@ -67,13 +70,26 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
-int smb_iod_send_echo(smb_vc_t *);
+/*
+ * SMB messages are up to 64K. Let's leave room for two.
+ * If we negotiate up to SMB2, increase these. XXX todo
+ */
+static int smb_tcpsndbuf = 0x20000;
+static int smb_tcprcvbuf = 0x20000;
+static int smb_connect_timeout = 10; /* seconds */
+
+static int smb1_iod_process(smb_vc_t *, mblk_t *);
+static int smb2_iod_process(smb_vc_t *, mblk_t *);
+static int smb_iod_send_echo(smb_vc_t *, cred_t *cr);
+static int smb_iod_logoff(struct smb_vc *vcp, cred_t *cr);
/*
* This is set/cleared when smbfs loads/unloads
@@ -93,7 +109,10 @@ smb_iod_share_disconnected(smb_share_t *ssp)
smb_share_invalidate(ssp);
- /* smbfs_dead() */
+ /*
+ * This is the only fscb hook smbfs currently uses.
+ * Replaces smbfs_dead() from Darwin.
+ */
if (fscb && fscb->fscb_disconn) {
fscb->fscb_disconn(ssp);
}
@@ -142,19 +161,22 @@ smb_iod_invrq(struct smb_vc *vcp)
/*
* Invalidate all outstanding requests for this connection
+ * Also wakeup iod_muxwant waiters.
*/
rw_enter(&vcp->iod_rqlock, RW_READER);
TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
}
rw_exit(&vcp->iod_rqlock);
+ cv_broadcast(&vcp->iod_muxwait);
}
/*
- * Called by smb_vc_rele, smb_vc_kill, and by the driver
- * close entry point if the IOD closes its dev handle.
+ * Called by smb_vc_rele/smb_vc_kill on last ref, and by
+ * the driver close function if the IOD closes its minor.
+ * In those cases, the caller should be the IOD thread.
*
- * Forcibly kill the connection and IOD.
+ * Forcibly kill the connection.
*/
void
smb_iod_disconnect(struct smb_vc *vcp)
@@ -170,139 +192,209 @@ smb_iod_disconnect(struct smb_vc *vcp)
}
SMB_VC_UNLOCK(vcp);
- /*
- * Let's be safe here and avoid doing any
- * call across the network while trying to
- * shut things down. If we just disconnect,
- * the server will take care of the logoff.
- */
SMB_TRAN_DISCONNECT(vcp);
}
/*
* Send one request.
*
+ * SMB1 only
+ *
* Called by _addrq (for internal requests)
* and _sendall (via _addrq, _multirq, _waitrq)
+ * Errors are reported via the smb_rq, using:
+ * smb_iod_rqprocessed(rqp, ...)
*/
-static int
-smb_iod_sendrq(struct smb_rq *rqp)
+static void
+smb1_iod_sendrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
mblk_t *m;
int error;
ASSERT(vcp);
- ASSERT(SEMA_HELD(&vcp->vc_sendlock));
- ASSERT(RW_READ_HELD(&vcp->iod_rqlock));
+ ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
/*
- * Note: Anything special for SMBR_INTERNAL here?
+ * Internal requests are allowed in any state;
+ * otherwise should be active.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- return (ENOTCONN);
+ smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
+ return;
}
-
/*
- * On the first send, set the MID and (maybe)
- * the signing sequence numbers. The increments
- * here are serialized by vc_sendlock
+ * Overwrite the SMB header with the assigned MID and
+ * (if we're signing) sign it.
*/
- if (rqp->sr_sendcnt == 0) {
+ smb_rq_fillhdr(rqp);
+ if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ smb_rq_sign(rqp);
+ }
- rqp->sr_mid = vcp->vc_next_mid++;
+ /*
+ * The transport send consumes the message and we'd
+ * prefer to keep a copy, so dupmsg() before sending.
+ */
+ m = dupmsg(rqp->sr_rq.mb_top);
+ if (m == NULL) {
+ error = ENOBUFS;
+ goto fatal;
+ }
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- /*
- * We're signing requests and verifying
- * signatures on responses. Set the
- * sequence numbers of the request and
- * response here, used in smb_rq_verify.
- */
- rqp->sr_seqno = vcp->vc_next_seq++;
- rqp->sr_rseqno = vcp->vc_next_seq++;
- }
+#ifdef DTRACE_PROBE2
+ DTRACE_PROBE2(iod_sendrq,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+#endif
- /* Fill in UID, TID, MID, etc. */
- smb_rq_fillhdr(rqp);
+ error = SMB_TRAN_SEND(vcp, m);
+ m = 0; /* consumed by SEND */
- /*
- * Sign the message now that we're finally done
- * filling in the SMB header fields, etc.
- */
- if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
- smb_rq_sign(rqp);
- }
+ rqp->sr_lerror = error;
+ if (error == 0) {
+ SMBRQ_LOCK(rqp);
+ rqp->sr_flags |= SMBR_SENT;
+ rqp->sr_state = SMBRQ_SENT;
+ SMBRQ_UNLOCK(rqp);
+ return;
}
- if (rqp->sr_sendcnt++ >= 60/SMBSBTIMO) { /* one minute */
- smb_iod_rqprocessed(rqp, rqp->sr_lerror, SMBR_RESTART);
+ /*
+ * Transport send returned an error.
+ * Was it a fatal one?
+ */
+ if (SMB_TRAN_FATAL(vcp, error)) {
/*
- * If all attempts to send a request failed, then
- * something is seriously hosed.
+ * No further attempts should be made
*/
- return (ENOTCONN);
+ fatal:
+ SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error);
+ smb_iod_rqprocessed(rqp, error, SMBR_RESTART);
+ return;
}
+}
+
+/*
+ * Send one request.
+ *
+ * SMB2 only
+ *
+ * Called by _addrq (for internal requests)
+ * and _sendall (via _addrq, _multirq, _waitrq)
+ * Errors are reported via the smb_rq, using:
+ * smb_iod_rqprocessed(rqp, ...)
+ */
+static void
+smb2_iod_sendrq(struct smb_rq *rqp)
+{
+ struct smb_rq *c_rqp; /* compound */
+ struct smb_vc *vcp = rqp->sr_vc;
+ mblk_t *top_m;
+ mblk_t *cur_m;
+ int error;
+
+ ASSERT(vcp);
+ ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
/*
- * Replaced m_copym() with Solaris copymsg() which does the same
- * work when we want to do a M_COPYALL.
- * m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, 0);
+ * Internal requests are allowed in any state;
+ * otherwise should be active.
*/
- m = copymsg(rqp->sr_rq.mb_top);
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
+ return;
+ }
-#ifdef DTRACE_PROBE
- DTRACE_PROBE2(smb_iod_sendrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
-#else
- SMBIODEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
-#endif
- m_dumpm(m);
+ /*
+ * Overwrite the SMB header with the assigned MID and
+ * (if we're signing) sign it. If there are compounded
+ * requests after the top one, do those too.
+ */
+ smb2_rq_fillhdr(rqp);
+ if (rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ smb2_rq_sign(rqp);
+ }
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ smb2_rq_fillhdr(c_rqp);
+ if (c_rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) {
+ smb2_rq_sign(c_rqp);
+ }
+ c_rqp = c_rqp->sr2_compound_next;
+ }
- if (m != NULL) {
- error = SMB_TRAN_SEND(vcp, m);
- m = 0; /* consumed by SEND */
- } else
+ /*
+ * The transport send consumes the message and we'd
+ * prefer to keep a copy, so dupmsg() before sending.
+ * We also need this to build the compound message
+ * that we'll actually send. The message offset at
+ * the start of each compounded message should be
+ * eight-byte aligned. The caller preparing the
+ * compounded request has to take care of that
+ * before we get here and sign messages etc.
+ */
+ top_m = dupmsg(rqp->sr_rq.mb_top);
+ if (top_m == NULL) {
error = ENOBUFS;
+ goto fatal;
+ }
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ size_t len = msgdsize(top_m);
+ ASSERT((len & 7) == 0);
+ cur_m = dupmsg(c_rqp->sr_rq.mb_top);
+ if (cur_m == NULL) {
+ freemsg(top_m);
+ error = ENOBUFS;
+ goto fatal;
+ }
+ linkb(top_m, cur_m);
+ }
+
+ DTRACE_PROBE2(iod_sendrq,
+ (smb_rq_t *), rqp, (mblk_t *), top_m);
+
+ error = SMB_TRAN_SEND(vcp, top_m);
+ top_m = 0; /* consumed by SEND */
rqp->sr_lerror = error;
if (error == 0) {
SMBRQ_LOCK(rqp);
rqp->sr_flags |= SMBR_SENT;
rqp->sr_state = SMBRQ_SENT;
- if (rqp->sr_flags & SMBR_SENDWAIT)
- cv_broadcast(&rqp->sr_cond);
SMBRQ_UNLOCK(rqp);
- return (0);
+ return;
}
/*
- * Check for fatal errors
+ * Transport send returned an error.
+ * Was it a fatal one?
*/
if (SMB_TRAN_FATAL(vcp, error)) {
/*
* No further attempts should be made
*/
+ fatal:
SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error);
- return (ENOTCONN);
+ smb_iod_rqprocessed(rqp, error, SMBR_RESTART);
+ return;
}
- if (error)
- SMBSDEBUG("TRAN_SEND returned non-fatal error %d\n", error);
-
-#ifdef APPLE
- /* If proc waiting on rqp was signaled... */
- if (smb_rq_intr(rqp))
- smb_iod_rqprocessed(rqp, EINTR, 0);
-#endif
-
- return (0);
}
+/*
+ * Receive one NetBIOS (or NBT over TCP) message. If none have arrived,
+ * wait up to SMB_NBTIMO (15 sec.) for one to arrive, and then if still
+ * none have arrived, return ETIME.
+ */
static int
-smb_iod_recv1(struct smb_vc *vcp, mblk_t **mpp)
+smb_iod_recvmsg(struct smb_vc *vcp, mblk_t **mpp)
{
mblk_t *m;
- uchar_t *hp;
int error;
top:
@@ -312,58 +404,50 @@ top:
goto top;
if (error)
return (error);
- ASSERT(m);
+ ASSERT(m != NULL);
- m = m_pullup(m, SMB_HDRLEN);
+ m = m_pullup(m, 4);
if (m == NULL) {
return (ENOSR);
}
- /*
- * Check the SMB header
- */
- hp = mtod(m, uchar_t *);
- if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
- m_freem(m);
- return (EPROTO);
- }
-
*mpp = m;
return (0);
}
/*
+ * How long should we keep around an unused VC (connection)?
+ * There's usually a good chance connections will be reused,
+ * so the default is to keep such connections for 5 min.
+ */
+#ifdef DEBUG
+int smb_iod_idle_keep_time = 60; /* seconds */
+#else
+int smb_iod_idle_keep_time = 300; /* seconds */
+#endif
+
+/*
* Process incoming packets
*
- * This is the "reader" loop, run by the IOD thread
- * while in state SMBIOD_ST_VCACTIVE. The loop now
- * simply blocks in the socket recv until either a
- * message arrives, or a disconnect.
+ * This is the "reader" loop, run by the IOD thread. Normally we're in
+ * state SMBIOD_ST_VCACTIVE here, but during reconnect we're called in
+ * other states with poll==TRUE
*
- * Any non-zero error means the IOD should terminate.
+ * A non-zero error return here causes the IOD work loop to terminate.
*/
int
-smb_iod_recvall(struct smb_vc *vcp)
+smb_iod_recvall(struct smb_vc *vcp, boolean_t poll)
{
- struct smb_rq *rqp;
mblk_t *m;
- uchar_t *hp;
- ushort_t mid;
int error = 0;
- int etime_count = 0; /* for "server not responding", etc. */
+ int etime_idle = 0; /* How many 15 sec. "ticks" idle. */
+ int etime_count = 0; /* ... and when we have requests. */
for (;;) {
/*
* Check whether someone "killed" this VC,
* or is asking the IOD to terminate.
*/
-
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
- error = 0;
- break;
- }
-
if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
SMBIODEBUG("SHUTDOWN set\n");
/* This IOD thread will terminate. */
@@ -376,52 +460,88 @@ smb_iod_recvall(struct smb_vc *vcp)
}
m = NULL;
- error = smb_iod_recv1(vcp, &m);
+ error = smb_iod_recvmsg(vcp, &m);
+
+ /*
+ * Internal requests (reconnecting) call this in a loop
+ * (with poll==TRUE) until the request completes.
+ */
+ if (error == ETIME && poll)
+ break;
if (error == ETIME &&
vcp->iod_rqlist.tqh_first != NULL) {
+
/*
- * Nothing received for 15 seconds and
- * we have requests in the queue.
+ * Nothing received and requests waiting.
+ * Increment etime_count. If we were idle,
+ * skip the 1st tick, because we started
+ * waiting before there were any requests.
*/
- etime_count++;
+ if (etime_idle != 0) {
+ etime_idle = 0;
+ } else if (etime_count < INT16_MAX) {
+ etime_count++;
+ }
/*
- * Once, at 15 sec. notify callbacks
- * and print the warning message.
+ * ETIME and requests in the queue.
+ * The first time (at 15 sec.)
+ * Log an error (just once).
*/
- if (etime_count == 1) {
- /* Was: smb_iod_notify_down(vcp); */
- if (fscb && fscb->fscb_down)
- smb_vc_walkshares(vcp,
- fscb->fscb_down);
+ if (etime_count > 0 &&
+ vcp->iod_noresp == B_FALSE) {
+ vcp->iod_noresp = B_TRUE;
zprintf(vcp->vc_zoneid,
"SMB server %s not responding\n",
vcp->vc_srvname);
}
-
/*
- * At 30 sec. try sending an echo, and then
- * once a minute thereafter.
+ * At 30 sec. try sending an echo, which
+ * should cause some response.
*/
- if ((etime_count & 3) == 2) {
- (void) smb_iod_send_echo(vcp);
+ if (etime_count == 2) {
+ SMBIODEBUG("send echo\n");
+ (void) smb_iod_send_echo(vcp, CRED());
+ }
+ /*
+ * At 45 sec. give up on the connection
+ * and try to reconnect.
+ */
+ if (etime_count == 3) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ SMB_VC_UNLOCK(vcp);
+ SMB_TRAN_DISCONNECT(vcp);
+ break;
}
-
continue;
- } /* ETIME && requests in queue */
+ } /* ETIME and requests in the queue */
if (error == ETIME) {
/*
- * If the IOD thread holds the last reference
- * to this VC, let the IOD thread terminate.
+ * Nothing received and no active requests.
+ *
+ * If we've received nothing from the server for
+ * smb_iod_idle_keep_time seconds, and the IOD
+ * thread holds the last reference to this VC,
+ * move to state IDLE and drop the TCP session.
+ * The IDLE handler will destroy the VC unless
+ * vc_state goes to RECONNECT before then.
*/
- if (vcp->vc_co.co_usecount > 1)
+ etime_count = 0;
+ if (etime_idle < INT16_MAX)
+ etime_idle++;
+ if ((etime_idle * SMB_NBTIMO) <
+ smb_iod_idle_keep_time)
continue;
SMB_VC_LOCK(vcp);
if (vcp->vc_co.co_usecount == 1) {
- smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
SMB_VC_UNLOCK(vcp);
+ SMBIODEBUG("logoff & disconnect\n");
+ (void) smb_iod_logoff(vcp, CRED());
+ SMB_TRAN_DISCONNECT(vcp);
error = 0;
break;
}
@@ -431,91 +551,327 @@ smb_iod_recvall(struct smb_vc *vcp)
if (error) {
/*
- * The recv. above returned some error
- * we can't continue from i.e. ENOTCONN.
- * It's dangerous to continue here.
- * (possible infinite loop!)
- *
- * If we have requests enqueued, next
- * state is reconnecting, else idle.
+ * The recv above returned an error indicating
+ * that our TCP session is no longer usable.
+ * Disconnect the session and get ready to
+ * reconnect. If we have pending requests,
+ * move to state reconnect immediately;
+ * otherwise move to state IDLE until a
+ * request is issued on this VC.
*/
- int state;
SMB_VC_LOCK(vcp);
- state = (vcp->iod_rqlist.tqh_first != NULL) ?
- SMBIOD_ST_RECONNECT : SMBIOD_ST_IDLE;
- smb_iod_newstate(vcp, state);
+ if (vcp->iod_rqlist.tqh_first != NULL)
+ smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+ else
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
cv_broadcast(&vcp->vc_statechg);
SMB_VC_UNLOCK(vcp);
- error = 0;
+ SMB_TRAN_DISCONNECT(vcp);
break;
}
/*
* Received something. Yea!
*/
- if (etime_count) {
- etime_count = 0;
+ etime_count = 0;
+ etime_idle = 0;
+ /*
+ * If we just completed a reconnect after logging
+ * "SMB server %s not responding" then log OK now.
+ */
+ if (vcp->iod_noresp) {
+ vcp->iod_noresp = B_FALSE;
zprintf(vcp->vc_zoneid, "SMB server %s OK\n",
vcp->vc_srvname);
+ }
- /* Was: smb_iod_notify_up(vcp); */
- if (fscb && fscb->fscb_up)
- smb_vc_walkshares(vcp, fscb->fscb_up);
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ error = smb2_iod_process(vcp, m);
+ } else {
+ error = smb1_iod_process(vcp, m);
}
/*
- * Have an SMB packet. The SMB header was
- * checked in smb_iod_recv1().
- * Find the request...
+ * Reconnect calls this in a loop with poll=TRUE
+ * We've received a response, so break now.
*/
- hp = mtod(m, uchar_t *);
- /*LINTED*/
- mid = letohs(SMB_HDRMID(hp));
- SMBIODEBUG("mid %04x\n", (uint_t)mid);
+ if (poll) {
+ error = 0;
+ break;
+ }
+ }
- rw_enter(&vcp->iod_rqlock, RW_READER);
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+ return (error);
+}
- if (rqp->sr_mid != mid)
- continue;
+/*
+ * Have what should be an SMB1 reply. Check and parse the header,
+ * then use the message ID to find the request this belongs to and
+ * post it on that request.
+ *
+ * Returns an error if the reader should give up.
+ * To be safe, error if we read garbage.
+ */
+static int
+smb1_iod_process(smb_vc_t *vcp, mblk_t *m)
+{
+ struct mdchain md;
+ struct smb_rq *rqp;
+ uint8_t cmd, sig[4];
+ uint16_t mid;
+ int err, skip;
+
+ m = m_pullup(m, SMB_HDRLEN);
+ if (m == NULL)
+ return (ENOMEM);
+
+ /*
+ * Note: Intentionally do NOT md_done(&md)
+ * because that would free the message and
+ * we just want to peek here.
+ */
+ md_initm(&md, m);
- DTRACE_PROBE2(smb_iod_recvrq,
- (smb_rq_t *), rqp, (mblk_t *), m);
- m_dumpm(m);
+ /*
+ * Check the SMB header version and get the MID.
+ *
+ * The header version should be SMB1 except when we're
+ * doing SMB1-to-SMB2 negotiation, in which case we may
+ * see an SMB2 header with message ID=0 (only allowed in
+ * vc_state == SMBIOD_ST_CONNECTED -- negotiationg).
+ */
+ err = md_get_mem(&md, sig, 4, MB_MSYSTEM);
+ if (err)
+ return (err);
+ if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') {
+ goto bad_hdr;
+ }
+ switch (sig[0]) {
+ case SMB_HDR_V1: /* SMB1 */
+ md_get_uint8(&md, &cmd);
+ /* Skip to and get the MID. At offset 5 now. */
+ skip = SMB_HDR_OFF_MID - 5;
+ md_get_mem(&md, NULL, skip, MB_MSYSTEM);
+ err = md_get_uint16le(&md, &mid);
+ if (err)
+ return (err);
+ break;
+ case SMB_HDR_V2: /* SMB2+ */
+ if (vcp->vc_state == SMBIOD_ST_CONNECTED) {
+ /*
+ * No need to look, can only be
+ * MID=0, cmd=negotiate
+ */
+ cmd = SMB_COM_NEGOTIATE;
+ mid = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+ bad_hdr:
+ default:
+ SMBIODEBUG("Bad SMB hdr\n");
+ m_freem(m);
+ return (EPROTO);
+ }
- SMBRQ_LOCK(rqp);
- if (rqp->sr_rp.md_top == NULL) {
- md_initm(&rqp->sr_rp, m);
+ /*
+ * Find the reqeuest and post the reply
+ */
+ rw_enter(&vcp->iod_rqlock, RW_READER);
+ TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+ if (rqp->sr_mid != mid)
+ continue;
+
+ DTRACE_PROBE2(iod_post_reply,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+ m_dumpm(m);
+
+ SMBRQ_LOCK(rqp);
+ if (rqp->sr_rp.md_top == NULL) {
+ md_initm(&rqp->sr_rp, m);
+ } else {
+ if (rqp->sr_flags & SMBR_MULTIPACKET) {
+ md_append_record(&rqp->sr_rp, m);
} else {
- if (rqp->sr_flags & SMBR_MULTIPACKET) {
- md_append_record(&rqp->sr_rp, m);
- } else {
- SMBRQ_UNLOCK(rqp);
- SMBSDEBUG("duplicate response %d "
- "(ignored)\n", mid);
- break;
- }
+ SMBRQ_UNLOCK(rqp);
+ rqp = NULL;
+ break;
}
- smb_iod_rqprocessed_LH(rqp, 0, 0);
- SMBRQ_UNLOCK(rqp);
- break;
}
+ smb_iod_rqprocessed_LH(rqp, 0, 0);
+ SMBRQ_UNLOCK(rqp);
+ break;
+ }
+ rw_exit(&vcp->iod_rqlock);
+
+ if (rqp == NULL) {
+ if (cmd != SMB_COM_ECHO) {
+ SMBSDEBUG("drop resp: MID 0x%04x\n", (uint_t)mid);
+ }
+ m_freem(m);
+ /*
+ * Keep going. It's possible this reply came
+ * after the request timed out and went away.
+ */
+ }
+ return (0);
+}
+
+/*
+ * Have what should be an SMB2 reply. Check and parse the header,
+ * then use the message ID to find the request this belongs to and
+ * post it on that request.
+ *
+ * We also want to apply any credit grant in this reply now,
+ * rather than waiting for the owner to wake up.
+ */
+static int
+smb2_iod_process(smb_vc_t *vcp, mblk_t *m)
+{
+ struct mdchain md;
+ struct smb_rq *rqp;
+ uint8_t sig[4];
+ mblk_t *next_m = NULL;
+ uint64_t message_id, async_id;
+ uint32_t flags, next_cmd_off, status;
+ uint16_t command, credits_granted;
+ int err;
- if (rqp == NULL) {
- int cmd = SMB_HDRCMD(hp);
+top:
+ m = m_pullup(m, SMB2_HDRLEN);
+ if (m == NULL)
+ return (ENOMEM);
- if (cmd != SMB_COM_ECHO)
- SMBSDEBUG("drop resp: mid %d, cmd %d\n",
- (uint_t)mid, cmd);
-/* smb_printrqlist(vcp); */
+ /*
+ * Note: Intentionally do NOT md_done(&md)
+ * because that would free the message and
+ * we just want to peek here.
+ */
+ md_initm(&md, m);
+
+ /*
+ * Check the SMB header. Must be SMB2
+ * (and later, could be SMB3 encrypted)
+ */
+ err = md_get_mem(&md, sig, 4, MB_MSYSTEM);
+ if (err)
+ return (err);
+ if (sig[1] != 'S' || sig[2] != 'M' || sig[3] != 'B') {
+ goto bad_hdr;
+ }
+ switch (sig[0]) {
+ case SMB_HDR_V2:
+ break;
+ case SMB_HDR_V3E:
+ /*
+ * Todo: If encryption enabled, decrypt the message
+ * and restart processing on the cleartext.
+ */
+ /* FALLTHROUGH */
+ bad_hdr:
+ default:
+ SMBIODEBUG("Bad SMB2 hdr\n");
+ m_freem(m);
+ return (EPROTO);
+ }
+
+ /*
+ * Parse the rest of the SMB2 header,
+ * skipping what we don't need.
+ */
+ md_get_uint32le(&md, NULL); /* length, credit_charge */
+ md_get_uint32le(&md, &status);
+ md_get_uint16le(&md, &command);
+ md_get_uint16le(&md, &credits_granted);
+ md_get_uint32le(&md, &flags);
+ md_get_uint32le(&md, &next_cmd_off);
+ md_get_uint64le(&md, &message_id);
+ if (flags & SMB2_FLAGS_ASYNC_COMMAND) {
+ md_get_uint64le(&md, &async_id);
+ } else {
+ /* PID, TID (not needed) */
+ async_id = 0;
+ }
+
+ /*
+ * If this is a compound reply, split it.
+ * Next must be 8-byte aligned.
+ */
+ if (next_cmd_off != 0) {
+ if ((next_cmd_off & 7) != 0)
+ SMBIODEBUG("Misaligned next cmd\n");
+ else
+ next_m = m_split(m, next_cmd_off, 1);
+ }
+
+ /*
+ * Apply the credit grant
+ */
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+ vcp->vc2_limit_message_id += credits_granted;
+
+ /*
+ * Find the reqeuest and post the reply
+ */
+ rw_downgrade(&vcp->iod_rqlock);
+ TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+ if (rqp->sr2_messageid != message_id)
+ continue;
+
+ DTRACE_PROBE2(iod_post_reply,
+ (smb_rq_t *), rqp, (mblk_t *), m);
+ m_dumpm(m);
+
+ /*
+ * If this is an interim response, just save the
+ * async ID but don't wakup the request.
+ * Don't need SMBRQ_LOCK for this.
+ */
+ if (status == NT_STATUS_PENDING && async_id != 0) {
+ rqp->sr2_rspasyncid = async_id;
m_freem(m);
+ break;
}
- rw_exit(&vcp->iod_rqlock);
+ SMBRQ_LOCK(rqp);
+ if (rqp->sr_rp.md_top == NULL) {
+ md_initm(&rqp->sr_rp, m);
+ } else {
+ SMBRQ_UNLOCK(rqp);
+ rqp = NULL;
+ break;
+ }
+ smb_iod_rqprocessed_LH(rqp, 0, 0);
+ SMBRQ_UNLOCK(rqp);
+ break;
}
+ rw_exit(&vcp->iod_rqlock);
- return (error);
+ if (rqp == NULL) {
+ if (command != SMB2_ECHO) {
+ SMBSDEBUG("drop resp: MID %lld\n",
+ (long long)message_id);
+ }
+ m_freem(m);
+ /*
+ * Keep going. It's possible this reply came
+ * after the request timed out and went away.
+ */
+ }
+
+ /*
+ * If we split a compound reply, continue with the
+ * next part of the compound.
+ */
+ if (next_m != NULL) {
+ m = next_m;
+ goto top;
+ }
+
+ return (0);
}
/*
@@ -529,126 +885,256 @@ smb_iod_recvall(struct smb_vc *vcp)
* The smb_smb_echo call uses SMBR_INTERNAL
* to avoid calling smb_iod_sendall().
*/
-int
-smb_iod_send_echo(smb_vc_t *vcp)
+static int
+smb_iod_send_echo(smb_vc_t *vcp, cred_t *cr)
{
smb_cred_t scred;
- int err;
+ int err, tmo = SMBNOREPLYWAIT;
- smb_credinit(&scred, NULL);
- err = smb_smb_echo(vcp, &scred, SMBNOREPLYWAIT);
+ ASSERT(vcp->iod_thr == curthread);
+
+ smb_credinit(&scred, cr);
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ err = smb2_smb_echo(vcp, &scred, tmo);
+ } else {
+ err = smb_smb_echo(vcp, &scred, tmo);
+ }
smb_credrele(&scred);
return (err);
}
/*
- * The IOD thread is now just a "reader",
- * so no more smb_iod_request(). Yea!
+ * Helper for smb1_iod_addrq, smb2_iod_addrq
+ * Returns zero if interrupted, else 1.
*/
+static int
+smb_iod_muxwait(smb_vc_t *vcp, boolean_t sig_ok)
+{
+ int rc;
+
+ SMB_VC_LOCK(vcp);
+ vcp->iod_muxwant++;
+ if (sig_ok) {
+ rc = cv_wait_sig(&vcp->iod_muxwait, &vcp->vc_lock);
+ } else {
+ cv_wait(&vcp->iod_muxwait, &vcp->vc_lock);
+ rc = 1;
+ }
+ vcp->iod_muxwant--;
+ SMB_VC_UNLOCK(vcp);
+
+ return (rc);
+}
/*
- * Place request in the queue, and send it now if possible.
+ * Place request in the queue, and send it.
* Called with no locks held.
+ *
+ * Called for SMB1 only
+ *
+ * The logic for how we limit active requests differs between
+ * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt.
*/
int
-smb_iod_addrq(struct smb_rq *rqp)
+smb1_iod_addrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
- int error, save_newrq;
+ uint16_t need;
+ boolean_t sig_ok =
+ (rqp->sr_flags & SMBR_NOINTR_SEND) == 0;
ASSERT(rqp->sr_cred);
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+ rqp->sr_owner = curthread;
+
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+
+recheck:
/*
- * State should be correct after the check in
- * smb_rq_enqueue(), but we dropped locks...
+ * Internal requests can be added in any state,
+ * but normal requests only in state active.
*/
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ rw_exit(&vcp->iod_rqlock);
return (ENOTCONN);
}
/*
- * Requests from the IOD itself are marked _INTERNAL,
- * and get some special treatment to avoid blocking
- * the reader thread (so we don't deadlock).
- * The request is not yet on the queue, so we can
- * modify it's state here without locks.
- * Only thing using this now is ECHO.
+ * If we're at the limit of active requests, block until
+ * enough requests complete so we can make ours active.
+ * Wakeup in smb_iod_removerq().
+ *
+ * Normal callers leave one slot free, so internal
+ * callers can have the last slot if needed.
*/
- rqp->sr_owner = curthread;
- if (rqp->sr_owner == vcp->iod_thr) {
- rqp->sr_flags |= SMBR_INTERNAL;
-
- /*
- * This is a request from the IOD thread.
- * Always send directly from this thread.
- * Note lock order: iod_rqlist, vc_sendlock
- */
+ need = 1;
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0)
+ need++;
+ if ((vcp->iod_muxcnt + need) > vcp->vc_maxmux) {
+ rw_exit(&vcp->iod_rqlock);
+ if (rqp->sr_flags & SMBR_INTERNAL)
+ return (EBUSY);
+ if (smb_iod_muxwait(vcp, sig_ok) == 0)
+ return (EINTR);
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link);
- rw_downgrade(&vcp->iod_rqlock);
+ goto recheck;
+ }
- /*
- * Note: iod_sendrq expects vc_sendlock,
- * so take that here, but carefully:
- * Never block the IOD thread here.
- */
- if (sema_tryp(&vcp->vc_sendlock) == 0) {
- SMBIODEBUG("sendlock busy\n");
- error = EAGAIN;
- } else {
- /* Have vc_sendlock */
- error = smb_iod_sendrq(rqp);
- sema_v(&vcp->vc_sendlock);
- }
+ /*
+ * Add this request to the active list and send it.
+ * For SMB2 we may have a sequence of compounded
+ * requests, in which case we must add them all.
+ * They're sent as a compound in smb2_iod_sendrq.
+ */
+ rqp->sr_mid = vcp->vc_next_mid++;
+ /* If signing, set the signing sequence numbers. */
+ if (vcp->vc_mackey != NULL && (rqp->sr_rqflags2 &
+ SMB_FLAGS2_SECURITY_SIGNATURE) != 0) {
+ rqp->sr_seqno = vcp->vc_next_seq++;
+ rqp->sr_rseqno = vcp->vc_next_seq++;
+ }
+ vcp->iod_muxcnt++;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
+ smb1_iod_sendrq(rqp);
- rw_exit(&vcp->iod_rqlock);
+ rw_exit(&vcp->iod_rqlock);
+ return (0);
+}
- /*
- * In the non-error case, _removerq
- * is done by either smb_rq_reply
- * or smb_iod_waitrq.
- */
- if (error)
- smb_iod_removerq(rqp);
+/*
+ * Place request in the queue, and send it.
+ * Called with no locks held.
+ *
+ * Called for SMB2 only.
+ *
+ * With SMB2 we have a range of valid message IDs, and we may
+ * only send requests when we can assign a message ID within
+ * the valid range. We may need to wait here for some active
+ * request to finish (and update vc2_limit_message_id) before
+ * we can get message IDs for our new request(s). Another
+ * difference is that the request sequence we're waiting to
+ * add here may require multipe message IDs, either due to
+ * either compounding or multi-credit requests. Therefore
+ * we need to wait for the availibility of how ever many
+ * message IDs are required by our request sequence.
+ */
+int
+smb2_iod_addrq(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ struct smb_rq *c_rqp; /* compound req */
+ uint16_t charge;
+ boolean_t sig_ok =
+ (rqp->sr_flags & SMBR_NOINTR_SEND) == 0;
- return (error);
+ ASSERT(rqp->sr_cred != NULL);
+ ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
+
+ /*
+ * Figure out the credit charges
+ * No multi-credit messages yet.
+ */
+ rqp->sr2_totalcreditcharge = rqp->sr2_creditcharge;
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ rqp->sr2_totalcreditcharge += c_rqp->sr2_creditcharge;
+ c_rqp = c_rqp->sr2_compound_next;
}
+ /*
+ * Internal request must not be compounded
+ * and should use exactly one credit.
+ */
+ if (rqp->sr_flags & SMBR_INTERNAL) {
+ if (rqp->sr2_compound_next != NULL) {
+ ASSERT(0);
+ return (EINVAL);
+ }
+ }
+
+ rqp->sr_owner = curthread;
+
rw_enter(&vcp->iod_rqlock, RW_WRITER);
- TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
- /* iod_rqlock/WRITER protects iod_newrq */
- save_newrq = vcp->iod_newrq;
- vcp->iod_newrq++;
+recheck:
+ /*
+ * Internal requests can be added in any state,
+ * but normal requests only in state active.
+ */
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0 &&
+ vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+ SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+ rw_exit(&vcp->iod_rqlock);
+ return (ENOTCONN);
+ }
- rw_exit(&vcp->iod_rqlock);
+ /*
+ * If we're at the limit of active requests, block until
+ * enough requests complete so we can make ours active.
+ * Wakeup in smb_iod_removerq().
+ *
+ * Normal callers leave one slot free, so internal
+ * callers can have the last slot if needed.
+ */
+ charge = rqp->sr2_totalcreditcharge;
+ if ((rqp->sr_flags & SMBR_INTERNAL) == 0)
+ charge++;
+ if ((vcp->vc2_next_message_id + charge) >
+ vcp->vc2_limit_message_id) {
+ rw_exit(&vcp->iod_rqlock);
+ if (rqp->sr_flags & SMBR_INTERNAL)
+ return (EBUSY);
+ if (smb_iod_muxwait(vcp, sig_ok) == 0)
+ return (EINTR);
+ rw_enter(&vcp->iod_rqlock, RW_WRITER);
+ goto recheck;
+ }
/*
- * Now send any requests that need to be sent,
- * including the one we just put on the list.
- * Only the thread that found iod_newrq==0
- * needs to run the send loop.
+ * Add this request to the active list and send it.
+ * For SMB2 we may have a sequence of compounded
+ * requests, in which case we must add them all.
+ * They're sent as a compound in smb2_iod_sendrq.
*/
- if (save_newrq == 0)
- smb_iod_sendall(vcp);
+ rqp->sr2_messageid = vcp->vc2_next_message_id;
+ vcp->vc2_next_message_id += rqp->sr2_creditcharge;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
+
+ c_rqp = rqp->sr2_compound_next;
+ while (c_rqp != NULL) {
+ c_rqp->sr2_messageid = vcp->vc2_next_message_id;
+ vcp->vc2_next_message_id += c_rqp->sr2_creditcharge;
+ TAILQ_INSERT_TAIL(&vcp->iod_rqlist, c_rqp, sr_link);
+ c_rqp = c_rqp->sr2_compound_next;
+ }
+ smb2_iod_sendrq(rqp);
+
+ rw_exit(&vcp->iod_rqlock);
return (0);
}
/*
* Mark an SMBR_MULTIPACKET request as
* needing another send. Similar to the
- * "normal" part of smb_iod_addrq.
+ * "normal" part of smb1_iod_addrq.
+ * Only used by SMB1
*/
int
-smb_iod_multirq(struct smb_rq *rqp)
+smb1_iod_multirq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
- int save_newrq;
ASSERT(rqp->sr_flags & SMBR_MULTIPACKET);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ ASSERT("!SMB2?");
+ return (EINVAL);
+ }
+
if (rqp->sr_flags & SMBR_INTERNAL)
return (EINVAL);
@@ -661,32 +1147,36 @@ smb_iod_multirq(struct smb_rq *rqp)
/* Already on iod_rqlist, just reset state. */
rqp->sr_state = SMBRQ_NOTSENT;
-
- /* iod_rqlock/WRITER protects iod_newrq */
- save_newrq = vcp->iod_newrq;
- vcp->iod_newrq++;
+ smb1_iod_sendrq(rqp);
rw_exit(&vcp->iod_rqlock);
- /*
- * Now send any requests that need to be sent,
- * including the one we just marked NOTSENT.
- * Only the thread that found iod_newrq==0
- * needs to run the send loop.
- */
- if (save_newrq == 0)
- smb_iod_sendall(vcp);
-
return (0);
}
-
+/*
+ * Remove a request from the active list, and
+ * wake up requests waiting to go active.
+ *
+ * Shared by SMB1 + SMB2
+ *
+ * The logic for how we limit active requests differs between
+ * SMB1 and SMB2. With SMB1 it's a simple counter ioc_muxcnt.
+ * With SMB2 we have a range of valid message IDs, and when we
+ * retire the oldest request we need to keep track of what is
+ * now the oldest message ID. In both cases, after we take a
+ * request out of the list here, we should be able to wake up
+ * a request waiting to get in the active list.
+ */
void
smb_iod_removerq(struct smb_rq *rqp)
{
+ struct smb_rq *rqp2;
struct smb_vc *vcp = rqp->sr_vc;
+ boolean_t was_head = B_FALSE;
rw_enter(&vcp->iod_rqlock, RW_WRITER);
+
#ifdef QUEUEDEBUG
/*
* Make sure we have not already removed it.
@@ -695,30 +1185,47 @@ smb_iod_removerq(struct smb_rq *rqp)
*/
ASSERT(rqp->sr_link.tqe_next != (void *)1L);
#endif
+
+ if (TAILQ_FIRST(&vcp->iod_rqlist) == rqp)
+ was_head = B_TRUE;
TAILQ_REMOVE(&vcp->iod_rqlist, rqp, sr_link);
- rw_exit(&vcp->iod_rqlock);
-}
+ if (vcp->vc_flags & SMBV_SMB2) {
+ rqp2 = TAILQ_FIRST(&vcp->iod_rqlist);
+ if (was_head && rqp2 != NULL) {
+ /* Do we still need this? */
+ vcp->vc2_oldest_message_id =
+ rqp2->sr2_messageid;
+ }
+ } else {
+ ASSERT(vcp->iod_muxcnt > 0);
+ vcp->iod_muxcnt--;
+ }
+ rw_exit(&vcp->iod_rqlock);
+ /*
+ * If there are requests waiting for "mux" slots,
+ * wake one.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->iod_muxwant != 0)
+ cv_signal(&vcp->iod_muxwait);
+ SMB_VC_UNLOCK(vcp);
+}
/*
* Wait for a request to complete.
- *
- * For normal requests, we need to deal with
- * ioc_muxcnt dropping below vc_maxmux by
- * making arrangements to send more...
*/
int
smb_iod_waitrq(struct smb_rq *rqp)
{
struct smb_vc *vcp = rqp->sr_vc;
clock_t tr, tmo1, tmo2;
- int error, rc;
+ int error;
if (rqp->sr_flags & SMBR_INTERNAL) {
- ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
- smb_iod_removerq(rqp);
- return (EAGAIN);
+ /* XXX - Do we ever take this path now? */
+ return (smb_iod_waitrq_int(rqp));
}
/*
@@ -730,35 +1237,6 @@ smb_iod_waitrq(struct smb_rq *rqp)
SMBRQ_LOCK(rqp);
/*
- * First, wait for the request to be sent. Normally the send
- * has already happened by the time we get here. However, if
- * we have more than maxmux entries in the request list, our
- * request may not be sent until other requests complete.
- * The wait in this case is due to local I/O demands, so
- * we don't want the server response timeout to apply.
- *
- * If a request is allowed to interrupt this wait, then the
- * request is cancelled and never sent OTW. Some kinds of
- * requests should never be cancelled (i.e. close) and those
- * are marked SMBR_NOINTR_SEND so they either go eventually,
- * or a connection close will terminate them with ENOTCONN.
- */
- while (rqp->sr_state == SMBRQ_NOTSENT) {
- rqp->sr_flags |= SMBR_SENDWAIT;
- if (rqp->sr_flags & SMBR_NOINTR_SEND) {
- cv_wait(&rqp->sr_cond, &rqp->sr_lock);
- rc = 1;
- } else
- rc = cv_wait_sig(&rqp->sr_cond, &rqp->sr_lock);
- rqp->sr_flags &= ~SMBR_SENDWAIT;
- if (rc == 0) {
- SMBIODEBUG("EINTR in sendwait, rqp=%p\n", rqp);
- error = EINTR;
- goto out;
- }
- }
-
- /*
* The request has been sent. Now wait for the response,
* with the timeout specified for this request.
* Compute all the deadlines now, so we effectively
@@ -791,17 +1269,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE
DTRACE_PROBE1(smb_iod_waitrq1,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (still waiting).\n", vcp->vc_srvname,
- rqp->sr_mid, smb_timo_notice);
-#endif
}
}
@@ -820,17 +1289,8 @@ smb_iod_waitrq(struct smb_rq *rqp)
goto out;
}
if (tr < 0) {
-#ifdef DTRACE_PROBE
DTRACE_PROBE1(smb_iod_waitrq2,
(smb_rq_t *), rqp);
-#endif
-#ifdef NOT_YET
- /* Want this to go ONLY to the user. */
- uprintf("SMB server %s has not responded"
- " to request %d after %d seconds..."
- " (giving up).\n", vcp->vc_srvname,
- rqp->sr_mid, rqp->sr_timo);
-#endif
error = ETIME;
goto out;
}
@@ -849,13 +1309,34 @@ out:
if ((rqp->sr_flags & SMBR_MULTIPACKET) == 0)
smb_iod_removerq(rqp);
- /*
- * Some request has been completed.
- * If we reached the mux limit,
- * re-run the send loop...
- */
- if (vcp->iod_muxfull)
- smb_iod_sendall(vcp);
+ return (error);
+}
+
+/*
+ * Internal variant of smb_iod_waitrq(), for use in
+ * requests run by the IOD (reader) thread itself.
+ * Block only long enough to receive one reply.
+ */
+int
+smb_iod_waitrq_int(struct smb_rq *rqp)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int timeleft = rqp->sr_timo;
+ int error;
+
+ ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
+again:
+ error = smb_iod_recvall(vcp, B_TRUE);
+ if (error == ETIME) {
+ /* We waited SMB_NBTIMO sec. */
+ timeleft -= SMB_NBTIMO;
+ if (timeleft > 0)
+ goto again;
+ }
+
+ smb_iod_removerq(rqp);
+ if (rqp->sr_state != SMBRQ_NOTIFIED)
+ error = ETIME;
return (error);
}
@@ -885,79 +1366,298 @@ smb_iod_shutdown_share(struct smb_share *ssp)
}
/*
- * Send all requests that need sending.
- * Called from _addrq, _multirq, _waitrq
+ * Ioctl functions called by the user-level I/O Deamon (IOD)
+ * to bring up and service a connection to some SMB server.
*/
-void
-smb_iod_sendall(smb_vc_t *vcp)
+
+/*
+ * Handle ioctl SMBIOC_IOD_CONNECT
+ */
+int
+nsmb_iod_connect(struct smb_vc *vcp, cred_t *cr)
{
- struct smb_rq *rqp;
- int error, muxcnt;
+ int err, val;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ cmn_err(CE_NOTE, "iod_connect: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
/*
- * Clear "newrq" to make sure threads adding
- * new requests will run this function again.
+ * Putting a TLI endpoint back in the right state for a new
+ * connection is a bit tricky. In theory, this could be:
+ * SMB_TRAN_DISCONNECT(vcp);
+ * SMB_TRAN_UNBIND(vcp);
+ * but that method often results in TOUTSTATE errors.
+ * It's easier to just close it and open a new endpoint.
*/
- rw_enter(&vcp->iod_rqlock, RW_WRITER);
- vcp->iod_newrq = 0;
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_tdata)
+ SMB_TRAN_DONE(vcp);
+ err = SMB_TRAN_CREATE(vcp, cr);
+ SMB_VC_UNLOCK(vcp);
+ if (err != 0)
+ return (err);
/*
- * We only read iod_rqlist, so downgrade rwlock.
- * This allows the IOD to handle responses while
- * some requesting thread may be blocked in send.
+ * Set various options on this endpoint.
+ * Keep going in spite of errors.
*/
- rw_downgrade(&vcp->iod_rqlock);
+ val = smb_tcpsndbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_SNDBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt SNDBUF, err=%d", err);
+ }
+ val = smb_tcprcvbuf;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_RCVBUF, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt RCVBUF, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_KEEPALIVE, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt KEEPALIVE, err=%d", err);
+ }
+ val = 1;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_NODELAY, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP_NODELAY, err=%d", err);
+ }
+ val = smb_connect_timeout * 1000;
+ err = SMB_TRAN_SETPARAM(vcp, SMBTP_TCP_CON_TMO, &val);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: setopt TCP con tmo, err=%d", err);
+ }
/*
- * Serialize to prevent multiple senders.
- * Note lock order: iod_rqlock, vc_sendlock
+ * Bind and connect
*/
- sema_p(&vcp->vc_sendlock);
+ err = SMB_TRAN_BIND(vcp, NULL);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "iod_connect: t_kbind: err=%d", err);
+ /* Continue on and try connect. */
+ }
+ err = SMB_TRAN_CONNECT(vcp, &vcp->vc_srvaddr.sa);
+ /*
+ * No cmn_err here, as connect failures are normal, i.e.
+ * when a server has multiple addresses and only some are
+ * routed for us. (libsmbfs tries them all)
+ */
+ if (err == 0) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_CONNECTED);
+ SMB_VC_UNLOCK(vcp);
+ } /* else stay in state reconnect */
+
+ return (err);
+}
+
+/*
+ * Handle ioctl SMBIOC_IOD_NEGOTIATE
+ * Do the whole SMB1/SMB2 negotiate
+ *
+ * This is where we send our first request to the server.
+ * If this is the first time we're talking to this server,
+ * (meaning not a reconnect) then we don't know whether
+ * the server supports SMB2, so we need to use the weird
+ * SMB1-to-SMB2 negotiation. That's where we send an SMB1
+ * negotiate including dialect "SMB 2.???" and if the
+ * server supports SMB2 we get an SMB2 reply -- Yes, an
+ * SMB2 reply to an SMB1 request. A strange protocol...
+ *
+ * If on the other hand we already know the server supports
+ * SMB2 (because this is a reconnect) or if the client side
+ * has disabled SMB1 entirely, we'll skip the SMB1 part.
+ */
+int
+nsmb_iod_negotiate(struct smb_vc *vcp, cred_t *cr)
+{
+ struct smb_sopt *sv = &vcp->vc_sopt;
+ smb_cred_t scred;
+ int err = 0;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ smb_credinit(&scred, cr);
+
+ if (vcp->vc_state != SMBIOD_ST_CONNECTED) {
+ cmn_err(CE_NOTE, "iod_negotiate: bad state %d", vcp->vc_state);
+ err = EINVAL;
+ goto out;
+ }
+
+ if (vcp->vc_maxver == 0 || vcp->vc_minver > vcp->vc_maxver) {
+ err = EINVAL;
+ goto out;
+ }
/*
- * Walk the list of requests and send when possible.
- * We avoid having more than vc_maxmux requests
- * outstanding to the server by traversing only
- * vc_maxmux entries into this list. Simple!
+ * (Re)init negotiated values
*/
- ASSERT(vcp->vc_maxmux > 0);
- error = muxcnt = 0;
- TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+ bzero(sv, sizeof (*sv));
+ vcp->vc2_next_message_id = 0;
+ vcp->vc2_limit_message_id = 1;
+ vcp->vc2_session_id = 0;
+ vcp->vc_next_seq = 0;
- if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- error = ENOTCONN; /* stop everything! */
- break;
- }
+ /*
+ * If this was reconnect, get rid of the old MAC key
+ * and session key.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_mackey != NULL) {
+ kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+ vcp->vc_mackey = NULL;
+ vcp->vc_mackeylen = 0;
+ }
+ if (vcp->vc_ssnkey != NULL) {
+ kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
+ vcp->vc_ssnkey = NULL;
+ vcp->vc_ssnkeylen = 0;
+ }
+ SMB_VC_UNLOCK(vcp);
- if (rqp->sr_state == SMBRQ_NOTSENT) {
- error = smb_iod_sendrq(rqp);
- if (error)
- break;
+ /*
+ * If this is not an SMB2 reconect (SMBV_SMB2 not set),
+ * and if SMB1 is enabled, do SMB1 neogotiate. Then
+ * if either SMB1-to-SMB2 negotiate tells us we should
+ * switch to SMB2, or the local configuration has
+ * disabled SMB1, set the SMBV_SMB2 flag.
+ *
+ * Note that vc_maxver is handled in smb_smb_negotiate
+ * so we never get sv_proto == SMB_DIALECT_SMB2_FF when
+ * the local configuration disables SMB2, and therefore
+ * we won't set the SMBV_SMB2 flag.
+ */
+ if ((vcp->vc_flags & SMBV_SMB2) == 0) {
+ if (vcp->vc_minver < SMB2_DIALECT_BASE) {
+ /*
+ * SMB1 is enabled
+ */
+ err = smb_smb_negotiate(vcp, &scred);
+ if (err != 0)
+ goto out;
}
-
- if (++muxcnt == vcp->vc_maxmux) {
- SMBIODEBUG("muxcnt == vc_maxmux\n");
- break;
+ /*
+ * If SMB1-to-SMB2 negotiate told us we should
+ * switch to SMB2, or if the local configuration
+ * disables SMB1, set the SMB2 flag.
+ */
+ if (sv->sv_proto == SMB_DIALECT_SMB2_FF ||
+ vcp->vc_minver >= SMB2_DIALECT_BASE) {
+ /*
+ * Switch this VC to SMB2.
+ */
+ SMB_VC_LOCK(vcp);
+ vcp->vc_flags |= SMBV_SMB2;
+ SMB_VC_UNLOCK(vcp);
}
+ }
+ /*
+ * If this is an SMB2 reconnect (SMBV_SMB2 was set before this
+ * function was called), or SMB1-to-SMB2 negotiate indicated
+ * we should switch to SMB2, or we have SMB1 disabled (both
+ * cases set SMBV_SMB2 above), then do SMB2 negotiate.
+ */
+ if ((vcp->vc_flags & SMBV_SMB2) != 0) {
+ err = smb2_smb_negotiate(vcp, &scred);
}
+out:
+ if (err == 0) {
+ SMB_VC_LOCK(vcp);
+ smb_iod_newstate(vcp, SMBIOD_ST_NEGOTIATED);
+ SMB_VC_UNLOCK(vcp);
+ }
/*
- * If we have vc_maxmux requests outstanding,
- * arrange for _waitrq to call _sendall as
- * requests are completed.
+ * (else) leave state as it was.
+ * User-level will either close this handle (if connecting
+ * for the first time) or call rcfail and then try again.
*/
- vcp->iod_muxfull =
- (muxcnt < vcp->vc_maxmux) ? 0 : 1;
- sema_v(&vcp->vc_sendlock);
- rw_exit(&vcp->iod_rqlock);
+ smb_credrele(&scred);
+
+ return (err);
}
+/*
+ * Handle ioctl SMBIOC_IOD_SSNSETUP
+ * Do either SMB1 or SMB2 session setup (one call/reply)
+ */
int
-smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
+nsmb_iod_ssnsetup(struct smb_vc *vcp, cred_t *cr)
{
- struct file *fp = NULL;
+ smb_cred_t scred;
+ int err;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ switch (vcp->vc_state) {
+ case SMBIOD_ST_NEGOTIATED:
+ case SMBIOD_ST_AUTHCONT:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ smb_credinit(&scred, cr);
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_smb_ssnsetup(vcp, &scred);
+ else
+ err = smb_smb_ssnsetup(vcp, &scred);
+ smb_credrele(&scred);
+
+ SMB_VC_LOCK(vcp);
+ switch (err) {
+ case 0:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHOK);
+ break;
+ case EINPROGRESS: /* MORE_PROCESSING_REQUIRED */
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHCONT);
+ break;
+ default:
+ smb_iod_newstate(vcp, SMBIOD_ST_AUTHFAIL);
+ break;
+ }
+ SMB_VC_UNLOCK(vcp);
+
+ return (err);
+}
+
+static int
+smb_iod_logoff(struct smb_vc *vcp, cred_t *cr)
+{
+ smb_cred_t scred;
+ int err;
+
+ ASSERT(vcp->iod_thr == curthread);
+
+ smb_credinit(&scred, cr);
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_smb_logoff(vcp, &scred);
+ else
+ err = smb_smb_logoff(vcp, &scred);
+ smb_credrele(&scred);
+
+ return (err);
+}
+
+/*
+ * Handle ioctl SMBIOC_IOD_WORK
+ *
+ * The smbiod agent calls this after authentication to become
+ * the reader for this session, so long as that's possible.
+ * This should only return non-zero if we want that agent to
+ * give up on this VC permanently.
+ */
+/* ARGSUSED */
+int
+smb_iod_vc_work(struct smb_vc *vcp, int flags, cred_t *cr)
+{
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
int err = 0;
/*
@@ -967,19 +1667,57 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
ASSERT(vcp->iod_thr == curthread);
/*
- * Get the network transport file pointer,
- * and "loan" it to our transport module.
+ * Should be in state...
*/
- if ((fp = getf(vcp->vc_tran_fd)) == NULL) {
- err = EBADF;
- goto out;
+ if (vcp->vc_state != SMBIOD_ST_AUTHOK) {
+ cmn_err(CE_NOTE, "iod_vc_work: bad state %d", vcp->vc_state);
+ return (EINVAL);
}
- if ((err = SMB_TRAN_LOAN_FP(vcp, fp, cr)) != 0)
- goto out;
/*
- * In case of reconnect, tell any enqueued requests
- * then can GO!
+ * Update the session key and initialize SMB signing.
+ *
+ * This implementation does not use multiple SMB sessions per
+ * TCP connection (where only the first session key is used)
+ * so we always have a new session key here. Sanity check the
+ * length from user space. Normally 16 or 32.
+ */
+ if (wk->wk_u_ssnkey_len > 1024) {
+ cmn_err(CE_NOTE, "iod_vc_work: ssn key too long");
+ return (EINVAL);
+ }
+
+ ASSERT(vcp->vc_ssnkey == NULL);
+ SMB_VC_LOCK(vcp);
+ if (wk->wk_u_ssnkey_len != 0 &&
+ wk->wk_u_ssnkey_buf.lp_ptr != NULL) {
+ vcp->vc_ssnkeylen = wk->wk_u_ssnkey_len;
+ vcp->vc_ssnkey = kmem_alloc(vcp->vc_ssnkeylen, KM_SLEEP);
+ if (ddi_copyin(wk->wk_u_ssnkey_buf.lp_ptr,
+ vcp->vc_ssnkey, vcp->vc_ssnkeylen, flags) != 0) {
+ err = EFAULT;
+ }
+ }
+ SMB_VC_UNLOCK(vcp);
+ if (err)
+ return (err);
+
+ /*
+ * If we have a session key, derive the MAC key for SMB signing.
+ * If this was a NULL session, we might have no session key.
+ */
+ ASSERT(vcp->vc_mackey == NULL);
+ if (vcp->vc_ssnkey != NULL) {
+ if (vcp->vc_flags & SMBV_SMB2)
+ err = smb2_sign_init(vcp);
+ else
+ err = smb_sign_init(vcp);
+ if (err != 0)
+ return (err);
+ }
+
+ /*
+ * Tell any enqueued requests they can start.
*/
SMB_VC_LOCK(vcp);
vcp->vc_genid++; /* possibly new connection */
@@ -998,9 +1736,11 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
smb_vc_walkshares(vcp, fscb->fscb_connect);
/*
- * Run the "reader" loop.
+ * Run the "reader" loop. An error return here is normal
+ * (i.e. when we need to reconnect) so ignore errors.
+ * Note: This call updates the vc_state.
*/
- err = smb_iod_recvall(vcp);
+ (void) smb_iod_recvall(vcp, B_FALSE);
/*
* The reader loop returned, so we must have a
@@ -1021,26 +1761,24 @@ smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
*/
smb_iod_invrq(vcp);
-out:
- /* Recall the file descriptor loan. */
- (void) SMB_TRAN_LOAN_FP(vcp, NULL, cr);
- if (fp != NULL) {
- releasef(vcp->vc_tran_fd);
- }
-
return (err);
}
/*
- * Wait around for someone to ask to use this VC.
- * If the VC has only the IOD reference, then
- * wait only a minute or so, then drop it.
+ * Handle ioctl SMBIOC_IOD_IDLE
+ *
+ * Wait around for someone to ask to use this VC again after the
+ * TCP session has closed. When one of the connected trees adds a
+ * request, smb_iod_reconnect will set vc_state to RECONNECT and
+ * wake this cv_wait. When a VC ref. goes away in smb_vc_rele,
+ * that also signals this wait so we can re-check whether we
+ * now hold the last ref. on this VC (and can destroy it).
*/
int
smb_iod_vc_idle(struct smb_vc *vcp)
{
- clock_t tr, delta = SEC_TO_TICK(15);
int err = 0;
+ boolean_t destroy = B_FALSE;
/*
* This is called by the one-and-only
@@ -1048,30 +1786,50 @@ smb_iod_vc_idle(struct smb_vc *vcp)
*/
ASSERT(vcp->iod_thr == curthread);
+ /*
+ * Should be in state...
+ */
+ if (vcp->vc_state != SMBIOD_ST_IDLE &&
+ vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ cmn_err(CE_NOTE, "iod_vc_idle: bad state %d", vcp->vc_state);
+ return (EINVAL);
+ }
+
SMB_VC_LOCK(vcp);
- while (vcp->vc_state == SMBIOD_ST_IDLE) {
- tr = cv_reltimedwait_sig(&vcp->iod_idle, &vcp->vc_lock,
- delta, TR_CLOCK_TICK);
- if (tr == 0) {
+
+ while (vcp->vc_state == SMBIOD_ST_IDLE &&
+ vcp->vc_co.co_usecount > 1) {
+ if (cv_wait_sig(&vcp->iod_idle, &vcp->vc_lock) == 0) {
err = EINTR;
break;
}
- if (tr < 0) {
- /* timeout */
- if (vcp->vc_co.co_usecount == 1) {
- /* Let this IOD terminate. */
- smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
- /* nobody to cv_broadcast */
- break;
- }
- }
}
+ if (vcp->vc_state == SMBIOD_ST_IDLE &&
+ vcp->vc_co.co_usecount == 1) {
+ /*
+ * We were woken because we now have the last ref.
+ * Arrange for this VC to be destroyed now.
+ * Set the "GONE" flag while holding the lock,
+ * to prevent a race with new references.
+ * The destroy happens after unlock.
+ */
+ vcp->vc_flags |= SMBV_GONE;
+ destroy = B_TRUE;
+ }
+
SMB_VC_UNLOCK(vcp);
+ if (destroy) {
+ /* This sets vc_state = DEAD */
+ smb_iod_disconnect(vcp);
+ }
+
return (err);
}
/*
+ * Handle ioctl SMBIOC_IOD_RCFAIL
+ *
* After a failed reconnect attempt, smbiod will
* call this to make current requests error out.
*/
@@ -1086,10 +1844,6 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
* IOD thread for this VC.
*/
ASSERT(vcp->iod_thr == curthread);
-
- if (vcp->vc_state != SMBIOD_ST_RECONNECT)
- return (EINVAL);
-
SMB_VC_LOCK(vcp);
smb_iod_newstate(vcp, SMBIOD_ST_RCFAILED);
@@ -1105,8 +1859,18 @@ smb_iod_vc_rcfail(struct smb_vc *vcp)
if (tr == 0)
err = EINTR;
- smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
- cv_broadcast(&vcp->vc_statechg);
+ /*
+ * Normally we'll switch to state IDLE here. However,
+ * if something called smb_iod_reconnect() while we were
+ * waiting above, we'll be in in state reconnect already.
+ * In that case, keep state RECONNECT, so we essentially
+ * skip transition through state IDLE that would normally
+ * happen next.
+ */
+ if (vcp->vc_state != SMBIOD_ST_RECONNECT) {
+ smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
+ cv_broadcast(&vcp->vc_statechg);
+ }
SMB_VC_UNLOCK(vcp);
@@ -1127,11 +1891,17 @@ again:
switch (vcp->vc_state) {
case SMBIOD_ST_IDLE:
+ /* Tell the IOD thread it's no longer IDLE. */
smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
cv_signal(&vcp->iod_idle);
/* FALLTHROUGH */
case SMBIOD_ST_RECONNECT:
+ case SMBIOD_ST_CONNECTED:
+ case SMBIOD_ST_NEGOTIATED:
+ case SMBIOD_ST_AUTHCONT:
+ case SMBIOD_ST_AUTHOK:
+ /* Wait for the VC state to become ACTIVE. */
rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock);
if (rv == 0) {
err = EINTR;
@@ -1143,6 +1913,7 @@ again:
err = 0; /* success! */
break;
+ case SMBIOD_ST_AUTHFAIL:
case SMBIOD_ST_RCFAILED:
case SMBIOD_ST_DEAD:
default:
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
index 712acb6f3b..aef9e70e27 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h
@@ -1,16 +1,35 @@
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2001 - 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
/*
* Code corresponding to smb_apple.h
- * XXX: Could merge this into smb_subr.h
- * as long as that doesn't break smbfs
*/
#ifndef _NETSMB_SMB_OSDEP_H_
#define _NETSMB_SMB_OSDEP_H_
#ifndef PRIVSYM
-#define PRIVSYM
+#define PRIVSYM
#endif
#ifndef min
@@ -65,8 +84,14 @@ typedef uint32_t u_int32_t;
typedef uint16_t u_int16_t;
typedef uint8_t u_int8_t;
-typedef const char * c_caddr_t;
-typedef uint64_t user_addr_t;
+typedef const char *c_caddr_t;
+typedef uint64_t user_addr_t;
+typedef ssize_t user_ssize_t;
+typedef size_t user_size_t;
+
+#ifdef _FAKE_KERNEL
+#define ddi_get_cred() CRED()
+#endif
/*
* Time related calls.
@@ -75,7 +100,7 @@ typedef uint64_t user_addr_t;
/* BEGIN CSTYLED */
#define timespeccmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
- ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
+ ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
/* END CSTYLED */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
index f4ebf9a573..4a44e36e89 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMB_PASS_H
@@ -44,14 +46,13 @@ typedef struct smb_passid {
zoneid_t zoneid; /* Future Use */
char *srvdom; /* Windows Domain (or server) */
char *username; /* Windows User name */
- uchar_t lmhash[SMBIOC_HASH_SZ];
- uchar_t nthash[SMBIOC_HASH_SZ];
+ uchar_t lmhash[SMBIOC_HASH_SZ];
+ uchar_t nthash[SMBIOC_HASH_SZ];
} smb_passid_t;
/* Called from smb_dev.c */
void smb_pkey_init(void);
void smb_pkey_fini(void);
int smb_pkey_idle(void);
-int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
#endif /* _SMB_PASS_H */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
index 997b7318dd..1c62850599 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c
@@ -34,6 +34,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -51,10 +53,12 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
/*
* How long to wait before restarting a request (after reconnect)
@@ -69,9 +73,8 @@
static int smb_rq_reply(struct smb_rq *rqp);
+static int smb_rq_parsehdr(struct smb_rq *rqp);
static int smb_rq_enqueue(struct smb_rq *rqp);
-static int smb_rq_getenv(struct smb_connobj *layer,
- struct smb_vc **vcpp, struct smb_share **sspp);
static int smb_rq_new(struct smb_rq *rqp, uchar_t cmd);
static int smb_t2_reply(struct smb_t2rq *t2p);
static int smb_nt_reply(struct smb_ntrq *ntp);
@@ -147,7 +150,6 @@ smb_rq_init(struct smb_rq *rqp, struct smb_connobj *co, uchar_t cmd,
rqp->sr_rexmit = SMBMAXRESTARTS;
rqp->sr_cred = scred; /* Note: ref hold done by caller. */
- rqp->sr_pid = (uint16_t)ddi_get_pid();
error = smb_rq_new(rqp, cmd);
return (error);
@@ -163,7 +165,6 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
ASSERT(rqp != NULL);
rqp->sr_sendcnt = 0;
- rqp->sr_cmd = cmd;
mb_done(mbp);
md_done(&rqp->sr_rp);
@@ -171,18 +172,42 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
if (error)
return (error);
- /*
- * Is this the right place to save the flags?
- */
- rqp->sr_rqflags = vcp->vc_hflags;
- rqp->sr_rqflags2 = vcp->vc_hflags2;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ /*
+ * SMB2 request initialization
+ */
+ rqp->sr2_command = cmd;
+ rqp->sr2_creditcharge = 1;
+ rqp->sr2_creditsrequested = 1;
+ rqp->sr_pid = 0xFEFF; /* Made up, just like Windows */
+ rqp->sr2_rqflags = 0;
+ if ((vcp->vc_flags & SMBV_SIGNING) != 0 &&
+ vcp->vc_mackey != NULL) {
+ rqp->sr2_rqflags |= SMB2_FLAGS_SIGNED;
+ }
- /*
- * The SMB header is filled in later by
- * smb_rq_fillhdr (see below)
- * Just reserve space here.
- */
- mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+ /*
+ * The SMB2 header is filled in later by
+ * smb2_rq_fillhdr (see smb2_rq.c)
+ * Just reserve space here.
+ */
+ mb_put_mem(mbp, NULL, SMB2_HDRLEN, MB_MZERO);
+ } else {
+ /*
+ * SMB1 request initialization
+ */
+ rqp->sr_cmd = cmd;
+ rqp->sr_pid = (uint32_t)ddi_get_pid();
+ rqp->sr_rqflags = vcp->vc_hflags;
+ rqp->sr_rqflags2 = vcp->vc_hflags2;
+
+ /*
+ * The SMB header is filled in later by
+ * smb_rq_fillhdr (see below)
+ * Just reserve space here.
+ */
+ mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+ }
return (0);
}
@@ -190,7 +215,7 @@ smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
/*
* Given a request with it's body already composed,
* rewind to the start and fill in the SMB header.
- * This is called after the request is enqueued,
+ * This is called when the request is enqueued,
* so we have the final MID, seq num. etc.
*/
void
@@ -217,7 +242,7 @@ smb_rq_fillhdr(struct smb_rq *rqp)
mb_put_mem(mbp, NULL, 8, MB_MZERO); /* MAC sig. (later) */
mb_put_uint16le(mbp, 0); /* reserved */
mb_put_uint16le(mbp, rqp->sr_rqtid);
- mb_put_uint16le(mbp, rqp->sr_pid);
+ mb_put_uint16le(mbp, (uint16_t)rqp->sr_pid);
mb_put_uint16le(mbp, rqp->sr_rquid);
mb_put_uint16le(mbp, rqp->sr_mid);
@@ -281,6 +306,8 @@ smb_rq_enqueue(struct smb_rq *rqp)
struct smb_share *ssp = rqp->sr_share;
int error = 0;
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+
/*
* Normal requests may initiate a reconnect,
* and/or wait for state changes to finish.
@@ -325,7 +352,71 @@ smb_rq_enqueue(struct smb_rq *rqp)
ok_out:
rqp->sr_rquid = vcp->vc_smbuid;
rqp->sr_rqtid = ssp ? ssp->ss_tid : SMB_TID_UNKNOWN;
- error = smb_iod_addrq(rqp);
+ error = smb1_iod_addrq(rqp);
+
+ return (error);
+}
+
+/*
+ * Used by the IOD thread during connection setup,
+ * and for smb_echo after network timeouts. Note that
+ * unlike smb_rq_simple, callers must check sr_error.
+ */
+int
+smb_rq_internal(struct smb_rq *rqp, int timeout)
+{
+ struct smb_vc *vcp = rqp->sr_vc;
+ int error;
+
+ ASSERT((vcp->vc_flags & SMBV_SMB2) == 0);
+
+ rqp->sr_flags &= ~SMBR_RESTART;
+ rqp->sr_timo = timeout; /* in seconds */
+ rqp->sr_state = SMBRQ_NOTSENT;
+
+ /*
+ * In-line smb_rq_enqueue(rqp) here, as we don't want it
+ * trying to reconnect etc. for an internal request.
+ */
+ rqp->sr_rquid = vcp->vc_smbuid;
+ rqp->sr_rqtid = SMB_TID_UNKNOWN;
+ rqp->sr_flags |= SMBR_INTERNAL;
+ error = smb1_iod_addrq(rqp);
+ if (error != 0)
+ return (error);
+
+ /*
+ * In-line a variant of smb_rq_reply(rqp) here as we may
+ * need to do custom parsing for SMB1-to-SMB2 negotiate.
+ */
+ if (rqp->sr_timo == SMBNOREPLYWAIT) {
+ smb_iod_removerq(rqp);
+ return (0);
+ }
+
+ error = smb_iod_waitrq_int(rqp);
+ if (error)
+ return (error);
+
+ /*
+ * If the request was signed, validate the
+ * signature on the response.
+ */
+ if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+ error = smb_rq_verify(rqp);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * Parse the SMB header.
+ */
+ error = smb_rq_parsehdr(rqp);
+
+ /*
+ * Skip the error translation smb_rq_reply does.
+ * Callers of this expect "raw" NT status.
+ */
return (error);
}
@@ -398,15 +489,6 @@ smb_rq_bend(struct smb_rq *rqp)
}
int
-smb_rq_intr(struct smb_rq *rqp)
-{
- if (rqp->sr_flags & SMBR_INTR)
- return (EINTR);
-
- return (0);
-}
-
-static int
smb_rq_getenv(struct smb_connobj *co,
struct smb_vc **vcpp, struct smb_share **sspp)
{
@@ -457,14 +539,12 @@ out:
}
/*
- * Wait for reply on the request
+ * Wait for a reply to this request, then parse it.
*/
static int
smb_rq_reply(struct smb_rq *rqp)
{
- struct mdchain *mdp = &rqp->sr_rp;
- u_int8_t tb;
- int error, rperror = 0;
+ int error;
if (rqp->sr_timo == SMBNOREPLYWAIT) {
smb_iod_removerq(rqp);
@@ -488,14 +568,23 @@ smb_rq_reply(struct smb_rq *rqp)
/*
* Parse the SMB header
*/
- error = md_get_uint32le(mdp, NULL);
- if (error)
+ error = smb_rq_parsehdr(rqp);
+ if (error != 0)
return (error);
- error = md_get_uint8(mdp, &tb);
- error = md_get_uint32le(mdp, &rqp->sr_error);
- error = md_get_uint8(mdp, &rqp->sr_rpflags);
- error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
- if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+
+ if (rqp->sr_error != 0) {
+ if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+ error = smb_maperr32(rqp->sr_error);
+ } else {
+ uint8_t errClass = rqp->sr_error & 0xff;
+ uint16_t errCode = rqp->sr_error >> 16;
+ /* Convert to NT status */
+ rqp->sr_error = smb_doserr2status(errClass, errCode);
+ error = smb_maperror(errClass, errCode);
+ }
+ }
+
+ if (error != 0) {
/*
* Do a special check for STATUS_BUFFER_OVERFLOW;
* it's not an error.
@@ -506,34 +595,65 @@ smb_rq_reply(struct smb_rq *rqp)
* they can look at rqp->sr_error if they
* need to know whether we got a
* STATUS_BUFFER_OVERFLOW.
- * XXX - should we do that for all errors
- * where (error & 0xC0000000) is 0x80000000,
- * i.e. all warnings?
*/
- rperror = 0;
- } else
- rperror = smb_maperr32(rqp->sr_error);
+ rqp->sr_flags |= SMBR_MOREDATA;
+ error = 0;
+ }
} else {
- rqp->sr_errclass = rqp->sr_error & 0xff;
- rqp->sr_serror = rqp->sr_error >> 16;
- rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
- }
- if (rperror == EMOREDATA) {
- rperror = E2BIG;
- rqp->sr_flags |= SMBR_MOREDATA;
- } else
rqp->sr_flags &= ~SMBR_MOREDATA;
+ }
+
+ return (error);
+}
+
+/*
+ * Parse the SMB header
+ */
+static int
+smb_rq_parsehdr(struct smb_rq *rqp)
+{
+ struct mdchain mdp_save;
+ struct mdchain *mdp = &rqp->sr_rp;
+ u_int8_t tb, sig[4];
+ int error;
- error = md_get_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
- error = md_get_uint32le(mdp, NULL);
+ /*
+ * Parse the signature. The reader already checked that
+ * the signature is valid. Here we just have to check
+ * for SMB1-to-SMB2 negotiate. Caller handles an EPROTO
+ * as a signal that we got an SMB2 reply. If we return
+ * EPROTO, rewind the mdchain back where it was.
+ */
+ mdp_save = *mdp;
+ error = md_get_mem(mdp, sig, 4, MB_MSYSTEM);
+ if (error)
+ return (error);
+ if (sig[0] != SMB_HDR_V1) {
+ if (rqp->sr_cmd == SMB_COM_NEGOTIATE) {
+ *mdp = mdp_save;
+ return (EPROTO);
+ }
+ return (EBADRPC);
+ }
+
+ /* Check cmd */
+ error = md_get_uint8(mdp, &tb);
+ if (tb != rqp->sr_cmd)
+ return (EBADRPC);
+
+ md_get_uint32le(mdp, &rqp->sr_error);
+ md_get_uint8(mdp, &rqp->sr_rpflags);
+ md_get_uint16le(mdp, &rqp->sr_rpflags2);
- error = md_get_uint16le(mdp, &rqp->sr_rptid);
- error = md_get_uint16le(mdp, &rqp->sr_rppid);
- error = md_get_uint16le(mdp, &rqp->sr_rpuid);
+ /* Skip: pid-high(2), MAC sig(8), reserved(2) */
+ md_get_mem(mdp, NULL, 12, MB_MSYSTEM);
+
+ md_get_uint16le(mdp, &rqp->sr_rptid);
+ md_get_uint16le(mdp, &rqp->sr_rppid);
+ md_get_uint16le(mdp, &rqp->sr_rpuid);
error = md_get_uint16le(mdp, &rqp->sr_rpmid);
- return ((error) ? error : rperror);
+ return (error);
}
@@ -1134,7 +1254,7 @@ smb_t2_request_int(struct smb_t2rq *t2p)
mb_put_mbuf(mbp, m);
}
smb_rq_bend(rqp);
- error = smb_iod_multirq(rqp);
+ error = smb1_iod_multirq(rqp);
if (error)
goto bad;
} /* while left params or data */
@@ -1345,7 +1465,7 @@ smb_nt_request_int(struct smb_ntrq *ntp)
mb_put_mbuf(mbp, m);
}
smb_rq_bend(rqp);
- error = smb_iod_multirq(rqp);
+ error = smb1_iod_multirq(rqp);
if (error)
goto bad;
} /* while left params or data */
@@ -1438,3 +1558,83 @@ smb_nt_request(struct smb_ntrq *ntp)
}
return (error);
}
+
+/*
+ * Run an SMB transact named pipe.
+ * Note: send_mb is consumed.
+ */
+int
+smb_t2_xnp(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *send_mb, struct mdchain *recv_md,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t *more, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p = NULL;
+ mblk_t *m;
+ uint16_t setup[2];
+ int err;
+
+ setup[0] = TRANS_TRANSACT_NAMED_PIPE;
+ setup[1] = fid;
+
+ t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
+ err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, scrp);
+ if (err) {
+ *data_out_sz = 0;
+ goto out;
+ }
+
+ t2p->t2_setupcount = 2;
+ t2p->t2_setupdata = setup;
+
+ t2p->t_name = "\\PIPE\\";
+ t2p->t_name_len = 6;
+
+ t2p->t2_maxscount = 0;
+ t2p->t2_maxpcount = 0;
+ t2p->t2_maxdcount = (uint16_t)*data_out_sz;
+
+ /* Transmit parameters (none) */
+
+ /*
+ * Transmit data
+ *
+ * Copy the mb, and clear the source so we
+ * don't end up with a double free.
+ */
+ t2p->t2_tdata = *send_mb;
+ bzero(send_mb, sizeof (*send_mb));
+
+ /*
+ * Run the request
+ */
+ err = smb_t2_request(t2p);
+
+ /* No returned parameters. */
+
+ if (err == 0 && (m = t2p->t2_rdata.md_top) != NULL) {
+ /*
+ * Received data
+ *
+ * Copy the mdchain, and clear the source so we
+ * don't end up with a double free.
+ */
+ *data_out_sz = msgdsize(m);
+ md_initm(recv_md, m);
+ t2p->t2_rdata.md_top = NULL;
+ } else {
+ *data_out_sz = 0;
+ }
+
+ if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW)
+ *more = 1;
+
+out:
+ if (t2p != NULL) {
+ /* Note: t2p->t_name no longer allocated */
+ smb_t2_done(t2p);
+ kmem_free(t2p, sizeof (*t2p));
+ }
+
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
index 0184022a65..7c3106612c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h
@@ -34,6 +34,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2012 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_RQ_H_
@@ -54,8 +56,12 @@
#define SMBR_NOINTR_RECV 0x0200 /* no interrupt in recv wait */
#define SMBR_SENDWAIT 0x0400 /* waiting for send to complete */
#define SMBR_NORECONNECT 0x0800 /* do not reconnect for this */
-/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
+/* SMBR_VCREF 0x4000 * took vc reference (obsolete) */
#define SMBR_MOREDATA 0x8000 /* our buffer was too small */
+#define SMBR_COMPOUND_RQ 0x10000 /* SMB 2/3 compound request */
+#define SMBR_ASYNC 0x20000 /* got async response */
+#define SMBR_RECONNECTED 0x40000 /* reconnected during request */
+
#define SMBT2_ALLSENT 0x0001 /* all data and params are sent */
#define SMBT2_ALLRECV 0x0002 /* all data and params are received */
@@ -64,7 +70,7 @@
#define SMBT2_NORESTART 0x0010
#define SMBT2_MOREDATA 0x8000 /* our buffer was too small */
-#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
+#define SMBRQ_LOCK(rqp) mutex_enter(&(rqp)->sr_lock)
#define SMBRQ_UNLOCK(rqp) mutex_exit(&(rqp)->sr_lock)
enum smbrq_state {
@@ -83,7 +89,7 @@ struct smb_rq {
enum smbrq_state sr_state;
struct smb_vc *sr_vc;
struct smb_share *sr_share;
- struct _kthread *sr_owner;
+ struct _kthread *sr_owner;
uint32_t sr_seqno; /* Seq. no. of request */
uint32_t sr_rseqno; /* Seq. no. of reply */
struct mbchain sr_rq;
@@ -91,11 +97,24 @@ struct smb_rq {
uint8_t sr_rqflags;
uint16_t sr_rqflags2;
uint16_t sr_rqtid;
- uint16_t sr_pid;
+ uint32_t sr_pid;
uint16_t sr_rquid;
uint16_t sr_mid;
uchar_t *sr_wcount;
uchar_t *sr_bcount;
+
+ /* SMB 2/3 request fields */
+ struct smb_rq *sr2_compound_next;
+ uint16_t sr2_command;
+ uint16_t sr2_totalcreditcharge;
+ uint16_t sr2_creditcharge;
+ uint16_t sr2_creditsrequested;
+ uint32_t sr2_rqflags;
+ uint32_t sr2_nextcmd;
+ uint64_t sr2_messageid; /* local copy of message id */
+ uint64_t sr2_rqsessionid;
+ uint32_t sr2_rqtreeid;
+
struct mdchain sr_rp;
int sr_rpgen;
int sr_rplast;
@@ -105,7 +124,7 @@ struct smb_rq {
int sr_timo;
int sr_rexmit; /* how many more retries. dflt 0 */
int sr_sendcnt;
- struct timespec sr_timesent;
+ struct timespec sr_timesent;
int sr_lerror;
uint8_t sr_errclass;
uint16_t sr_serror;
@@ -116,6 +135,15 @@ struct smb_rq {
uint16_t sr_rppid;
uint16_t sr_rpuid;
uint16_t sr_rpmid;
+
+ /* SMB2 response fields */
+ uint16_t sr2_rspcreditsgranted;
+ uint32_t sr2_rspflags;
+ uint32_t sr2_rspnextcmd;
+ uint32_t sr2_rsppid;
+ uint32_t sr2_rsptreeid;
+ uint64_t sr2_rspasyncid;
+ uint64_t sr2_rspsessionid;
};
typedef struct smb_rq smb_rq_t;
@@ -124,7 +152,7 @@ struct smb_t2rq {
kcondvar_t t2_cond;
uint16_t t2_setupcount;
uint16_t *t2_setupdata;
- uint16_t t2_setup[SMBIOC_T2RQ_MAXSETUP];
+ uint16_t t2_setup[4];
uint8_t t2_maxscount; /* max setup words to return */
uint16_t t2_maxpcount; /* max param bytes to return */
uint16_t t2_maxdcount; /* max data bytes to return */
@@ -184,15 +212,19 @@ int smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd,
struct smb_cred *scred, struct smb_rq **rqpp);
int smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer,
uchar_t cmd, struct smb_cred *scred);
+int smb_rq_getenv(struct smb_connobj *layer,
+ struct smb_vc **vcpp, struct smb_share **sspp);
void smb_rq_fillhdr(struct smb_rq *rqp);
void smb_rq_wstart(struct smb_rq *rqp);
void smb_rq_wend(struct smb_rq *rqp);
void smb_rq_bstart(struct smb_rq *rqp);
void smb_rq_bend(struct smb_rq *rqp);
-int smb_rq_intr(struct smb_rq *rqp);
int smb_rq_simple(struct smb_rq *rqp);
int smb_rq_simple_timed(struct smb_rq *rqp, int timeout);
+int smb_rq_internal(struct smb_rq *rqp, int timeout);
+
+int smb2_parse_smb1nego_resp(struct smb_rq *rqp);
int smb_t2_alloc(struct smb_connobj *layer, ushort_t setup,
struct smb_cred *scred, struct smb_t2rq **rqpp);
@@ -201,6 +233,10 @@ int smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer,
void smb_t2_done(struct smb_t2rq *t2p);
int smb_t2_request(struct smb_t2rq *t2p);
+int smb_t2_xnp(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *send_mb, struct mdchain *recv_md,
+ uint32_t *data_out_sz, uint32_t *more, struct smb_cred *scrp);
+
int smb_nt_alloc(struct smb_connobj *layer, ushort_t fn,
struct smb_cred *scred, struct smb_ntrq **rqpp);
int smb_nt_init(struct smb_ntrq *rqp, struct smb_connobj *layer,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
index cf06e75767..bec61e4392 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -37,8 +38,6 @@
#include <sys/md5.h>
#include <sys/des.h>
#include <sys/kmem.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/common.h>
#include <sys/cmn_err.h>
#include <sys/stream.h>
#include <sys/strsun.h>
@@ -50,6 +49,7 @@
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_rq.h>
+#include <netsmb/smb_signing.h>
#ifdef DEBUG
/*
@@ -59,15 +59,37 @@
int nsmb_signing_fudge = 0;
#endif
-/* Mechanism definitions */
-static crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
-
-void
-smb_crypto_mech_init(void)
+/*
+ * This is called just after session setup completes,
+ * at the top of smb_iod_vc_work(). Initialize signing.
+ */
+int
+smb_sign_init(smb_vc_t *vcp)
{
- crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
-}
+ int rc;
+ ASSERT(vcp->vc_ssnkey != NULL);
+ ASSERT(vcp->vc_mackey == NULL);
+
+ rc = smb_md5_getmech(&vcp->vc_signmech);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "smb can't get signing mechanism");
+ return (EAUTH);
+ }
+
+ /*
+ * Convert the session key to the MAC key.
+ * SMB1 uses the whole session key.
+ */
+ vcp->vc_mackeylen = vcp->vc_ssnkeylen;
+ vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
+ bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
+
+ /* The initial sequence number is two. */
+ vcp->vc_next_seq = 2;
+
+ return (0);
+}
#define SMBSIGLEN 8 /* SMB signature length */
@@ -83,12 +105,12 @@ static int
smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
uint32_t seqno, uchar_t *signature)
{
- crypto_context_t crypto_ctx;
- crypto_data_t key;
- crypto_data_t data;
- crypto_data_t digest;
- uchar_t mac[16];
- int status;
+ uchar_t digest[MD5_DIGEST_LENGTH];
+ smb_sign_ctx_t ctx = 0;
+ mblk_t *m = mp;
+ int size;
+ int rc;
+
/*
* This union is a little bit of trickery to:
* (1) get the sequence number int aligned, and
@@ -109,78 +131,64 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
} s;
} smbhdr;
- ASSERT(mp != NULL);
- ASSERT(MBLKL(mp) >= SMB_HDRLEN);
- ASSERT(vcp->vc_mackey != NULL);
+ if (vcp->vc_mackey == NULL)
+ return (-1);
+
+ if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
+ return (rc);
+
+ /* Digest the MAC Key */
+ rc = smb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen);
+ if (rc != 0)
+ return (rc);
+
+ /* Our caller should ensure mp has a contiguous header */
+ ASSERT(m != NULL);
+ ASSERT(MBLKL(m) >= SMB_HDRLEN);
/*
- * Make an aligned copy of the SMB header
- * and fill in the sequence number.
+ * Make an aligned copy of the SMB header,
+ * fill in the sequence number, and digest.
*/
- bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
+ size = SMB_HDRLEN;
+ bcopy(m->b_rptr, smbhdr.r.raw, size);
smbhdr.s.sig[0] = htolel(seqno);
smbhdr.s.sig[1] = 0;
+ rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
+ if (rc != 0)
+ return (rc);
+
/*
- * Compute the MAC: MD5(concat(Key, message))
+ * Digest the rest of the SMB header packet, starting at
+ * the data just after the SMB header.
*/
- if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
- SMBSDEBUG("crypto_mech_md5 invalid\n");
- return (CRYPTO_MECHANISM_INVALID);
- }
- status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the MAC Key */
- key.cd_format = CRYPTO_DATA_RAW;
- key.cd_offset = 0;
- key.cd_length = vcp->vc_mackeylen;
- key.cd_miscdata = 0;
- key.cd_raw.iov_base = (char *)vcp->vc_mackey;
- key.cd_raw.iov_len = vcp->vc_mackeylen;
- status = crypto_digest_update(crypto_ctx, &key, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Digest the (copied) SMB header */
- data.cd_format = CRYPTO_DATA_RAW;
- data.cd_offset = 0;
- data.cd_length = SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_raw.iov_base = (char *)smbhdr.r.raw;
- data.cd_raw.iov_len = SMB_HDRLEN;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
+ size = MBLKL(m) - SMB_HDRLEN;
+ rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
+ if (rc != 0)
+ return (rc);
+ m = m->b_cont;
/* Digest rest of the SMB message. */
- data.cd_format = CRYPTO_DATA_MBLK;
- data.cd_offset = SMB_HDRLEN;
- data.cd_length = msgdsize(mp) - SMB_HDRLEN;
- data.cd_miscdata = 0;
- data.cd_mp = mp;
- status = crypto_digest_update(crypto_ctx, &data, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
-
- /* Final */
- digest.cd_format = CRYPTO_DATA_RAW;
- digest.cd_offset = 0;
- digest.cd_length = sizeof (mac);
- digest.cd_miscdata = 0;
- digest.cd_raw.iov_base = (char *)mac;
- digest.cd_raw.iov_len = sizeof (mac);
- status = crypto_digest_final(crypto_ctx, &digest, 0);
- if (status != CRYPTO_SUCCESS)
- return (status);
+ while (m != NULL) {
+ size = MBLKL(m);
+ if (size > 0) {
+ rc = smb_md5_update(ctx, m->b_rptr, size);
+ if (rc != 0)
+ return (rc);
+ }
+ m = m->b_cont;
+ }
+ rc = smb_md5_final(ctx, digest);
+ if (rc != 0)
+ return (rc);
/*
* Finally, store the signature.
* (first 8 bytes of the mac)
*/
- if (signature)
- bcopy(mac, signature, SMBSIGLEN);
+ if (signature != NULL)
+ bcopy(digest, signature, SMBSIGLEN);
return (0);
}
@@ -197,13 +205,10 @@ smb_rq_sign(struct smb_rq *rqp)
int status;
/*
- * Our mblk allocation ensures this,
- * but just in case...
+ * smb_rq_new() ensures this,
+ * but just in case..
*/
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return;
- }
+ ASSERT(MBLKL(mp) >= SMB_HDRLEN);
sigloc = mp->b_rptr + SMBSIGOFF;
if (vcp->vc_mackey == NULL) {
@@ -221,7 +226,7 @@ smb_rq_sign(struct smb_rq *rqp)
* directly into the message at sigloc.
*/
status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
- if (status != CRYPTO_SUCCESS) {
+ if (status != 0) {
SMBSDEBUG("Crypto error %d", status);
bzero(sigloc, SMBSIGLEN);
}
@@ -256,10 +261,8 @@ smb_rq_verify(struct smb_rq *rqp)
SMBSDEBUG("empty reply\n");
return (0);
}
- if (MBLKL(mp) < SMB_HDRLEN) {
- if (!pullupmsg(mp, SMB_HDRLEN))
- return (0);
- }
+
+ ASSERT(MBLKL(mp) >= SMB_HDRLEN);
sigloc = mp->b_rptr + SMBSIGOFF;
/*
@@ -267,7 +270,7 @@ smb_rq_verify(struct smb_rq *rqp)
*/
rsn = rqp->sr_rseqno;
status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
- if (status != CRYPTO_SUCCESS) {
+ if (status != 0) {
SMBSDEBUG("Crypto error %d", status);
/*
* If we can't compute a MAC, then there's
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.h
new file mode 100644
index 0000000000..e1799e3383
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_signing.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 _SMB_SIGNING_H_
+#define _SMB_SIGNING_H_
+
+/*
+ * SMB signing routines used in {smb,smb2}_sign.c
+ * Two implementations of these (kernel/user) in:
+ * uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c
+ * lib/smbclnt/libfknsmb/common/fksmb_sign_pkcs.c
+ */
+
+#ifdef _KERNEL
+#include <sys/crypto/api.h>
+#else
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */
+#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
+#define SMB2_SIG_SIZE 16
+
+#ifdef _KERNEL
+/* KCF variant */
+typedef crypto_mechanism_t smb_sign_mech_t;
+typedef crypto_context_t smb_sign_ctx_t;
+#else /* _KERNEL */
+/* PKCS11 variant */
+typedef CK_MECHANISM smb_sign_mech_t;
+typedef CK_SESSION_HANDLE smb_sign_ctx_t;
+#endif /* _KERNEL */
+
+/*
+ * SMB signing routines used in smb_signing.c
+ */
+
+int smb_md5_getmech(smb_sign_mech_t *);
+int smb_md5_init(smb_sign_ctx_t *, smb_sign_mech_t *);
+int smb_md5_update(smb_sign_ctx_t, void *, size_t);
+int smb_md5_final(smb_sign_ctx_t, uint8_t *);
+
+/*
+ * SMB2 signing routines used in smb2_signing.c
+ */
+
+int smb2_hmac_getmech(smb_sign_mech_t *);
+int smb2_hmac_init(smb_sign_ctx_t *, smb_sign_mech_t *, uint8_t *, size_t);
+int smb2_hmac_update(smb_sign_ctx_t, uint8_t *, size_t);
+int smb2_hmac_final(smb_sign_ctx_t, uint8_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_SIGNING_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
index 6016f5061a..566f131316 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c
@@ -33,8 +33,9 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -49,6 +50,7 @@
#include <sys/uio.h>
#include <sys/random.h>
#include <sys/note.h>
+#include <sys/errno.h>
#include <sys/cmn_err.h>
#include <netsmb/smb_osdep.h>
@@ -61,14 +63,25 @@
#define STYPE_LEN 8 /* share type strings */
-/*
- * Largest size to use with LARGE_READ/LARGE_WRITE.
- * Specs say up to 64k data bytes, but Windows traffic
- * uses 60k... no doubt for some good reason.
- * (Probably to keep 4k block alignment.)
- * XXX: Move to smb.h maybe?
- */
-#define SMB_MAX_LARGE_RW_SIZE (60*1024)
+struct smb_dialect {
+ int d_id;
+ const char *d_name;
+};
+
+static struct smb_dialect smb_dialects[3] = {
+ {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
+ {SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
+#define NDIALECT_SMB1 2
+ {SMB_DIALECT_SMB2_FF, "SMB 2.???"},
+#define NDIALECT_SMB2 3
+};
+
+static const uint32_t smb_clnt_caps_mask =
+ SMB_CAP_UNICODE |
+ SMB_CAP_LARGE_FILES |
+ SMB_CAP_NT_SMBS |
+ SMB_CAP_STATUS32 |
+ SMB_CAP_EXT_SECURITY;
/*
* Default timeout values, all in seconds.
@@ -76,20 +89,526 @@
*/
int smb_timo_notice = 15;
int smb_timo_default = 30; /* was SMB_DEFRQTIMO */
+int smb_timo_logon = 45;
int smb_timo_open = 45;
int smb_timo_read = 45;
int smb_timo_write = 60; /* was SMBWRTTIMO */
int smb_timo_append = 90;
-static int smb_smb_read(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-static int smb_smb_write(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
+int
+smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ struct smb_dialect *dp;
+ int err, sblen, tlen;
+ uint8_t wc, eklen;
+ uint16_t dindex, bc;
+ uint16_t ndialects;
+ boolean_t will_sign = B_FALSE;
+
+ /*
+ * Initialize: vc_hflags and vc_hflags2.
+ * Note: vcp->vc_hflags* are copied into the
+ * (per request) rqp->rq_hflags* by smb_rq_init.
+ *
+ * Like Windows, set FLAGS2_UNICODE in our first request,
+ * even though technically we don't yet know whether the
+ * server supports Unicode. Will clear this flag below
+ * if we find out it doesn't. Need to do this because
+ * some servers reject all non-Unicode requests.
+ */
+ vcp->vc_hflags =
+ SMB_FLAGS_CASELESS |
+ SMB_FLAGS_CANONICAL_PATHNAMES;
+ vcp->vc_hflags2 =
+ SMB_FLAGS2_KNOWS_LONG_NAMES |
+ SMB_FLAGS2_KNOWS_EAS |
+ SMB_FLAGS2_IS_LONG_NAME |
+ SMB_FLAGS2_EXT_SEC |
+ SMB_FLAGS2_ERR_STATUS |
+ SMB_FLAGS2_UNICODE;
+
+ /*
+ * The initial UID needs to be zero,
+ */
+ vcp->vc_smbuid = 0;
+
+ /*
+ * (Re)init negotiated values
+ */
+ bzero(sv, sizeof (*sv));
+ sv->sv_maxmux = 1;
+ sv->sv_maxvcs = 1;
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Should we offer the magic SMB2 dialect?
+ */
+ if (vcp->vc_ssn.ssn_maxver >= SMB2_DIALECT_BASE)
+ ndialects = NDIALECT_SMB2;
+ else
+ ndialects = NDIALECT_SMB1;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
+ if (err)
+ return (err);
+
+ /*
+ * Build the SMB request.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ for (dindex = 0; dindex < ndialects; dindex++) {
+ dp = &smb_dialects[dindex];
+ mb_put_uint8(mbp, SMB_DT_DIALECT);
+ tlen = strlen(dp->d_name) + 1;
+ mb_put_mem(mbp, dp->d_name, tlen, MB_MSYSTEM);
+ }
+ smb_rq_bend(rqp);
+
+ /*
+ * Do the OTW call.
+ */
+ err = smb_rq_internal(rqp, smb_timo_default);
+ /*
+ * If it's an SMB1-to-SMB2 negotiate response,
+ * call the special handler and then skip the
+ * whole rest of this function.
+ */
+ if (err == EPROTO) {
+ err = smb2_parse_smb1nego_resp(rqp);
+ smb_rq_done(rqp);
+ return (err);
+ }
+ if (err) {
+ SMBSDEBUG("smb_rq_internal, err %d", err);
+ goto errout;
+ }
+ /* Should only get status success. */
+ if (rqp->sr_error != NT_STATUS_SUCCESS) {
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Decode the response
+ *
+ * Comments to right show names as described in
+ * The Microsoft SMB Protocol spec. [MS-SMB]
+ * section 2.2.3
+ */
+ smb_rq_getreply(rqp, &mdp);
+ (void) md_get_uint8(mdp, &wc);
+ err = md_get_uint16le(mdp, &dindex);
+ if (err != 0)
+ goto errout;
+ if (dindex >= ndialects) {
+ SMBERROR("Invalid dialect index from server: %s\n",
+ vcp->vc_srvname);
+ err = EBADRPC;
+ goto errout;
+ }
+ dp = smb_dialects + dindex;
+ sv->sv_proto = dp->d_id;
+ SMBSDEBUG("Dialect %s", dp->d_name);
+ if (dp->d_id < SMB_DIALECT_NTLM0_12) {
+ SMBSDEBUG("old dialect %s", dp->d_name);
+ goto errout;
+ }
+ if (wc != 17) {
+ SMBSDEBUG("bad wc %d", (int)wc);
+ goto errout;
+ }
+ md_get_uint8(mdp, &sv->sv_sm); /* SecurityMode */
+ md_get_uint16le(mdp, &sv->sv_maxmux); /* MaxMpxCount */
+ md_get_uint16le(mdp, &sv->sv_maxvcs); /* MaxCountVCs */
+ md_get_uint32le(mdp, &sv->sv_maxtx); /* MaxBufferSize */
+ md_get_uint32le(mdp, &sv->sv_maxraw); /* MaxRawSize */
+ md_get_uint32le(mdp, &sv->sv_skey); /* SessionKey */
+ md_get_uint32le(mdp, &sv->sv_caps); /* Capabilities */
+ md_get_mem(mdp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */
+ md_get_uint16le(mdp, (uint16_t *)&sv->sv_tz);
+ md_get_uint8(mdp, &eklen); /* EncryptionKeyLength */
+ err = md_get_uint16le(mdp, &bc); /* ByteCount */
+ if (err)
+ goto errout;
+
+ /* BEGIN CSTYLED */
+ /*
+ * Will we do SMB signing? Or block the connection?
+ * The table below describes this logic. References:
+ * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
+ * http://msdn.microsoft.com/en-us/library/cc212511.aspx
+ * http://msdn.microsoft.com/en-us/library/cc212929.aspx
+ *
+ * Srv/Cli | Required | Enabled | If Required | Disabled
+ * ------------+----------+------------+-------------+-----------
+ * Required | Signed | Signed | Signed | Blocked [1]
+ * ------------+----------+------------+-------------+-----------
+ * Enabled | Signed | Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * If Required | Signed | Not Signed | Not Signed | Not Signed
+ * ------------+----------+------------+-------------+-----------
+ * Disabled | Blocked | Not Signed | Not Signed | Not Signed
+ *
+ * [1] Like Windows 2003 and later, we don't really implement
+ * the "Disabled" setting. Instead we implement "If Required",
+ * so we always sign if the server requires signing.
+ */
+ /* END CSTYLED */
+
+ if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
+ /*
+ * Server requires signing. We will sign,
+ * even if local setting is "disabled".
+ */
+ will_sign = B_TRUE;
+ } else if (sv->sv_sm & SMB_SM_SIGS) {
+ /*
+ * Server enables signing (client's option).
+ * If enabled locally, do signing.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
+ will_sign = B_TRUE;
+ /* else not signing. */
+ } else {
+ /*
+ * Server does not support signing.
+ * If we "require" it, bail now.
+ */
+ if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
+ SMBERROR("Client requires signing "
+ "but server has it disabled.");
+ err = EBADRPC;
+ goto errout;
+ }
+ }
+
+ /*
+ * Anonymous sessions can't sign.
+ */
+ if (vcp->vc_vopt & SMBVOPT_ANONYMOUS) {
+ will_sign = B_FALSE;
+ }
+
+ SMBSDEBUG("Security signatures: %d", (int)will_sign);
+ if (will_sign) {
+ vcp->vc_flags |= SMBV_SIGNING;
+ vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+
+ /*
+ * MS-SMB 2.2.4.5 says that when SMB signing is enabled,
+ * we should NOT use "large read/write" even though the
+ * server might offer those capabilities.
+ */
+ sv->sv_caps &= ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
+ }
+
+ /* See comment above re. FLAGS2_UNICODE */
+ if ((sv->sv_caps & SMB_CAP_UNICODE) != 0)
+ vcp->vc_flags |= SMBV_UNICODE;
+ else
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
+
+ if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
+ /* They don't do NT error codes. */
+ vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
+ }
+
+ /*
+ * Warn if they don't support SMB_CAP_NT_SMBS
+ * (We'll try to use NtCreate anyway)
+ */
+ if ((sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
+ cmn_err(CE_NOTE, "%s does not support SMB_CAP_NT_SMBS",
+ vcp->vc_srvname);
+ }
+
+ /*
+ * The rest of the message varies depending on
+ * whether we've negotiated "extended security".
+ *
+ * With extended security, we have:
+ * Server_GUID (length 16)
+ * Security_BLOB
+ * Otherwise we have:
+ * EncryptionKey (length is eklen)
+ * PrimaryDomain
+ */
+ if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
+ SMBSDEBUG("Ext.Security: yes");
+
+ /*
+ * Skip the server GUID.
+ */
+ err = md_get_mem(mdp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
+ if (err)
+ goto errout;
+ /*
+ * Remainder is the security blob.
+ * Note: eklen "must be ignored" [MS-SMB]
+ */
+ sblen = (int)bc - SMB_GUIDLEN;
+ if (sblen < 0)
+ goto errout;
+ /* Security blob (hint) is next */
+ } else {
+ SMBSDEBUG("Ext.Security: no");
+ err = ENOTSUP;
+ goto errout;
+ }
+
+ /*
+ * Copy the security blob out to user space.
+ * Buffer addr,size in vc_auth_rbuf,rlen
+ */
+ if (wk->wk_u_auth_rlen < sblen) {
+ SMBSDEBUG("vc_auth_rbuf too small");
+ /* Give caller required size. */
+ wk->wk_u_auth_rlen = sblen;
+ err = EMSGSIZE;
+ goto errout;
+ }
+ wk->wk_u_auth_rlen = sblen;
+ err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, sblen, MB_MUSER);
+ if (err)
+ goto errout;
+
+ /*
+ * A few sanity checks on what we received,
+ * becuse we will send these in ssnsetup.
+ *
+ * Maximum outstanding requests (we care),
+ * and Max. VCs (we only use one). Also,
+ * MaxBufferSize lower limit per spec.
+ */
+ if (sv->sv_maxmux < 1)
+ sv->sv_maxmux = 1;
+ if (sv->sv_maxvcs < 1)
+ sv->sv_maxvcs = 1;
+ if (sv->sv_maxtx < 1024)
+ sv->sv_maxtx = 1024;
+
+ /*
+ * Maximum transfer size.
+ * Sanity checks:
+ *
+ * Let's be conservative about an upper limit here.
+ * Win2k uses 16644 (and others) so 32k should be a
+ * reasonable sanity limit for this value.
+ *
+ * Note that this limit does NOT affect READX/WRITEX
+ * with CAP_LARGE_..., which we nearly always use.
+ */
+ vcp->vc_txmax = sv->sv_maxtx;
+ if (vcp->vc_txmax > 0x8000)
+ vcp->vc_txmax = 0x8000;
+
+ /*
+ * Max read/write sizes, WITHOUT overhead.
+ * This is just the payload size, so we must
+ * leave room for the SMB headers, etc.
+ * This is just the ct_txmax value, but
+ * reduced and rounded down. Tricky bit:
+ *
+ * Servers typically give us a value that's
+ * some nice "round" number, i.e 0x4000 plus
+ * some overhead, i.e. Win2k: 16644==0x4104
+ * Subtract for the SMB header (32) and the
+ * SMB command word and byte vectors (34?),
+ * then round down to a 512 byte multiple.
+ */
+ tlen = vcp->vc_txmax - 68;
+ tlen &= 0xFE00;
+
+ vcp->vc_rwmax = tlen;
+ vcp->vc_rxmax = tlen;
+ vcp->vc_wxmax = tlen;
+
+ /*
+ * Most of the "capability" bits we offer in session setup
+ * are just copied from those offered by the server.
+ */
+ sv->sv_caps &= smb_clnt_caps_mask;
+
+ smb_rq_done(rqp);
+ return (0);
+
+errout:
+ smb_rq_done(rqp);
+ if (err == 0)
+ err = EBADRPC;
+ return (err);
+}
+
+static const char NativeOS[] = "illumos";
+static const char LanMan[] = "NETSMB";
+
+int
+smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ smb_sopt_t *sv = &vcp->vc_sopt;
+ smbioc_ssn_work_t *wk = &vcp->vc_work;
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp = NULL;
+ struct mdchain *mdp = NULL;
+ char *sb;
+ int err, ret;
+ uint32_t caps;
+ uint16_t action, bc, sblen;
+ uint8_t wc;
+
+ caps = sv->sv_caps;
+ sb = wk->wk_u_auth_wbuf.lp_ptr;
+ sblen = (uint16_t)wk->wk_u_auth_wlen;
+
+ err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
+ scred, &rqp);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+
+ /*
+ * Build the SMB Session Setup request.
+ * Always extended security form.
+ */
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */
+ mb_put_uint16le(mbp, 0); /* 1: AndXOffset */
+ mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */
+ mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
+ mb_put_uint16le(mbp, 1); /* 4: VcNumber */
+ mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */
+ mb_put_uint16le(mbp, sblen); /* 7: Sec. Blob Len */
+ mb_put_uint32le(mbp, 0); /* 8,9: reserved */
+ mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */
+ smb_rq_wend(rqp); /* 12: Byte Count */
+ smb_rq_bstart(rqp);
+ err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
+ if (err != 0) {
+ ret = err;
+ goto out;
+ }
+ (void) smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE);
+ (void) smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE);
+ smb_rq_bend(rqp);
+
+ /*
+ * Run the request. The return value here should be the
+ * return from this function, unless we fail decoding.
+ * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
+ * the caller expects EINPROGRESS for that case.
+ */
+ ret = smb_rq_internal(rqp, smb_timo_logon);
+ if (ret != 0)
+ goto out;
+ switch (rqp->sr_error) {
+ case NT_STATUS_SUCCESS:
+ break;
+ case NT_STATUS_MORE_PROCESSING_REQUIRED:
+ /* Keep going, but return... */
+ ret = EINPROGRESS;
+ break;
+ default:
+ ret = EAUTH;
+ goto out;
+ }
+
+ if (vcp->vc_smbuid == 0)
+ vcp->vc_smbuid = rqp->sr_rpuid;
+
+ /*
+ * Parse the reply
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ err = md_get_uint8(mdp, &wc);
+ if (err != 0)
+ wc = 0;
+ if (wc != 4) {
+ ret = EBADRPC;
+ goto out;
+ }
+ md_get_uint16le(mdp, NULL); /* secondary cmd */
+ md_get_uint16le(mdp, NULL); /* andxoffset */
+ md_get_uint16le(mdp, &action); /* action XXX */
+ md_get_uint16le(mdp, &sblen); /* sec. blob len */
+ md_get_uint16le(mdp, &bc); /* byte count */
+ /*
+ * Get the security blob, after
+ * sanity-checking the length.
+ */
+ if (sblen == 0 || sblen > bc) {
+ ret = EBADRPC;
+ goto out;
+ }
+ if (sblen > wk->wk_u_auth_rlen) {
+ ret = EBADRPC;
+ goto out;
+ }
+ sb = wk->wk_u_auth_rbuf.lp_ptr;
+ err = md_get_mem(mdp, sb, sblen, MB_MUSER);
+ if (err) {
+ ret = EBADRPC;
+ goto out;
+ }
+
+ /*
+ * Native OS, LANMGR, & Domain follow here.
+ * We don't need them and don't parse them.
+ */
+
+out:
+ if (err != 0 && err != EINPROGRESS) {
+ /* UID no longer valid. */
+ vcp->vc_smbuid = 0;
+ }
+ if (rqp)
+ smb_rq_done(rqp);
+
+ return (ret);
+}
+
+int
+smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
+ return (0);
+
+ error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
+ if (error)
+ return (error);
+ mbp = &rqp->sr_rq;
+ smb_rq_wstart(rqp);
+ mb_put_uint8(mbp, 0xff);
+ mb_put_uint8(mbp, 0);
+ mb_put_uint16le(mbp, 0);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
-static int smb_smb_readx(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
-static int smb_smb_writex(struct smb_share *ssp, uint16_t fid,
- uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
+ /*
+ * Run this with a relatively short timeout. (5 sec.)
+ * We don't really care about the result here.
+ * Also, don't reconnect for this, of course!
+ */
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb_rq_internal(rqp, 5);
+ smb_rq_done(rqp);
+ return (error);
+}
/*
* Get the string representation of a share "use" type,
@@ -352,7 +871,7 @@ smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
* Modern create/open of file or directory.
*/
int
-smb_smb_ntcreate(
+smb1_smb_ntcreate(
struct smb_share *ssp,
struct mbchain *name_mb,
uint32_t cr_flags, /* create flags */
@@ -475,7 +994,7 @@ done:
}
int
-smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
+smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
struct smb_cred *scrp)
{
struct smb_rq rq, *rqp = &rq;
@@ -600,101 +1119,11 @@ smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
return (error);
}
-/*
- * Common function for read/write with UIO.
- * Called by netsmb smb_usr_rw,
- * smbfs_readvnode, smbfs_writevnode
- */
int
-smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_vc *vcp = SSTOVC(ssp);
- ssize_t save_resid;
- uint32_t len, rlen, maxlen;
- int error = 0;
- int (*iofun)(struct smb_share *, uint16_t, uint32_t *,
- uio_t *, smb_cred_t *, int);
-
- /*
- * Determine which function to use,
- * and the transfer size per call.
- */
- if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) {
- /*
- * Using NT LM 0.12, so readx, writex.
- * Make sure we can represent the offset.
- */
- if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
- (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
- return (EFBIG);
-
- if (rw == UIO_READ) {
- iofun = smb_smb_readx;
- if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
- maxlen = SMB_MAX_LARGE_RW_SIZE;
- else
- maxlen = vcp->vc_rxmax;
- } else { /* UIO_WRITE */
- iofun = smb_smb_writex;
- if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
- maxlen = SMB_MAX_LARGE_RW_SIZE;
- else
- maxlen = vcp->vc_wxmax;
- }
- } else {
- /*
- * Using the old SMB_READ and SMB_WRITE so
- * we're limited to 32-bit offsets, etc.
- * XXX: Someday, punt the old dialects.
- */
- if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
- return (EFBIG);
-
- if (rw == UIO_READ) {
- iofun = smb_smb_read;
- maxlen = vcp->vc_rxmax;
- } else { /* UIO_WRITE */
- iofun = smb_smb_write;
- maxlen = vcp->vc_wxmax;
- }
- }
-
- save_resid = uiop->uio_resid;
- while (uiop->uio_resid > 0) {
- /* Lint: uio_resid may be 64-bits */
- rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
- error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
-
- /*
- * Note: the iofun called uio_update, so
- * not doing that here as one might expect.
- *
- * Quit the loop either on error, or if we
- * transferred less then requested.
- */
- if (error || (rlen < len))
- break;
-
- timo = 0; /* only first I/O should wait */
- }
- if (error && (save_resid != uiop->uio_resid)) {
- /*
- * Stopped on an error after having
- * successfully transferred data.
- * Suppress this error.
- */
- SMBSDEBUG("error %d suppressed\n", error);
- error = 0;
- }
-
- return (error);
-}
-
-static int
-smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
+smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
+ struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
@@ -716,7 +1145,7 @@ smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint16le(mbp, lenlo); /* MaxCount */
mb_put_uint16le(mbp, 1); /* MinCount */
@@ -786,10 +1215,11 @@ out:
return (error);
}
-static int
-smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
+int
+smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo)
{
+ struct smb_share *ssp = FHTOSS(fhp);
struct smb_rq *rqp;
struct mbchain *mbp;
struct mdchain *mdp;
@@ -811,7 +1241,7 @@ smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
mb_put_uint8(mbp, 0xff); /* no secondary command */
mb_put_uint8(mbp, 0); /* MBZ */
mb_put_uint16le(mbp, 0); /* offset to secondary */
- mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, fhp->fh_fid1);
mb_put_uint32le(mbp, offlo); /* offset (low part) */
mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
mb_put_uint16le(mbp, 0); /* !write-thru */
@@ -859,148 +1289,13 @@ out:
return (error);
}
-static int
-smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t bc, cnt, dlen, rcnt, todo;
- uint8_t wc;
-
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned reads. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
-
- if (timo == 0)
- timo = smb_timo_read;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 5) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &rcnt); /* ret. count */
- md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */
- md_get_uint16le(mdp, &bc); /* byte count */
- md_get_uint8(mdp, NULL); /* buffer format */
- error = md_get_uint16le(mdp, &dlen); /* data len */
- if (error)
- goto out;
- if (dlen < rcnt) {
- SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
- (int)dlen, (int)rcnt);
- rcnt = dlen;
- }
- if (rcnt == 0) {
- *lenp = 0;
- goto out;
- }
- /* paranoid */
- if (rcnt > cnt) {
- SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
- (int)rcnt, (int)cnt);
- rcnt = cnt;
- }
- error = md_get_uio(mdp, uiop, (int)rcnt);
- if (error)
- goto out;
-
- /* success */
- *lenp = (int)rcnt;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-static int
-smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
- uio_t *uiop, smb_cred_t *scred, int timo)
-{
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- int error;
- uint32_t off32;
- uint16_t cnt, rcnt, todo;
- uint8_t wc;
-
- ASSERT(uiop->uio_loffset <= UINT32_MAX);
- off32 = (uint32_t)uiop->uio_loffset;
- ASSERT(*lenp <= UINT16_MAX);
- cnt = (uint16_t)*lenp;
- /* This next is an "estimate" of planned writes. */
- todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
-
- error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, cnt);
- mb_put_uint32le(mbp, off32);
- mb_put_uint16le(mbp, todo);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, cnt);
-
- error = mb_put_uio(mbp, uiop, *lenp);
- if (error)
- goto out;
- smb_rq_bend(rqp);
- if (timo == 0)
- timo = smb_timo_write;
- error = smb_rq_simple_timed(rqp, timo);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, &rcnt);
- if (error)
- goto out;
- *lenp = rcnt;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
static u_int32_t smbechoes = 0;
+/*
+ * Note: the IOD calls this, so this request must not wait for
+ * connection state changes, etc. (uses smb_rq_internal)
+ */
int
smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
{
@@ -1018,13 +1313,8 @@ smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
smb_rq_bstart(rqp);
mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
smb_rq_bend(rqp);
- /*
- * Note: the IOD calls this, so
- * this request must not wait for
- * connection state changes, etc.
- */
rqp->sr_flags |= SMBR_NORECONNECT;
- error = smb_rq_simple_timed(rqp, timo);
+ error = smb_rq_internal(rqp, timo);
SMBSDEBUG("%d\n", error);
smb_rq_done(rqp);
return (error);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
index df0f28ec05..b780f9b21b 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h
@@ -33,8 +33,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_SUBR_H_
@@ -43,8 +43,16 @@
#include <sys/cmn_err.h>
#include <sys/lock.h>
#include <sys/note.h>
+#include <netsmb/mchain.h>
#include <netsmb/smb_conn.h>
+/*
+ * Possible lock commands
+ */
+#define SMB_LOCK_EXCL 0
+#define SMB_LOCK_SHARED 1
+#define SMB_LOCK_RELEASE 2
+
struct msgb; /* avoiding sys/stream.h here */
/* Helper function for SMBERROR */
@@ -117,86 +125,131 @@ extern int smb_timo_open;
extern int smb_timo_read;
extern int smb_timo_write;
extern int smb_timo_append;
+extern dev_t nsmb_dev_tcp;
+extern dev_t nsmb_dev_tcp6;
-#define EMOREDATA (0x7fff)
+/*
+ * Tunable timeout values. See: smb2_smb.c
+ */
+extern int smb2_timo_notice;
+extern int smb2_timo_default;
+extern int smb2_timo_open;
+extern int smb2_timo_read;
+extern int smb2_timo_write;
+extern int smb2_timo_append;
void smb_credinit(struct smb_cred *scred, cred_t *cr);
void smb_credrele(struct smb_cred *scred);
-void smb_oldlm_hash(const char *apwd, uchar_t *hash);
-void smb_ntlmv1hash(const char *apwd, uchar_t *hash);
-void smb_ntlmv2hash(const uchar_t *v1hash, const char *user,
- const char *destination, uchar_t *v2hash);
-
-int smb_lmresponse(const uchar_t *hash, const uchar_t *C8, uchar_t *RN);
-int smb_ntlmv2response(const uchar_t *hash, const uchar_t *C8,
- const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen);
int smb_maperror(int eclass, int eno);
int smb_maperr32(uint32_t eno);
+uint_t smb_doserr2status(int, int);
+int smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp,
+ char *outbuf, size_t *outlen, int inlen);
int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp,
const char *src, int len, int caseopt, int *lenp);
int smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp,
const char *src, int caseopt);
int smb_put_string(struct smb_rq *rqp, const char *src);
int smb_put_asunistring(struct smb_rq *rqp, const char *src);
-int smb_checksmp(void);
+
+int smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb_fh_t *fhp,
+ uint32_t *cr_act_p, struct smbfattr *fap);
+
+int smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp);
+
+int smb_rwuio(smb_fh_t *fhp, uio_rw_t rw,
+ uio_t *uiop, smb_cred_t *scred, int timo);
int smb_cmp_sockaddr(struct sockaddr *, struct sockaddr *);
struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa);
void smb_free_sockaddr(struct sockaddr *sa);
-int smb_toupper(const char *, char *, size_t);
+int smb_sign_init(struct smb_vc *);
void smb_rq_sign(struct smb_rq *);
int smb_rq_verify(struct smb_rq *);
int smb_calcv2mackey(struct smb_vc *, const uchar_t *,
const uchar_t *, size_t);
int smb_calcmackey(struct smb_vc *, const uchar_t *,
const uchar_t *, size_t);
-void smb_crypto_mech_init(void);
+int smb2_sign_init(struct smb_vc *);
+void smb2_rq_sign(struct smb_rq *);
+int smb2_rq_verify(struct smb_rq *);
/*
* SMB protocol level functions
*/
+int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
+int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
+int smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred);
int smb_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
int smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
int smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
-int
-smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+int smb1_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
uint32_t disp, uint32_t createopt, uint32_t impersonate,
struct smb_cred *scrp, uint16_t *fidp,
uint32_t *cr_act_p, struct smbfattr *fap);
-int smb_smb_close(struct smb_share *ssp, uint16_t fid,
+int smb1_smb_close(struct smb_share *ssp, uint16_t fid,
struct timespec *mtime, struct smb_cred *scrp);
-int
-smb_smb_open_prjob(struct smb_share *ssp, char *title,
+int smb_smb_open_prjob(struct smb_share *ssp, char *title,
uint16_t setuplen, uint16_t mode,
struct smb_cred *scrp, uint16_t *fidp);
int smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
struct smb_cred *scrp);
-int smb_rwuio(smb_share_t *ssp, uint16_t fid, uio_rw_t rw,
+int smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
+int smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
uio_t *uiop, smb_cred_t *scred, int timo);
/*
- * time conversions
+ * SMB2 protocol level functions
*/
+int smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred);
+int smb2_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
+int smb2_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
+int smb2_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
+
+int
+smb2_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ struct mbchain *cctx_in, struct mdchain *cctx_out,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb2fid_t *fidp,
+ uint32_t *cr_act_p, struct smbfattr *fap);
+
+int smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp);
+
+int smb2_smb_ioctl(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *data_in, struct mdchain *data_out,
+ uint32_t *data_out_sz, /* max / returned */
+ uint32_t ctl_code, struct smb_cred *scrp);
+
+int smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
+int smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
+ uio_t *uiop, smb_cred_t *scred, int timo);
-void smb_time_init(void);
-void smb_time_fini(void);
+/*
+ * time conversions
+ */
void smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds);
void smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp);
void smb_time_NT2local(uint64_t nsec, struct timespec *tsp);
void smb_time_local2NT(struct timespec *tsp, uint64_t *nsec);
-void smb_time_unix2dos(struct timespec *tsp, int tzoff, uint16_t *ddp,
- uint16_t *dtp, uint8_t *dhp);
-void smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
- struct timespec *tsp);
#endif /* !_NETSMB_SMB_SUBR_H_ */
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
index e29a96631a..bf1e605187 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c
@@ -34,6 +34,8 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -57,50 +59,19 @@
#include <netsmb/smb_rq.h>
#include <netsmb/smb_subr.h>
-/*
- * XXX:This conversion might not be fully MS-Compatible
- * for calculating hashes. The output length may differ
- * for some locales and needs to be handled from where
- * the call is made.
- */
-int
-smb_toupper(const char *inbuf, char *outbuf, size_t outlen)
-{
- int err = 0;
- size_t inlen, inrem, outrem;
-
- inrem = inlen = strlen(inbuf);
- outrem = outlen;
- (void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem,
- U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
- /* inrem, outrem are bytes unused, remaining */
- if (inrem) {
- SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf);
- inlen -= inrem;
- }
- if (outrem) {
- outlen -= outrem;
- outbuf[outlen] = '\0';
- }
- if (outlen > inlen) {
- SMBSDEBUG("outlen > inlen! (%d > %d)\n",
- (int)outlen, (int)inlen);
- /* Truncate to inlen here? */
- }
-
- return (err);
-}
-
void
smb_credinit(struct smb_cred *scred, cred_t *cr)
{
/* cr arg is optional */
if (cr == NULL)
cr = ddi_get_cred();
+#ifdef _KERNEL
if (is_system_labeled()) {
cr = crdup(cr);
(void) setpflags(NET_MAC_AWARE, 1, cr);
- } else {
+ } else
+#endif
+ {
crhold(cr);
}
scred->scr_cred = cr;
@@ -115,6 +86,14 @@ smb_credrele(struct smb_cred *scred)
}
}
+#ifndef _KERNEL
+/* ARGSUSED */
+void
+smb_debugmsg(const char *func, char *msg)
+{
+}
+#endif /* _KERNEL */
+
/*
* Helper for the SMBERROR macro, etc.
* This is also a good place for a breakpoint
@@ -137,6 +116,9 @@ smb_errmsg(int cel, const char *func_name, const char *fmt, ...)
DTRACE_PROBE2(debugmsg2,
(char *), func_name,
(char *), buf);
+#ifndef _KERNEL
+ smb_debugmsg(func_name, buf);
+#endif
} else {
/*
* This is one of our xxxERROR macros.
@@ -190,6 +172,9 @@ m_dumpm(mblk_t *m)
#ifndef ETIME
#define ETIME ETIMEDOUT
#endif
+#ifndef EMOREDATA
+#define EMOREDATA (0x7fff)
+#endif
/*
* Log any un-handled NT or DOS errors we encounter.
@@ -219,7 +204,9 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_ACCOUNT_RESTRICTION, EACCES},
{NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE},
{NT_STATUS_BAD_NETWORK_NAME, ENOENT},
- {NT_STATUS_BUFFER_TOO_SMALL, EMOREDATA},
+ {NT_STATUS_BAD_NETWORK_PATH, ENOENT},
+ {NT_STATUS_BUFFER_TOO_SMALL, E2BIG},
+ {NT_STATUS_CANCELLED, ECANCELED},
{NT_STATUS_CANNOT_DELETE, EACCES},
{NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE},
{NT_STATUS_CONNECTION_ABORTED, ECONNABORTED},
@@ -233,59 +220,87 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_DISK_FULL, ENOSPC},
{NT_STATUS_DLL_NOT_FOUND, ELIBACC},
{NT_STATUS_DUPLICATE_NAME, EINVAL},
+ {NT_STATUS_EAS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_EA_TOO_LARGE, E2BIG},
{NT_STATUS_END_OF_FILE, ENODATA},
+ {NT_STATUS_FILE_CLOSED, EBADF},
+ {NT_STATUS_FILE_DELETED, ENOENT},
+ {NT_STATUS_FILE_INVALID, EIO},
{NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR},
{NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN},
+ {NT_STATUS_FILE_RENAMED, ENOENT},
{NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE},
{NT_STATUS_FLOAT_OVERFLOW, ERANGE},
{NT_STATUS_FLOAT_UNDERFLOW, ERANGE},
{NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH},
- {NT_STATUS_ILL_FORMED_PASSWORD, EACCES},
+ {NT_STATUS_ILL_FORMED_PASSWORD, EAUTH},
+ {NT_STATUS_INFO_LENGTH_MISMATCH, EINVAL},
+ {NT_STATUS_INSUFFICIENT_RESOURCES, EAGAIN},
+ {NT_STATUS_INSUFF_SERVER_RESOURCES, EAGAIN},
{NT_STATUS_INTEGER_OVERFLOW, ERANGE},
- {NT_STATUS_INVALID_ACCOUNT_NAME, EACCES},
+ {NT_STATUS_INVALID_ACCOUNT_NAME, EAUTH},
+ {NT_STATUS_INVALID_BUFFER_SIZE, EIO},
+ {NT_STATUS_INVALID_DEVICE_REQUEST, EINVAL},
{NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_INVALID_INFO_CLASS, EINVAL},
{NT_STATUS_INVALID_LEVEL, ENOTSUP},
- {NT_STATUS_INVALID_LOGON_HOURS, EACCES},
+ {NT_STATUS_INVALID_LOCK_SEQUENCE, EINVAL},
+ {NT_STATUS_INVALID_LOGON_HOURS, EAUTH},
{NT_STATUS_INVALID_OWNER, EINVAL},
{NT_STATUS_INVALID_PARAMETER, EINVAL},
{NT_STATUS_INVALID_PIPE_STATE, EPIPE},
{NT_STATUS_INVALID_PRIMARY_GROUP, EINVAL},
{NT_STATUS_INVALID_WORKSTATION, EACCES},
{NT_STATUS_IN_PAGE_ERROR, EFAULT},
+ {NT_STATUS_IO_DEVICE_ERROR, EIO},
{NT_STATUS_IO_TIMEOUT, ETIMEDOUT},
- {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ},
- {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ},
+ {NT_STATUS_IP_ADDRESS_CONFLICT1, EADDRINUSE},
+ {NT_STATUS_IP_ADDRESS_CONFLICT2, EADDRINUSE},
{NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT},
{NT_STATUS_LOCK_NOT_GRANTED, EAGAIN},
- {NT_STATUS_LOGIN_TIME_RESTRICTION, EACCES},
- {NT_STATUS_LOGON_FAILURE, EACCES},
+ {NT_STATUS_LOGIN_TIME_RESTRICTION, EAUTH},
+ {NT_STATUS_LOGON_FAILURE, EAUTH},
+ {NT_STATUS_LOGON_TYPE_NOT_GRANTED, EAUTH},
{NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS},
{NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT},
+ {NT_STATUS_MORE_PROCESSING_REQUIRED, EINPROGRESS},
{NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG},
{NT_STATUS_NETWORK_ACCESS_DENIED, EACCES},
{NT_STATUS_NETWORK_BUSY, EBUSY},
+ {NT_STATUS_NETWORK_NAME_DELETED, ENOENT},
{NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH},
{NT_STATUS_NET_WRITE_FAULT, ECOMM},
+ {NT_STATUS_NONEXISTENT_EA_ENTRY, ENOENT},
{NT_STATUS_NONEXISTENT_SECTOR, ESPIPE},
{NT_STATUS_NONE_MAPPED, EINVAL},
{NT_STATUS_NOT_A_DIRECTORY, ENOTDIR},
+ {NT_STATUS_NOT_FOUND, ENOENT},
{NT_STATUS_NOT_IMPLEMENTED, ENOTSUP},
+ {NT_STATUS_NOT_LOCKED, ENOLCK},
{NT_STATUS_NOT_MAPPED_VIEW, EINVAL},
{NT_STATUS_NOT_SUPPORTED, ENOTSUP},
+ {NT_STATUS_NO_EAS_ON_FILE, ENOENT},
+ {NT_STATUS_NO_LOGON_SERVERS, EAUTH},
{NT_STATUS_NO_MEDIA, ENOMEDIUM},
{NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM},
{NT_STATUS_NO_MEMORY, ENOMEM},
{NT_STATUS_NO_SUCH_DEVICE, ENODEV},
{NT_STATUS_NO_SUCH_FILE, ENOENT},
+ {NT_STATUS_NO_SUCH_LOGON_SESSION, EAUTH},
+ {NT_STATUS_NO_SUCH_USER, EAUTH},
+ {NT_STATUS_NO_TRUST_LSA_SECRET, EAUTH},
+ {NT_STATUS_NO_TRUST_SAM_ACCOUNT, EAUTH},
{NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
{NT_STATUS_OBJECT_NAME_INVALID, EINVAL},
{NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
{NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
{NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT},
+ {NT_STATUS_OBJECT_PATH_SYNTAX_BAD, EINVAL},
+ {NT_STATUS_OBJECT_TYPE_MISMATCH, EBADF},
{NT_STATUS_PAGEFILE_QUOTA, EDQUOT},
- {NT_STATUS_PASSWORD_EXPIRED, EACCES},
- {NT_STATUS_PASSWORD_MUST_CHANGE, EACCES},
- {NT_STATUS_PASSWORD_RESTRICTION, EACCES},
+ {NT_STATUS_PASSWORD_EXPIRED, EAUTH},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, EAUTH},
+ {NT_STATUS_PASSWORD_RESTRICTION, EAUTH},
{NT_STATUS_PATH_NOT_COVERED, ENOENT},
{NT_STATUS_PIPE_BROKEN, EPIPE},
{NT_STATUS_PIPE_BUSY, EPIPE},
@@ -293,11 +308,12 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_PIPE_DISCONNECTED, EPIPE},
{NT_STATUS_PIPE_NOT_AVAILABLE, EBUSY},
{NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_PORT_DISCONNECTED, EBADF},
{NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE},
{NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH},
{NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT},
{NT_STATUS_QUOTA_EXCEEDED, EDQUOT},
- {NT_STATUS_RANGE_NOT_LOCKED, EIO},
+ {NT_STATUS_RANGE_NOT_LOCKED, EAGAIN}, /* like F_SETLK */
{NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT},
{NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN},
{NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED},
@@ -307,9 +323,11 @@ static const nt2errno_t nt2errno[] = {
{NT_STATUS_TIMER_NOT_CANCELED, ETIME},
{NT_STATUS_TOO_MANY_LINKS, EMLINK},
{NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE},
+ {NT_STATUS_TRUSTED_DOMAIN_FAILURE, EAUTH},
+ {NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE, EAUTH},
{NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE},
{NT_STATUS_UNSUCCESSFUL, EINVAL},
- {NT_STATUS_WRONG_PASSWORD, EACCES},
+ {NT_STATUS_WRONG_PASSWORD, EAUTH},
{0, 0}
};
@@ -593,14 +611,6 @@ static const nt2doserr_t nt2doserr[] = {
{ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION},
{ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE},
{ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
- {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR},
{ERRHRD, ERRgeneral, NT_STATUS_NO_LDT},
{ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE},
{ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET},
@@ -868,6 +878,19 @@ smb_maperr32(uint32_t nterr)
return (EIO);
}
+uint_t
+smb_doserr2status(int dclass, int derr)
+{
+ const nt2doserr_t *nt2d;
+
+ if (dclass == 0 && derr == 0)
+ return (0);
+
+ for (nt2d = nt2doserr; nt2d->nterr; nt2d++)
+ if (nt2d->dclass == dclass && nt2d->derr == derr)
+ return (nt2d->nterr);
+ return (NT_STATUS_UNSUCCESSFUL);
+}
int
smb_maperror(int eclass, int eno)
@@ -996,13 +1019,90 @@ smb_maperror(int eclass, int eno)
return (EIO);
}
-#if defined(NOICONVSUPPORT) || defined(lint)
-extern int iconv_conv(void *handle, const char **inbuf,
- size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
-#endif
-
#define SMALL_CONV 256
+/*
+ * Decode an SMB OTW string (Unicode or OEM chars)
+ * converting to UTF-8 in the output buffer.
+ * outlen is in/out (max size on input)
+ * insize is the wire size (2 * chars if unicode)
+ * The output string is null terminated.
+ * Output length does not include the null.
+ */
+int
+smb_get_dstring(struct mdchain *mdc, struct smb_vc *vcp,
+ char *outbuf, size_t *outlen, int insize)
+{
+ uint16_t convbuf[SMALL_CONV];
+ uint16_t *cbuf;
+ size_t cbufalloc, inlen, outsize;
+ int error;
+
+ if (insize <= 0)
+ return (0);
+ /* Note: inlen is UTF-16 symbols. */
+ inlen = insize / 2;
+
+ if (*outlen < 2)
+ return (EINVAL);
+ outsize = *outlen - 1; /* room for null */
+
+ /*
+ * Get a buffer for the conversion and fill it.
+ * Use stack buffer if the string is
+ * small enough, else allocate.
+ */
+ if (insize < sizeof (convbuf)) {
+ cbufalloc = 0;
+ cbuf = convbuf;
+ } else {
+ cbufalloc = insize + 2;
+ cbuf = kmem_alloc(cbufalloc, KM_SLEEP);
+ }
+ error = md_get_mem(mdc, cbuf, insize, MB_MSYSTEM);
+ if (error != 0)
+ goto out;
+ cbuf[inlen] = 0;
+
+ /*
+ * Handle the easy case (non-unicode).
+ * XXX: Technically, we should convert
+ * the string to OEM codeset first...
+ * Modern servers all use Unicode, so
+ * this is good enough.
+ */
+ if (SMB_UNICODE_STRINGS(vcp) == 0) {
+ *outlen = strlcpy(outbuf, (char *)cbuf, outsize);
+ if (*outlen > outsize) {
+ *outlen = outsize;
+ error = E2BIG;
+ }
+ } else {
+ /*
+ * Convert from UTF-16 to UTF-8
+ */
+ error = uconv_u16tou8(cbuf, &inlen,
+ (uchar_t *)outbuf, outlen,
+ UCONV_IN_LITTLE_ENDIAN);
+ if (error == 0) {
+ outbuf[*outlen] = '\0';
+ }
+ }
+
+ ASSERT(*outlen == strlen(outbuf));
+
+out:
+ if (cbufalloc != 0)
+ kmem_free(cbuf, cbufalloc);
+
+ return (error);
+}
+
+/*
+ * It's surprising that this function does utf8-ucs2 conversion.
+ * One would expect only smb_put_dstring to do that.
+ * Fixing that will require changing a bunch of callers. XXX
+ */
/*ARGSUSED*/
int
smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
@@ -1080,3 +1180,130 @@ smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
return (error);
}
+int
+smb_smb_ntcreate(struct smb_share *ssp, struct mbchain *name_mb,
+ uint32_t crflag, uint32_t req_acc, uint32_t efa, uint32_t sh_acc,
+ uint32_t disp, uint32_t createopt, uint32_t impersonate,
+ struct smb_cred *scrp, smb_fh_t *fhp,
+ uint32_t *cr_act_p, struct smbfattr *fap)
+{
+ int err;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ntcreate(ssp, name_mb, NULL, NULL,
+ crflag, req_acc, efa, sh_acc, disp, createopt,
+ impersonate, scrp, &fhp->fh_fid2, cr_act_p, fap);
+ } else {
+ err = smb1_smb_ntcreate(ssp, name_mb, crflag, req_acc,
+ efa, sh_acc, disp, createopt, impersonate, scrp,
+ &fhp->fh_fid1, cr_act_p, fap);
+ }
+ return (err);
+}
+
+int
+smb_smb_close(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp)
+{
+ int err;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_close(ssp, &fhp->fh_fid2, scrp);
+ } else {
+ err = smb1_smb_close(ssp, fhp->fh_fid1, NULL, scrp);
+ }
+
+ return (err);
+}
+
+/*
+ * Largest size to use with LARGE_READ/LARGE_WRITE.
+ * Specs say up to 64k data bytes, but Windows traffic
+ * uses 60k... no doubt for some good reason.
+ * (Probably to keep 4k block alignment.)
+ */
+uint32_t smb1_large_io_max = (60*1024);
+
+/*
+ * Common function for read/write with UIO.
+ * Called by netsmb smb_usr_rw,
+ * smbfs_readvnode, smbfs_writevnode
+ */
+int
+smb_rwuio(smb_fh_t *fhp, uio_rw_t rw,
+ uio_t *uiop, smb_cred_t *scred, int timo)
+{
+ struct smb_share *ssp = FHTOSS(fhp);
+ struct smb_vc *vcp = SSTOVC(ssp);
+ ssize_t save_resid;
+ uint32_t len, rlen, maxlen;
+ int error = 0;
+ int (*iofun)(smb_fh_t *, uint32_t *,
+ uio_t *, smb_cred_t *, int);
+
+ /* After reconnect, the fid is invalid. */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ if (rw == UIO_READ) {
+ iofun = smb2_smb_read;
+ maxlen = vcp->vc_sopt.sv2_maxread;
+ } else { /* UIO_WRITE */
+ iofun = smb2_smb_write;
+ maxlen = vcp->vc_sopt.sv2_maxwrite;
+ }
+ } else {
+ /*
+ * Using NT LM 0.12, so readx, writex.
+ * Make sure we can represent the offset.
+ */
+ if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
+ (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
+ return (EFBIG);
+
+ if (rw == UIO_READ) {
+ iofun = smb_smb_readx;
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
+ maxlen = smb1_large_io_max;
+ else
+ maxlen = vcp->vc_rxmax;
+ } else { /* UIO_WRITE */
+ iofun = smb_smb_writex;
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
+ maxlen = smb1_large_io_max;
+ else
+ maxlen = vcp->vc_wxmax;
+ }
+ }
+
+ save_resid = uiop->uio_resid;
+ while (uiop->uio_resid > 0) {
+ /* Lint: uio_resid may be 64-bits */
+ rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
+ error = (*iofun)(fhp, &rlen, uiop, scred, timo);
+
+ /*
+ * Note: the iofun called uio_update, so
+ * not doing that here as one might expect.
+ *
+ * Quit the loop either on error, or if we
+ * transferred less then requested.
+ */
+ if (error || (rlen < len))
+ break;
+
+ timo = 0; /* only first I/O should wait */
+ }
+ if (error && (save_resid != uiop->uio_resid)) {
+ /*
+ * Stopped on an error after having
+ * successfully transferred data.
+ * Suppress this error.
+ */
+ SMBSDEBUG("error %d suppressed\n", error);
+ error = 0;
+ }
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
index e984ded911..0116d6ea6e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -55,61 +57,6 @@
#include <netsmb/smb_subr.h>
/*
- * Time & date conversion routines taken from msdosfs. Although leap
- * year calculation is bogus, it's sufficient before 2100 :)
- */
-/*
- * This is the format of the contents of the deTime field in the direntry
- * structure.
- * We don't use bitfields because we don't know how compilers for
- * arbitrary machines will lay them out.
- */
-#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
-#define DT_2SECONDS_SHIFT 0
-#define DT_MINUTES_MASK 0x7E0 /* minutes */
-#define DT_MINUTES_SHIFT 5
-#define DT_HOURS_MASK 0xF800 /* hours */
-#define DT_HOURS_SHIFT 11
-
-/*
- * This is the format of the contents of the deDate field in the direntry
- * structure.
- */
-#define DD_DAY_MASK 0x1F /* day of month */
-#define DD_DAY_SHIFT 0
-#define DD_MONTH_MASK 0x1E0 /* month */
-#define DD_MONTH_SHIFT 5
-#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
-#define DD_YEAR_SHIFT 9
-/*
- * Total number of days that have passed for each month in a regular year.
- */
-static ushort_t regyear[] = {
- 31, 59, 90, 120, 151, 181,
- 212, 243, 273, 304, 334, 365
-};
-
-/*
- * Total number of days that have passed for each month in a leap year.
- */
-static ushort_t leapyear[] = {
- 31, 60, 91, 121, 152, 182,
- 213, 244, 274, 305, 335, 366
-};
-
-/*
- * Variables used to remember parts of the last time conversion. Maybe we
- * can avoid a full conversion.
- */
-static ulong_t lasttime;
-static ulong_t lastday;
-static ushort_t lastddate;
-static ushort_t lastdtime;
-
-/* Lock for the lastxxx variables */
-static kmutex_t lastdt_lock;
-
-/*
* Number of seconds between 1970 and 1601 year
* (134774 days)
*/
@@ -193,161 +140,3 @@ smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp)
tsp->tv_sec = seconds + tzoff * 60;
tsp->tv_nsec = 0;
}
-
-/*
- * Time conversions to/from DOS format, for old dialects.
- */
-
-void
-smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
- u_int16_t *dtp, u_int8_t *dhp)
-{
- long t;
- ulong_t days, year, month, inc;
- ushort_t *months;
-
- mutex_enter(&lastdt_lock);
-
- /*
- * If the time from the last conversion is the same as now, then
- * skip the computations and use the saved result.
- */
- smb_time_local2server(tsp, tzoff, &t);
- t &= ~1;
- if (lasttime != t) {
- lasttime = t;
- if (t < 0) {
- /*
- * This is before 1970, so it's before 1980,
- * and can't be represented as a DOS time.
- * Just represent it as the DOS epoch.
- */
- lastdtime = 0;
- lastddate = (1 << DD_DAY_SHIFT)
- + (1 << DD_MONTH_SHIFT)
- + ((1980 - 1980) << DD_YEAR_SHIFT);
- } else {
- lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
- + (((t / 60) % 60) << DT_MINUTES_SHIFT)
- + (((t / 3600) % 24) << DT_HOURS_SHIFT);
-
- /*
- * If the number of days since 1970 is the same as
- * the last time we did the computation then skip
- * all this leap year and month stuff.
- */
- days = t / (24 * 60 * 60);
- if (days != lastday) {
- lastday = days;
- for (year = 1970; ; year++) {
- /*
- * XXX - works in 2000, but won't
- * work in 2100.
- */
- inc = year & 0x03 ? 365 : 366;
- if (days < inc)
- break;
- days -= inc;
- }
- /*
- * XXX - works in 2000, but won't work in 2100.
- */
- months = year & 0x03 ? regyear : leapyear;
- for (month = 0; days >= months[month]; month++)
- ;
- if (month > 0)
- days -= months[month - 1];
- lastddate = ((days + 1) << DD_DAY_SHIFT)
- + ((month + 1) << DD_MONTH_SHIFT);
- /*
- * Remember DOS's idea of time is relative
- * to 1980, but UN*X's is relative to 1970.
- * If somehow we get a time before 1980 then
- * don't give totally crazy results.
- */
- if (year > 1980)
- lastddate += (year - 1980) <<
- DD_YEAR_SHIFT;
- }
- }
- }
- if (dhp)
- *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
-
- *ddp = lastddate;
- *dtp = lastdtime;
-
- mutex_exit(&lastdt_lock);
-}
-
-/*
- * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
- * interval there were 8 regular years and 2 leap years.
- */
-#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
-
-static ushort_t lastdosdate;
-static ulong_t lastseconds;
-
-void
-smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
- struct timespec *tsp)
-{
- ulong_t seconds;
- ulong_t month;
- ulong_t year;
- ulong_t days;
- ushort_t *months;
-
- if (dd == 0) {
- tsp->tv_sec = 0;
- tsp->tv_nsec = 0;
- return;
- }
- seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
- + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
- + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
- + dh / 100;
-
- /*
- * If the year, month, and day from the last conversion are the
- * same then use the saved value.
- */
- mutex_enter(&lastdt_lock);
- if (lastdosdate != dd) {
- lastdosdate = (ushort_t)dd;
- days = 0;
- year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
- days = year * 365;
- days += year / 4 + 1; /* add in leap days */
- /*
- * XXX - works in 2000, but won't work in 2100.
- */
- if ((year & 0x03) == 0)
- days--; /* if year is a leap year */
- months = year & 0x03 ? regyear : leapyear;
- month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
- if (month < 1 || month > 12) {
- month = 1;
- }
- if (month > 1)
- days += months[month - 2];
- days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
- lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
- }
- smb_time_server2local(seconds + lastseconds, tzoff, tsp);
- tsp->tv_nsec = (dh % 100) * 10000000;
- mutex_exit(&lastdt_lock);
-}
-
-void
-smb_time_init(void)
-{
- mutex_init(&lastdt_lock, NULL, MUTEX_DEFAULT, NULL);
-}
-
-void
-smb_time_fini(void)
-{
- mutex_destroy(&lastdt_lock);
-}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
index f954056a79..1060139491 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_TRAN_H_
@@ -42,6 +44,9 @@
#include <sys/socket.h>
#include <sys/stream.h>
+#ifndef _KERNEL
+struct file;
+#endif
/*
* Known transports
@@ -49,11 +54,14 @@
#define SMBT_NBTCP 1
/*
- * Transport parameters
+ * Transport parameters, for tr_getparam/tr_setparam
*/
-#define SMBTP_SNDSZ 1 /* R - int */
-#define SMBTP_RCVSZ 2 /* R - int */
-#define SMBTP_TIMEOUT 3 /* RW - struct timespec */
+#define SMBTP_TCP_NODELAY 0x01 /* RW - int */
+#define SMBTP_TCP_CON_TMO 0x13 /* RW - int */
+#define SMBTP_KEEPALIVE SO_KEEPALIVE /* RW - int */
+#define SMBTP_SNDBUF SO_SNDBUF /* RW - int */
+#define SMBTP_RCVBUF SO_RCVBUF /* RW - int */
+#define SMBTP_RCVTIMEO SO_RCVTIMEO /* RW - int? */
struct smb_tran_ops;
@@ -62,12 +70,12 @@ struct smb_tran_desc {
int (*tr_create)(struct smb_vc *vcp, cred_t *cr);
int (*tr_done)(struct smb_vc *vcp);
int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap);
+ int (*tr_unbind)(struct smb_vc *vcp);
int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap);
int (*tr_disconnect)(struct smb_vc *vcp);
int (*tr_send)(struct smb_vc *vcp, mblk_t *m);
int (*tr_recv)(struct smb_vc *vcp, mblk_t **mpp);
int (*tr_poll)(struct smb_vc *vcp, int ticks);
- int (*tr_loan_fp)(struct smb_vc *, struct file *, cred_t *cr);
int (*tr_getparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_setparam)(struct smb_vc *vcp, int param, void *data);
int (*tr_fatal)(struct smb_vc *vcp, int error);
@@ -78,12 +86,12 @@ typedef struct smb_tran_desc smb_tran_desc_t;
#define SMB_TRAN_CREATE(vcp, cr) (vcp)->vc_tdesc->tr_create(vcp, cr)
#define SMB_TRAN_DONE(vcp) (vcp)->vc_tdesc->tr_done(vcp)
#define SMB_TRAN_BIND(vcp, sap) (vcp)->vc_tdesc->tr_bind(vcp, sap)
+#define SMB_TRAN_UNBIND(vcp) (vcp)->vc_tdesc->tr_unbind(vcp)
#define SMB_TRAN_CONNECT(vcp, sap) (vcp)->vc_tdesc->tr_connect(vcp, sap)
#define SMB_TRAN_DISCONNECT(vcp) (vcp)->vc_tdesc->tr_disconnect(vcp)
#define SMB_TRAN_SEND(vcp, m) (vcp)->vc_tdesc->tr_send(vcp, m)
#define SMB_TRAN_RECV(vcp, m) (vcp)->vc_tdesc->tr_recv(vcp, m)
#define SMB_TRAN_POLL(vcp, t) (vcp)->vc_tdesc->tr_poll(vcp, t)
-#define SMB_TRAN_LOAN_FP(vcp, f, cr) (vcp)->vc_tdesc->tr_loan_fp(vcp, f, cr)
#define SMB_TRAN_GETPARAM(vcp, par, data) \
(vcp)->vc_tdesc->tr_getparam(vcp, par, data)
#define SMB_TRAN_SETPARAM(vcp, par, data) \
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
index 4f101a4f5f..849e91637e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
@@ -34,7 +34,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -73,13 +74,6 @@
#include <netsmb/smb_tran.h>
#include <netsmb/smb_trantcp.h>
-/*
- * SMB messages are up to 64K.
- * Let's leave room for two.
- */
-static int smb_tcpsndbuf = 0x20000;
-static int smb_tcprcvbuf = 0x20000;
-
static int nb_disconnect(struct nbpcb *nbp);
@@ -163,7 +157,7 @@ nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
case T_DISCON_IND:
/* Peer disconnected. */
NBDEBUG("T_DISCON_IND: reason=%d",
- pptr->discon_ind.DISCON_reason);
+ (int)pptr->discon_ind.DISCON_reason);
goto discon;
case T_ORDREL_IND:
/* Peer disconnecting. */
@@ -176,11 +170,11 @@ nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
goto discon;
default:
NBDEBUG("T_OK_ACK/prim=%d",
- pptr->ok_ack.CORRECT_prim);
+ (int)pptr->ok_ack.CORRECT_prim);
goto discon;
}
default:
- NBDEBUG("M_PROTO/type=%d", pptr->type);
+ NBDEBUG("M_PROTO/type=%d", (int)pptr->type);
goto discon;
}
break; /* M_PROTO, M_PCPROTO */
@@ -485,22 +479,45 @@ out:
* This is called only by the thread creating this endpoint,
* so we're single-threaded here.
*/
-/*ARGSUSED*/
static int
smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
{
- struct nbpcb *nbp;
+ TIUSER *tiptr = NULL;
+ struct nbpcb *nbp = NULL;
+ dev_t dev;
+ int rc;
+ ushort_t fmode;
+
+ switch (vcp->vc_srvaddr.sa.sa_family) {
+ case AF_INET:
+ dev = nsmb_dev_tcp;
+ break;
+ case AF_INET6:
+ dev = nsmb_dev_tcp6;
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ fmode = FREAD|FWRITE;
+ rc = t_kopen(NULL, dev, fmode, &tiptr, cr);
+ if (rc != 0) {
+ cmn_err(CE_NOTE, "t_kopen failed, rc=%d", rc);
+ return (rc);
+ }
+ ASSERT(tiptr != NULL);
nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
nbp->nbp_timo.tv_sec = SMB_NBTIMO;
- nbp->nbp_state = NBST_CLOSED; /* really IDLE */
+ nbp->nbp_state = NBST_IDLE;
nbp->nbp_vc = vcp;
- nbp->nbp_sndbuf = smb_tcpsndbuf;
- nbp->nbp_rcvbuf = smb_tcprcvbuf;
+ nbp->nbp_tiptr = tiptr;
+ nbp->nbp_fmode = fmode;
nbp->nbp_cred = cr;
crhold(cr);
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
+
vcp->vc_tdata = nbp;
return (0);
@@ -541,111 +558,74 @@ smb_nbst_done(struct smb_vc *vcp)
return (0);
}
-/*
- * Loan a transport file pointer (from user space) to this
- * IOD endpoint. There should be no other thread using this
- * endpoint when we do this, but lock for consistency.
- */
static int
-nb_loan_fp(struct nbpcb *nbp, struct file *fp, cred_t *cr)
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
{
- TIUSER *tiptr;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
int err;
- err = t_kopen(fp, 0, 0, &tiptr, cr);
- if (err != 0)
- return (err);
+ /* Only default bind supported. */
+ if (sap != NULL)
+ return (ENOTSUP);
- mutex_enter(&nbp->nbp_lock);
-
- nbp->nbp_tiptr = tiptr;
- nbp->nbp_fmode = tiptr->fp->f_flag;
- nbp->nbp_flags |= NBF_CONNECTED;
- nbp->nbp_state = NBST_SESSION;
-
- mutex_exit(&nbp->nbp_lock);
+ err = t_kbind(tiptr, NULL, NULL);
- return (0);
+ return (err);
}
-/*
- * Take back the transport file pointer we previously loaned.
- * It's possible there may be another thread in here, so let
- * others get out of the way before we pull the rug out.
- *
- * Some notes about the locking here: The higher-level IOD code
- * serializes activity such that at most one reader and writer
- * thread can be active in this code (and possibly both).
- * Keeping nbp_lock held during the activities of these two
- * threads would lead to the possibility of nbp_lock being
- * held by a blocked thread, so this instead sets one of the
- * flags (NBF_SENDLOCK | NBF_RECVLOCK) when a sender or a
- * receiver is active (respectively). Lastly, tear-down is
- * the only tricky bit (here) where we must wait for any of
- * these activities to get out of current calls so they will
- * notice that we've turned off the NBF_CONNECTED flag.
- */
-static void
-nb_unloan_fp(struct nbpcb *nbp)
+static int
+smb_nbst_unbind(struct smb_vc *vcp)
{
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int err;
- mutex_enter(&nbp->nbp_lock);
-
- nbp->nbp_flags &= ~NBF_CONNECTED;
- while (nbp->nbp_flags & (NBF_SENDLOCK | NBF_RECVLOCK)) {
- nbp->nbp_flags |= NBF_LOCKWAIT;
- cv_wait(&nbp->nbp_cv, &nbp->nbp_lock);
- }
- if (nbp->nbp_frag != NULL) {
- freemsg(nbp->nbp_frag);
- nbp->nbp_frag = NULL;
- }
- if (nbp->nbp_tiptr != NULL) {
- (void) t_kclose(nbp->nbp_tiptr, 0);
- nbp->nbp_tiptr = NULL;
- }
- nbp->nbp_state = NBST_CLOSED;
+ err = t_kunbind(tiptr);
- mutex_exit(&nbp->nbp_lock);
+ return (err);
}
static int
-smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
{
- struct nbpcb *nbp = vcp->vc_tdata;
- int error = 0;
+ struct t_call call;
+ struct nbpcb *nbp = vcp->vc_tdata;
+ TIUSER *tiptr = nbp->nbp_tiptr;
+ int alen, err;
+
+ /* Need the address length */
+ switch (sap->sa_family) {
+ case AF_INET:
+ alen = sizeof (struct sockaddr_in);
+ break;
+ case AF_INET6:
+ alen = sizeof (struct sockaddr_in6);
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
- /*
- * Un-loan the existing one, if any.
- */
- (void) nb_disconnect(nbp);
- nb_unloan_fp(nbp);
+ /* sockaddr goes in the "addr" netbuf */
+ bzero(&call, sizeof (call));
+ call.addr.buf = (char *)sap;
+ call.addr.len = alen;
+ call.addr.maxlen = alen;
- /*
- * Loan the new one passed in.
- */
- if (fp != NULL) {
- error = nb_loan_fp(nbp, fp, cr);
- }
+ err = t_kconnect(tiptr, &call, NULL);
+ if (err != 0)
+ return (err);
- return (error);
-}
+ mutex_enter(&nbp->nbp_lock);
-/*ARGSUSED*/
-static int
-smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
-}
+ nbp->nbp_flags |= NBF_CONNECTED;
+ nbp->nbp_state = NBST_SESSION;
-/*ARGSUSED*/
-static int
-smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
-{
- return (ENOTSUP);
+ mutex_exit(&nbp->nbp_lock);
+
+ return (0);
}
-/*ARGSUSED*/
static int
smb_nbst_disconnect(struct smb_vc *vcp)
{
@@ -832,42 +812,78 @@ smb_nbst_poll(struct smb_vc *vcp, int ticks)
return (ENOTSUP);
}
+/*ARGSUSED*/
static int
smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
{
+ return (EINVAL);
+}
+
+static int
+smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
+{
+ struct t_optmgmt oreq, ores;
+ struct {
+ struct T_opthdr oh;
+ int ival;
+ } opts;
struct nbpcb *nbp = vcp->vc_tdata;
+ int level, name, err;
switch (param) {
- case SMBTP_SNDSZ:
- *(int *)data = nbp->nbp_sndbuf;
+ case SMBTP_TCP_NODELAY:
+ level = IPPROTO_TCP;
+ name = TCP_NODELAY;
break;
- case SMBTP_RCVSZ:
- *(int *)data = nbp->nbp_rcvbuf;
- break;
- case SMBTP_TIMEOUT:
- *(struct timespec *)data = nbp->nbp_timo;
- break;
-#ifdef SMBTP_SELECTID
- case SMBTP_SELECTID:
- *(void **)data = nbp->nbp_selectid;
+
+ case SMBTP_TCP_CON_TMO: /* int mSec */
+ level = IPPROTO_TCP;
+ name = TCP_CONN_ABORT_THRESHOLD;
break;
-#endif
-#ifdef SMBTP_UPCALL
- case SMBTP_UPCALL:
- *(void **)data = nbp->nbp_upcall;
+
+ case SMBTP_KEEPALIVE: // SO_KEEPALIVE
+ case SMBTP_SNDBUF: // SO_SNDBUF
+ case SMBTP_RCVBUF: // SO_RCVBUF
+ case SMBTP_RCVTIMEO: // SO_RCVTIMEO
+ level = SOL_SOCKET;
+ name = param;
break;
-#endif
+
default:
return (EINVAL);
}
- return (0);
-}
-/*ARGSUSED*/
-static int
-smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
-{
- return (EINVAL);
+ /* opt header */
+ opts.oh.len = sizeof (opts);
+ opts.oh.level = level;
+ opts.oh.name = name;
+ opts.oh.status = 0;
+ opts.ival = *(int *)data;
+
+ oreq.flags = T_NEGOTIATE;
+ oreq.opt.buf = (void *)&opts;
+ oreq.opt.len = sizeof (opts);
+ oreq.opt.maxlen = oreq.opt.len;
+
+ ores.flags = 0;
+ ores.opt.buf = NULL;
+ ores.opt.len = 0;
+ ores.opt.maxlen = 0;
+
+ err = t_koptmgmt(nbp->nbp_tiptr, &oreq, &ores);
+ if (err != 0) {
+ cmn_err(CE_NOTE, "t_opgmgnt, err = %d", err);
+ return (EPROTO);
+ }
+
+ if ((ores.flags & T_SUCCESS) == 0) {
+ cmn_err(CE_NOTE, "smb_nbst_setparam: "
+ "flags 0x%x, status 0x%x",
+ (int)ores.flags, (int)opts.oh.status);
+ return (EPROTO);
+ }
+
+ return (0);
}
/*
@@ -893,12 +909,12 @@ struct smb_tran_desc smb_tran_nbtcp_desc = {
smb_nbst_create,
smb_nbst_done,
smb_nbst_bind,
+ smb_nbst_unbind,
smb_nbst_connect,
smb_nbst_disconnect,
smb_nbst_send,
smb_nbst_recv,
smb_nbst_poll,
- smb_nbst_loan_fp,
smb_nbst_getparam,
smb_nbst_setparam,
smb_nbst_fatal,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
index f810a538cd..3c5e86639e 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h
@@ -32,13 +32,14 @@
* $Id: smb_trantcp.h,v 1.8 2004/08/03 23:50:01 lindak Exp $
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_TRANTCP_H_
#define _NETSMB_SMB_TRANTCP_H_
enum nbstate {
NBST_CLOSED,
+ NBST_IDLE,
NBST_RQSENT,
NBST_SESSION,
NBST_RETARGET,
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
index fb587cd79e..d83c3a086c 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -52,6 +53,7 @@
#include <netsmb/smb_osdep.h>
+#include <smb/winioctl.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_rq.h>
@@ -61,28 +63,6 @@
static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
/*
- * Ioctl function for SMBIOC_FLAGS2
- */
-int
-smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
-{
- struct smb_vc *vcp = NULL;
-
- /* This ioctl requires a session. */
- if ((vcp = sdp->sd_vc) == NULL)
- return (ENOTCONN);
-
- /*
- * Return the flags2 value.
- */
- if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
- sizeof (u_int16_t), flags))
- return (EFAULT);
-
- return (0);
-}
-
-/*
* Ioctl function for SMBIOC_GETSSNKEY
* Size copied out is SMBIOC_HASH_SZ.
*
@@ -105,7 +85,10 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
/*
* Return the session key.
*/
- if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
+ if (vcp->vc_ssnkey == NULL ||
+ vcp->vc_ssnkeylen < SMBIOC_HASH_SZ)
+ return (EINVAL);
+ if (ddi_copyout(vcp->vc_ssnkey, (void *)arg,
SMBIOC_HASH_SZ, flags))
return (EFAULT);
@@ -113,224 +96,90 @@ smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
}
/*
- * Ioctl function for SMBIOC_REQUEST
+ * Ioctl function for SMBIOC_XACTNP (transact named pipe)
*/
int
-smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
struct smb_cred scred;
struct smb_share *ssp;
- smbioc_rq_t *ioc = NULL;
- struct smb_rq *rqp = NULL;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint32_t rsz;
+ struct smb_fh *fhp;
+ smbioc_xnp_t *ioc = NULL;
+ struct mbchain send_mb;
+ struct mdchain recv_md;
+ uint32_t rdlen;
int err, mbseg;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
-
- smb_credinit(&scred, cr);
- ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
- if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
- err = EFAULT;
- goto out;
- }
-
- /* See ddi_copyin, ddi_copyout */
- mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
-
- /*
- * Lots of SMB commands could be safe, but
- * these are the only ones used by libsmbfs.
- */
- switch (ioc->ioc_cmd) {
- /* These are OK */
- case SMB_COM_CLOSE:
- case SMB_COM_FLUSH:
- case SMB_COM_NT_CREATE_ANDX:
- case SMB_COM_OPEN_PRINT_FILE:
- case SMB_COM_CLOSE_PRINT_FILE:
- break;
-
- default:
- err = EPERM;
- goto out;
- }
-
- err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
- if (err)
- goto out;
-
- mbp = &rqp->sr_rq;
- err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
-
- err = smb_rq_simple(rqp);
- if (err == 0) {
- /*
- * This may have been an open, so save the
- * generation ID of the share, which we
- * check before trying read or write.
- */
- sdp->sd_vcgenid = ssp->ss_vcgenid;
-
- /*
- * Have reply data. to copyout.
- * SMB header already parsed.
- */
- mdp = &rqp->sr_rp;
- rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
- if (ioc->ioc_rbufsz < rsz) {
- err = EOVERFLOW;
- goto out;
- }
- ioc->ioc_rbufsz = rsz;
- err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
- if (err)
- goto out;
-
- }
-
- ioc->ioc_errclass = rqp->sr_errclass;
- ioc->ioc_serror = rqp->sr_serror;
- ioc->ioc_error = rqp->sr_error;
- (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
-
-out:
- if (rqp != NULL)
- smb_rq_done(rqp); /* free rqp */
- kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
-
- return (err);
-
-}
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ ssp = FHTOSS(fhp);
-/*
- * Ioctl function for SMBIOC_T2RQ
- */
-int
-smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
-{
- struct smb_cred scred;
- struct smb_share *ssp;
- smbioc_t2rq_t *ioc = NULL;
- struct smb_t2rq *t2p = NULL;
- struct mdchain *mdp;
- int err, len, mbseg;
+ /* After reconnect, force close+reopen */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ bzero(&send_mb, sizeof (send_mb));
+ bzero(&recv_md, sizeof (recv_md));
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
goto out;
}
- /* See ddi_copyin, ddi_copyout */
+ /*
+ * Copyin the send data, into an mbchain,
+ * save output buffer size.
+ */
mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
-
- if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
- err = EINVAL;
+ err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
+ if (err)
goto out;
- }
+ rdlen = ioc->ioc_rdlen;
/*
- * Fill in the FID for libsmbfs transact named pipe.
+ * Run the SMB2 ioctl or SMB1 trans2
*/
- if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) {
- if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
- err = ESTALE;
- goto out;
- }
- ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid;
- }
-
- t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
- err = smb_t2_init(t2p, SSTOCP(ssp),
- ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
- if (err)
- goto out;
- t2p->t2_setupcount = ioc->ioc_setupcnt;
- t2p->t2_setupdata = ioc->ioc_setup;
-
- /* This ioc member is a fixed-size array. */
- if (ioc->ioc_name[0]) {
- /* Get the name length - carefully! */
- ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
- t2p->t_name_len = strlen(ioc->ioc_name);
- t2p->t_name = ioc->ioc_name;
+ smb_credinit(&scred, cr);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ioctl(ssp, &fhp->fh_fid2,
+ &send_mb, &recv_md, &rdlen,
+ FSCTL_PIPE_TRANSCEIVE, &scred);
+ } else {
+ err = smb_t2_xnp(ssp, fhp->fh_fid1,
+ &send_mb, &recv_md, &rdlen,
+ &ioc->ioc_more, &scred);
}
- t2p->t2_maxscount = 0;
- t2p->t2_maxpcount = ioc->ioc_rparamcnt;
- t2p->t2_maxdcount = ioc->ioc_rdatacnt;
-
- /* Transmit parameters */
- err = smb_cpdatain(&t2p->t2_tparam,
- ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
- if (err)
- goto out;
-
- /* Transmit data */
- err = smb_cpdatain(&t2p->t2_tdata,
- ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
- if (err)
- goto out;
-
- err = smb_t2_request(t2p);
-
- /* Copyout returned parameters. */
- mdp = &t2p->t2_rparam;
- if (err == 0 && mdp->md_top != NULL) {
- /* User's buffer large enough? */
- len = m_fixhdr(mdp->md_top);
- if (len > ioc->ioc_rparamcnt) {
- err = EMSGSIZE;
- goto out;
- }
- ioc->ioc_rparamcnt = (ushort_t)len;
- err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
- if (err)
- goto out;
- } else
- ioc->ioc_rparamcnt = 0;
+ smb_credrele(&scred);
/* Copyout returned data. */
- mdp = &t2p->t2_rdata;
- if (err == 0 && mdp->md_top != NULL) {
- /* User's buffer large enough? */
- len = m_fixhdr(mdp->md_top);
- if (len > ioc->ioc_rdatacnt) {
+ if (err == 0 && recv_md.md_top != NULL) {
+ /* User's buffer large enough for copyout? */
+ size_t len = m_fixhdr(recv_md.md_top);
+ if (len > ioc->ioc_rdlen) {
err = EMSGSIZE;
goto out;
}
- ioc->ioc_rdatacnt = (ushort_t)len;
- err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
+ err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg);
if (err)
goto out;
} else
- ioc->ioc_rdatacnt = 0;
+ ioc->ioc_rdlen = 0;
- ioc->ioc_errclass = t2p->t2_sr_errclass;
- ioc->ioc_serror = t2p->t2_sr_serror;
- ioc->ioc_error = t2p->t2_sr_error;
- ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
+ /* Tell caller received length */
+ if (rdlen <= ioc->ioc_rdlen) {
+ /* Normal case */
+ ioc->ioc_rdlen = rdlen;
+ } else {
+ /* Buffer overlow. Leave ioc_rdlen */
+ ioc->ioc_more = 1;
+ }
(void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
-
out:
- if (t2p != NULL) {
- /* Note: t2p->t_name no longer allocated */
- smb_t2_done(t2p);
- kmem_free(t2p, sizeof (*t2p));
- }
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
return (err);
}
@@ -358,22 +207,22 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
struct smb_cred scred;
struct smb_share *ssp;
+ struct smb_fh *fhp;
smbioc_rw_t *ioc = NULL;
struct iovec aiov[1];
struct uio auio;
- uint16_t fh;
int err;
uio_rw_t rw;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ ssp = FHTOSS(fhp);
/* After reconnect, force close+reopen */
- if (sdp->sd_vcgenid != ssp->ss_vcgenid)
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
return (ESTALE);
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
@@ -392,15 +241,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
goto out;
}
- /*
- * If caller passes -1 in ioc_fh, then
- * use the FID from SMBIOC_NTCREATE.
- */
- if (ioc->ioc_fh == -1)
- fh = (uint16_t)sdp->sd_smbfid;
- else
- fh = (uint16_t)ioc->ioc_fh;
-
aiov[0].iov_base = ioc->ioc_base;
aiov[0].iov_len = (size_t)ioc->ioc_cnt;
@@ -412,7 +252,9 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
auio.uio_fmode = 0;
auio.uio_resid = (size_t)ioc->ioc_cnt;
- err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
+ smb_credinit(&scred, cr);
+ err = smb_rwuio(fhp, rw, &auio, &scred, 0);
+ smb_credrele(&scred);
/*
* On return ioc_cnt holds the
@@ -424,7 +266,6 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
out:
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
return (err);
}
@@ -439,20 +280,20 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
struct smb_cred scred;
struct mbchain name_mb;
struct smb_share *ssp;
+ struct smb_fh *fhp = NULL;
smbioc_ntcreate_t *ioc = NULL;
- uint16_t fid;
int err, nmlen;
+ mb_init(&name_mb);
+
/* This ioctl requires a share. */
if ((ssp = sdp->sd_share) == NULL)
return (ENOTCONN);
- /* Must not be already open. */
- if (sdp->sd_smbfid != -1)
+ /* Must not already have a file handle. */
+ if (sdp->sd_fh != NULL)
return (EINVAL);
- mb_init(&name_mb);
- smb_credinit(&scred, cr);
ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
err = EFAULT;
@@ -468,7 +309,14 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
if (err != 0)
goto out;
- /* Do the OtW open, save the FID. */
+ err = smb_fh_create(ssp, &fhp);
+ if (err != 0)
+ goto out;
+
+ /*
+ * Do the OtW open, save the FID.
+ */
+ smb_credinit(&scred, cr);
err = smb_smb_ntcreate(ssp, &name_mb,
0, /* create flags */
ioc->ioc_req_acc,
@@ -478,18 +326,22 @@ smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
ioc->ioc_creat_opts,
NTCREATEX_IMPERSONATION_IMPERSONATION,
&scred,
- &fid,
+ fhp,
NULL,
NULL);
+ smb_credrele(&scred);
if (err != 0)
goto out;
- sdp->sd_smbfid = fid;
- sdp->sd_vcgenid = ssp->ss_vcgenid;
+ fhp->fh_rights = ioc->ioc_req_acc;
+ smb_fh_opened(fhp);
+ sdp->sd_fh = fhp;
+ fhp = NULL;
out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
mb_done(&name_mb);
return (err);
@@ -502,11 +354,17 @@ out:
int
smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
{
+ static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
struct smb_cred scred;
+ struct mbchain name_mb;
struct smb_share *ssp;
+ struct smb_fh *fhp = NULL;
smbioc_printjob_t *ioc = NULL;
- uint16_t fid;
- int err;
+ int err, cklen, nmlen;
+ uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
+ SA_RIGHT_FILE_READ_ATTRIBUTES;
+
+ mb_init(&name_mb);
/* This ioctl requires a share. */
if ((ssp = sdp->sd_share) == NULL)
@@ -516,8 +374,8 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
if (ssp->ss_type != STYPE_PRINTQ)
return (EINVAL);
- /* Must not be already open. */
- if (sdp->sd_smbfid != -1)
+ /* Must not already have a file handle. */
+ if (sdp->sd_fh != NULL)
return (EINVAL);
smb_credinit(&scred, cr);
@@ -526,21 +384,68 @@ smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
err = EFAULT;
goto out;
}
+
+ /*
+ * Use the print job title as the file name to open, but
+ * check for invalid characters first. See the notes in
+ * libsmbfs/smb/print.c about job name sanitizing.
+ */
ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
+ nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1);
+ cklen = strcspn(ioc->ioc_title, invalid_chars);
+ if (cklen < nmlen) {
+ err = EINVAL;
+ goto out;
+ }
- /* Do the OtW open, save the FID. */
- err = smb_smb_open_prjob(ssp, ioc->ioc_title,
- ioc->ioc_setuplen, ioc->ioc_prmode,
- &scred, &fid);
+ /* Build name_mb */
+ err = smb_put_dmem(&name_mb, SSTOVC(ssp),
+ ioc->ioc_title, nmlen,
+ SMB_CS_NONE, NULL);
if (err != 0)
goto out;
- sdp->sd_smbfid = fid;
- sdp->sd_vcgenid = ssp->ss_vcgenid;
+ err = smb_fh_create(ssp, &fhp);
+ if (err != 0)
+ goto out;
+
+ /*
+ * Do the OtW open, save the FID.
+ */
+ smb_credinit(&scred, cr);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smb2_smb_ntcreate(ssp, &name_mb,
+ NULL, NULL, /* cctx in, out */
+ 0, /* create flags */
+ access,
+ SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ NTCREATEX_IMPERSONATION_IMPERSONATION,
+ &scred,
+ &fhp->fh_fid2,
+ NULL,
+ NULL);
+ } else {
+ err = smb_smb_open_prjob(ssp, ioc->ioc_title,
+ ioc->ioc_setuplen, ioc->ioc_prmode,
+ &scred, &fhp->fh_fid1);
+ }
+ smb_credrele(&scred);
+ if (err != 0)
+ goto out;
+
+ fhp->fh_rights = access;
+ smb_fh_opened(fhp);
+ sdp->sd_fh = fhp;
+ fhp = NULL;
out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
kmem_free(ioc, sizeof (*ioc));
- smb_credrele(&scred);
+ mb_done(&name_mb);
return (err);
}
@@ -549,31 +454,21 @@ out:
* Helper for nsmb_ioctl case
* SMBIOC_CLOSEFH
*/
+/*ARGSUSED*/
int
smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
{
- struct smb_cred scred;
- struct smb_share *ssp;
- uint16_t fid;
- int err;
+ struct smb_fh *fhp;
- /* This ioctl requires a share. */
- if ((ssp = sdp->sd_share) == NULL)
- return (ENOTCONN);
+ /* This ioctl requires a file handle. */
+ if ((fhp = sdp->sd_fh) == NULL)
+ return (EINVAL);
+ sdp->sd_fh = NULL;
- if (sdp->sd_smbfid == -1)
- return (0);
- fid = (uint16_t)sdp->sd_smbfid;
- sdp->sd_smbfid = -1;
+ smb_fh_close(fhp);
+ smb_fh_rele(fhp);
- smb_credinit(&scred, cr);
- if (ssp->ss_type == STYPE_PRINTQ)
- err = smb_smb_close_prjob(ssp, fid, &scred);
- else
- err = smb_smb_close(ssp, fid, NULL, &scred);
- smb_credrele(&scred);
-
- return (err);
+ return (0);
}
/*
@@ -825,24 +720,22 @@ smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
return (0);
}
-
/*
- * Ioctl function: SMBIOC_IOD_WORK
- *
- * Become the reader (IOD) thread, until either the connection is
- * reset by the server, or until the connection is idle longer than
- * some max time. (max idle time not yet implemented)
+ * Ioctl handler for all SMBIOC_IOD_...
*/
int
-smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
+ struct smb_vc *vcp;
int err = 0;
- /* Must have a valid session. */
+ /* Must be the IOD. */
+ if ((sdp->sd_flags & NSMBFL_IOD) == 0)
+ return (EINVAL);
+ /* Must have a VC and no share. */
if ((vcp = sdp->sd_vc) == NULL)
return (EINVAL);
- if (vcp->vc_flags & SMBV_GONE)
+ if (sdp->sd_share != NULL)
return (EINVAL);
/*
@@ -859,39 +752,53 @@ smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
return (err);
/*
- * Copy the "work" state, etc. into the VC
- * The MAC key is copied separately.
+ * Copy the "work" state, etc. into the VC,
+ * and back to the caller on the way out.
+ * Clear the "out only" part.
*/
if (ddi_copyin((void *)arg, &vcp->vc_work,
sizeof (smbioc_ssn_work_t), flags)) {
err = EFAULT;
goto out;
}
- if (vcp->vc_u_maclen) {
- vcp->vc_mackeylen = vcp->vc_u_maclen;
- vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
- if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
- vcp->vc_mackeylen, flags)) {
- err = EFAULT;
- goto out;
- }
- }
+ vcp->vc_work.wk_out_state = 0;
- err = smb_iod_vc_work(vcp, cr);
+ switch (cmd) {
- /* Caller wants state here. */
- vcp->vc_work.wk_out_state = vcp->vc_state;
+ case SMBIOC_IOD_CONNECT:
+ err = nsmb_iod_connect(vcp, cr);
+ break;
- (void) ddi_copyout(&vcp->vc_work, (void *)arg,
- sizeof (smbioc_ssn_work_t), flags);
+ case SMBIOC_IOD_NEGOTIATE:
+ err = nsmb_iod_negotiate(vcp, cr);
+ break;
-out:
- if (vcp->vc_mackey) {
- kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
- vcp->vc_mackey = NULL;
- vcp->vc_mackeylen = 0;
+ case SMBIOC_IOD_SSNSETUP:
+ err = nsmb_iod_ssnsetup(vcp, cr);
+ break;
+
+ case SMBIOC_IOD_WORK:
+ err = smb_iod_vc_work(vcp, flags, cr);
+ break;
+
+ case SMBIOC_IOD_IDLE:
+ err = smb_iod_vc_idle(vcp);
+ break;
+
+ case SMBIOC_IOD_RCFAIL:
+ err = smb_iod_vc_rcfail(vcp);
+ break;
+
+ default:
+ err = ENOTTY;
+ break;
}
+out:
+ vcp->vc_work.wk_out_state = vcp->vc_state;
+ (void) ddi_copyout(&vcp->vc_work, (void *)arg,
+ sizeof (smbioc_ssn_work_t), flags);
+
/*
* The IOD thread is leaving the driver. Clear iod_thr,
* and wake up anybody waiting for us to quit.
@@ -904,67 +811,104 @@ out:
return (err);
}
-/*
- * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
- *
- * Wait for user-level requests to be enqueued on this session,
- * and then return to the user-space helper, which will then
- * initiate a reconnect, etc.
- */
int
-smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
+smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
{
- struct smb_vc *vcp = NULL;
- int err = 0;
-
- /* Must have a valid session. */
- if ((vcp = sdp->sd_vc) == NULL)
- return (EINVAL);
- if (vcp->vc_flags & SMBV_GONE)
- return (EINVAL);
+ int err;
/*
- * Is there already an IOD for this VC?
- * (Should never happen.)
+ * Serialize ioctl calls. The smb_usr_... functions
+ * don't expect concurrent calls on a given sdp.
*/
- SMB_VC_LOCK(vcp);
- if (vcp->iod_thr == NULL)
- vcp->iod_thr = curthread;
- else
- err = EEXIST;
- SMB_VC_UNLOCK(vcp);
- if (err)
- return (err);
-
- /* nothing to copyin */
+ mutex_enter(&sdp->sd_lock);
+ if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
+ mutex_exit(&sdp->sd_lock);
+ return (EBUSY);
+ }
+ sdp->sd_flags |= NSMBFL_IOCTL;
+ mutex_exit(&sdp->sd_lock);
+ err = 0;
switch (cmd) {
- case SMBIOC_IOD_IDLE:
- err = smb_iod_vc_idle(vcp);
+ case SMBIOC_GETVERS:
+ (void) ddi_copyout(&nsmb_version, (void *)arg,
+ sizeof (nsmb_version), flags);
+ break;
+
+ case SMBIOC_GETSSNKEY:
+ err = smb_usr_get_ssnkey(sdp, arg, flags);
+ break;
+
+ case SMBIOC_DUP_DEV:
+ err = smb_usr_dup_dev(sdp, arg, flags);
+ break;
+
+ case SMBIOC_XACTNP:
+ err = smb_usr_xnp(sdp, arg, flags, cr);
break;
+ case SMBIOC_READ:
+ case SMBIOC_WRITE:
+ err = smb_usr_rw(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_NTCREATE:
+ err = smb_usr_ntcreate(sdp, arg, flags, cr);
+ break;
+
+ case SMBIOC_PRINTJOB:
+ err = smb_usr_printjob(sdp, arg, flags, cr);
+ break;
+
+ case SMBIOC_CLOSEFH:
+ err = smb_usr_closefh(sdp, cr);
+ break;
+
+ case SMBIOC_SSN_CREATE:
+ case SMBIOC_SSN_FIND:
+ err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_SSN_KILL:
+ case SMBIOC_SSN_RELE:
+ err = smb_usr_drop_ssn(sdp, cmd);
+ break;
+
+ case SMBIOC_TREE_CONNECT:
+ case SMBIOC_TREE_FIND:
+ err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_TREE_KILL:
+ case SMBIOC_TREE_RELE:
+ err = smb_usr_drop_tree(sdp, cmd);
+ break;
+
+ case SMBIOC_IOD_CONNECT:
+ case SMBIOC_IOD_NEGOTIATE:
+ case SMBIOC_IOD_SSNSETUP:
+ case SMBIOC_IOD_WORK:
+ case SMBIOC_IOD_IDLE:
case SMBIOC_IOD_RCFAIL:
- err = smb_iod_vc_rcfail(vcp);
+ err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
+ break;
+
+ case SMBIOC_PK_ADD:
+ case SMBIOC_PK_DEL:
+ case SMBIOC_PK_CHK:
+ case SMBIOC_PK_DEL_OWNER:
+ case SMBIOC_PK_DEL_EVERYONE:
+ err = smb_pkey_ioctl(cmd, arg, flags, cr);
break;
default:
err = ENOTTY;
- goto out;
+ break;
}
- /* Both of these ioctls copy out the new state. */
- (void) ddi_copyout(&vcp->vc_state, (void *)arg,
- sizeof (int), flags);
-
-out:
- /*
- * The IOD thread is leaving the driver. Clear iod_thr,
- * and wake up anybody waiting for us to quit.
- */
- SMB_VC_LOCK(vcp);
- vcp->iod_thr = NULL;
- cv_broadcast(&vcp->vc_statechg);
- SMB_VC_UNLOCK(vcp);
+ mutex_enter(&sdp->sd_lock);
+ sdp->sd_flags &= ~NSMBFL_IOCTL;
+ mutex_exit(&sdp->sd_lock);
return (err);
}
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
index 47b2783c58..b7f6bd8570 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -63,9 +64,9 @@
* m_data ... (m_data + m_len)
* In Unix STREAMS, the mblk payload is:
* b_rptr ... b_wptr
- *
+ *
* Here are some handy conversion notes:
- *
+ *
* struct mbuf struct mblk
* m->m_next m->b_cont
* m->m_nextpkt m->b_next
@@ -75,7 +76,7 @@
* &m->m_dat[MLEN] m->b_datap->db_lim
* M_TRAILINGSPACE(m) MBLKTAIL(m)
* m_freem(m) freemsg(m)
- *
+ *
* Note that mbufs chains also have a special "packet" header,
* which has the length of the whole message. In STREAMS one
* typically just calls msgdsize(m) to get that.
@@ -113,6 +114,9 @@
*/
#define MLEN 4096
+#if (MLEN < SMB2_HDRLEN)
+#error "MLEN can't fit a contiguous SMB2 header"
+#endif
/*
* Some UIO routines.
@@ -420,6 +424,22 @@ mb_put_padbyte(struct mbchain *mbp)
return (0);
}
+/*
+ * Adds padding to 8 byte boundary
+ */
+int
+mb_put_align8(struct mbchain *mbp)
+{
+ static const char zeros[8] = { 0 };
+ int pad_len = 0;
+
+ if ((mbp->mb_count % 8) != 0) {
+ pad_len = 8 - (mbp->mb_count % 8);
+ MB_PUT_INLINE(mbp, zeros, pad_len);
+ }
+ return (0);
+}
+
int
mb_put_uint8(struct mbchain *mbp, u_int8_t x)
{
@@ -537,6 +557,7 @@ mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
/*
* Append an mblk to the chain.
+ * Note: The mblk_t *m is consumed.
*/
int
mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
@@ -576,6 +597,29 @@ mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
}
/*
+ * Put an mbchain into another mbchain
+ * Leave sub_mbp untouched.
+ */
+int
+mb_put_mbchain(struct mbchain *mbp, struct mbchain *sub_mbp)
+{
+ mblk_t *m;
+
+ if (sub_mbp == NULL)
+ return (0);
+
+ m = sub_mbp->mb_top;
+ if (m == NULL)
+ return (0);
+
+ m = dupmsg(m);
+ if (m == NULL)
+ return (ENOSR);
+
+ return (mb_put_mbuf(mbp, m));
+}
+
+/*
* copies a uio scatter/gather list to an mbuf chain.
*/
int
@@ -875,6 +919,7 @@ md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
/*
* Get the next SIZE bytes as a separate mblk.
+ * Advances position in mdp by SIZE.
*/
int
md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
@@ -898,6 +943,7 @@ md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
rm = m_copym(m, off, size, M_WAITOK);
if (rm == NULL)
return (EBADRPC);
+ (void) md_get_mem(mdp, NULL, size, MB_MSYSTEM);
*ret = rm;
return (0);
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
index c5af3391c6..1e16e95d18 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c
@@ -22,6 +22,8 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -69,12 +71,12 @@ static int
smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
{
struct smb_cred scred;
- int error, cerror;
smbmntinfo_t *smi;
smbnode_t *np;
- u_int16_t fid = SMB_FID_UNUSED;
+ smb_fh_t *fid = NULL;
uint32_t sdlen = SMALL_SD_SIZE;
uint32_t rights = STD_RIGHT_READ_CONTROL_ACCESS;
+ int error;
if (selector & SACL_SECURITY_INFORMATION)
rights |= SEC_RIGHT_SYSTEM_SECURITY;
@@ -82,9 +84,6 @@ smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
np = VTOSMB(vp);
smi = VTOSMI(vp);
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
@@ -95,8 +94,8 @@ again:
/*
* This does the OTW Get
*/
- error = smbfs_smb_getsec_m(smi->smi_share, fid,
- &scred, selector, mp, &sdlen);
+ error = smbfs_smb_getsec(smi->smi_share, fid,
+ selector, mp, &sdlen, &scred);
/*
* Server may give us an error indicating that we
* need a larger data buffer to receive the SD,
@@ -115,14 +114,10 @@ again:
sdlen <= MAX_RAW_SD_SIZE)
goto again;
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing file %s\n",
- cerror, np->n_rpath);
+ smbfs_smb_tmpclose(np, fid);
out:
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
return (error);
}
@@ -139,11 +134,11 @@ static int
smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
{
struct smb_cred scred;
- int error, cerror;
smbmntinfo_t *smi;
smbnode_t *np;
uint32_t rights;
- u_int16_t fid = SMB_FID_UNUSED;
+ smb_fh_t *fid = NULL;
+ int error;
np = VTOSMB(vp);
smi = VTOSMI(vp);
@@ -164,9 +159,6 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
if (selector & SACL_SECURITY_INFORMATION)
rights |= SEC_RIGHT_SYSTEM_SECURITY;
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
@@ -185,17 +177,13 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
/*
* This does the OTW Set
*/
- error = smbfs_smb_setsec_m(smi->smi_share, fid,
- &scred, selector, mp);
+ error = smbfs_smb_setsec(smi->smi_share, fid,
+ selector, mp, &scred);
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing file %s\n",
- cerror, np->n_rpath);
+ smbfs_smb_tmpclose(np, fid);
out:
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
return (error);
}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
index 44319e6682..41a6f41a2b 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
@@ -24,6 +24,8 @@
*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -60,6 +62,7 @@
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
+#ifdef _KERNEL
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/page.h>
@@ -67,6 +70,7 @@
#include <vm/seg.h>
#include <vm/seg_map.h>
#include <vm/seg_vn.h>
+#endif // _KERNEL
#define ATTRCACHE_VALID(vp) (gethrtime() < VTOSMB(vp)->r_attrtime)
@@ -394,11 +398,23 @@ smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap)
static int
smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
{
- struct smbnode *np;
struct smb_cred scred;
+ smbnode_t *np = VTOSMB(vp);
+ smb_share_t *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp = NULL;
int error;
- np = VTOSMB(vp);
+ bzero(fap, sizeof (*fap));
+
+ /*
+ * Special case the XATTR directory here (all fake).
+ * OK to leave a,c,m times zero (expected).
+ */
+ if (vp->v_flag & V_XATTRDIR) {
+ fap->fa_attr = SMB_FA_DIR;
+ fap->fa_size = DEV_BSIZE;
+ return (0);
+ }
/*
* Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
@@ -412,8 +428,28 @@ smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
return (EINTR);
smb_credinit(&scred, cr);
- bzero(fap, sizeof (*fap));
- error = smbfs_smb_getfattr(np, fap, &scred);
+// Does the attr. open code path work for streams?
+// Trying that, and if it doesn't work enable this.
+#if 0 // XXX
+ /*
+ * Extended attribute files
+ */
+ if (np->n_flag & N_XATTR) {
+ error = smbfs_xa_getfattr(np, fap, scrp);
+ goto out;
+ }
+#endif // XXX
+
+ if (np->n_fidrefs > 0 &&
+ (fhp = np->n_fid) != NULL &&
+ (fhp->fh_vcgenid == ssp->ss_vcgenid)) {
+ /* Use the FID we have. */
+ error = smbfs_smb_getfattr(np, fhp, fap, &scred);
+
+ } else {
+ /* This will do an attr open */
+ error = smbfs_smb_getpattr(np, fap, &scred);
+ }
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -816,9 +852,8 @@ static void smbfs_cb_nop(smb_share_t *ss)
smb_fscb_t smbfs_cb = {
.fscb_disconn = smbfs_dead,
- .fscb_connect = smbfs_cb_nop,
- .fscb_down = smbfs_cb_nop,
- .fscb_up = smbfs_cb_nop };
+ .fscb_connect = smbfs_cb_nop
+};
#endif /* NEED_SMBFS_CALLBACKS */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
index 5bbbae860e..163a5a4504 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c
@@ -35,11 +35,14 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cred.h>
+#include <sys/errno.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
index 2fe7476814..62d47e9b20 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _FS_SMBFS_NODE_H_
@@ -221,10 +222,8 @@ typedef struct smbnode {
struct smbfs_fctx *n_dirseq; /* ff context */
int n_dirofs; /* last ff offset */
int n_fidrefs;
- uint16_t n_fid; /* file handle */
+ smb_fh_t *n_fid; /* file handle */
enum vtype n_ovtype; /* vnode type opened */
- uint32_t n_rights; /* granted rights */
- int n_vcgenid; /* gereration no. (reconnect) */
/*
* Misc. bookkeeping
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
index db920f21b8..9a44867521 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
@@ -28,18 +28,18 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $Id: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/inttypes.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/sunddi.h>
@@ -48,6 +48,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -62,375 +63,70 @@
*/
const uint64_t NT1980 = 11960035200ULL*10000000ULL;
-/*
- * Local functions.
- * Not static, to aid debugging.
- */
-
-int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp);
-int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel);
-
-int smbfs_smb_statfsLM1(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
-int smbfs_smb_statfsLM2(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
-
-int smbfs_smb_setfattrNT(struct smbnode *np, int fid,
- uint32_t attr, struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
-int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
- struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
-int smbfs_smb_setpattr1(struct smbnode *np,
- const char *name, int len, uint32_t attr,
- struct timespec *mtime, struct smb_cred *scrp);
-
-
-/*
- * Todo: locking over-the-wire
- */
-#ifdef APPLE
-
-static int
-smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
- offset_t start, uint64_t len, int largelock,
- struct smb_cred *scrp, uint32_t timeout)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- uint8_t ltype = 0;
- int error;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- return (ESTALE);
-
- if (op == SMB_LOCK_SHARED)
- ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
- /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
- if (largelock)
- ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint8(mbp, 0xff); /* secondary command */
- mb_put_uint8(mbp, 0); /* MBZ */
- mb_put_uint16le(mbp, 0);
- mb_put_uint16le(mbp, np->n_fid);
- mb_put_uint8(mbp, ltype); /* locktype */
- mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
- mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
- mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
- mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint16le(mbp, pid);
- if (!largelock) {
- mb_put_uint32le(mbp, start);
- mb_put_uint32le(mbp, len);
- } else {
- mb_put_uint16le(mbp, 0); /* pad */
- mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
- mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
- mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
- mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
- }
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * unlock send or lock response, or we could
- * lose track of an outstanding lock.
- */
- if (op == SMB_LOCK_RELEASE)
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- else
- rqp->sr_flags |= SMBR_NOINTR_RECV;
-
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
- offset_t start, uint64_t len, int largelock,
- struct smb_cred *scrp, uint32_t timeout)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
-
- if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
- /*
- * TODO: use LOCK_BYTE_RANGE here.
- */
- return (EINVAL);
-
- /*
- * XXX: compute largelock via:
- * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
- */
- return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
- largelock, scrp, timeout));
-}
-
-#endif /* APPLE */
/*
- * Helper for smbfs_getattr
- * Something like nfs_getattr_otw
+ * Helper for smbfs_getattr_otw
+ * used when we have an open FID
*/
int
smbfs_smb_getfattr(
struct smbnode *np,
+ smb_fh_t *fhp,
struct smbfattr *fap,
struct smb_cred *scrp)
{
+ struct smb_share *ssp = np->n_mount->smi_share;
int error;
- /*
- * This lock is necessary for FID-based calls.
- * Lock may be writer (via open) or reader.
- */
- ASSERT(np->r_lkserlock.count != 0);
-
- /*
- * Extended attribute directory or file.
- */
- if (np->n_flag & N_XATTR) {
- error = smbfs_xa_getfattr(np, fap, scrp);
- return (error);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_qfileinfo(ssp, &fhp->fh_fid2, fap, scrp);
+ } else {
+ error = smbfs_smb1_trans2_query(np, fhp->fh_fid1, fap, scrp);
}
- error = smbfs_smb_trans2_query(np, fap, scrp, 0);
- if (error != EINVAL)
- return (error);
-
- /* fallback */
- error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
-
return (error);
}
/*
- * Common function for QueryFileInfo, QueryPathInfo.
+ * Helper for smbfs_getattr_otw
+ * used when we don't have an open FID
+ *
+ * For SMB1 we can just use the path form of trans2 query.
+ * For SMB2 we need to do an attribute-only open.
+ * See smbfs_smb2_getpattr()
*/
int
-smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel)
+smbfs_smb_getpattr(
+ struct smbnode *np,
+ struct smbfattr *fap,
+ struct smb_cred *scrp)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct smb_t2rq *t2p;
- int error, svtz, timesok = 1;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t cmd, date, time, wattr;
- uint64_t llongint, lsize;
- uint32_t size, dattr;
-
- /*
- * Shared lock for n_fid use below.
- * See smbfs_smb_getfattr()
- */
- ASSERT(np->r_lkserlock.count != 0);
-
- /*
- * If we have a valid open FID, use it.
- */
- if ((np->n_fidrefs > 0) &&
- (np->n_fid != SMB_FID_UNUSED) &&
- (np->n_vcgenid == ssp->ss_vcgenid))
- cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
- else
- cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
-
-top:
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- if (!infolevel) {
- if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
- infolevel = SMB_QFILEINFO_STANDARD;
- else
- infolevel = SMB_QFILEINFO_ALL_INFO;
- }
-
- if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
- mb_put_uint16le(mbp, np->n_fid);
-
- mb_put_uint16le(mbp, infolevel);
-
- if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
- mb_put_uint32le(mbp, 0);
- /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error) {
- smb_t2_done(t2p);
- return (error);
- }
- }
+ int error;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = vcp->vc_txmax;
- error = smb_t2_request(t2p);
- if (error) {
- smb_t2_done(t2p);
- /* Invalid info level? Try fallback. */
- if (error == EINVAL &&
- infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- return (error);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_getpattr(np, fap, scrp);
+ } else {
+ uint16_t fid = SMB_FID_UNUSED;
+ error = smbfs_smb1_trans2_query(np, fid, fap, scrp);
}
- mdp = &t2p->t2_rdata;
- svtz = vcp->vc_sopt.sv_tz;
- switch (infolevel) {
- case SMB_QFILEINFO_STANDARD:
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
- md_get_uint32le(mdp, &size); /* EOF position */
- fap->fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- fap->fa_allocsz = size;
- error = md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- timesok = 1;
- break;
- case SMB_QFILEINFO_ALL_INFO:
- timesok = 0;
- /* creation time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_createtime);
-
- /* last access time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_atime);
-
- /* last write time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_mtime);
-
- /* last change time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_ctime);
-
- /* attributes */
- md_get_uint32le(mdp, &dattr);
- fap->fa_attr = dattr;
- /*
- * 4-Byte alignment - discard
- * Specs don't talk about this.
- */
- md_get_uint32le(mdp, NULL);
- /* allocation size */
- md_get_uint64le(mdp, &lsize);
- fap->fa_allocsz = lsize;
- /* File size */
- error = md_get_uint64le(mdp, &lsize);
- fap->fa_size = lsize;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", infolevel);
- error = EINVAL;
- }
- smb_t2_done(t2p);
- /*
- * if all times are zero (observed with FAT on NT4SP6)
- * then fall back to older info level
- */
- if (!timesok) {
- if (infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- error = EINVAL;
- }
return (error);
}
/*
- * Support functions for _qstreaminfo
- * Moved to smbfs_xattr.c
+ * Get and parse FileFsAttributeInformation
*/
-
int
smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
struct smb_cred *scrp)
{
- struct smb_t2rq *t2p;
- struct mbchain *mbp;
- struct mdchain *mdp;
int error;
- uint32_t nlen;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
- t2p->t2_maxpcount = 4;
- t2p->t2_maxdcount = 4 * 3 + 512;
- error = smb_t2_request(t2p);
- if (error)
- goto out;
-
- mdp = &t2p->t2_rdata;
- md_get_uint32le(mdp, &fsa->fsa_aflags);
- md_get_uint32le(mdp, &fsa->fsa_maxname);
- error = md_get_uint32le(mdp, &nlen); /* fs name length */
- if (error)
- goto out;
- /*
- * Get the FS type name.
- */
- bzero(fsa->fsa_tname, FSTYPSZ);
- if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
- uint16_t tmpbuf[FSTYPSZ];
- size_t tmplen, outlen;
-
- if (nlen > sizeof (tmpbuf))
- nlen = sizeof (tmpbuf);
- error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
- tmplen = nlen / 2; /* UCS-2 chars */
- outlen = FSTYPSZ - 1;
- (void) uconv_u16tou8(tmpbuf, &tmplen,
- (uchar_t *)fsa->fsa_tname, &outlen,
- UCONV_IN_LITTLE_ENDIAN);
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_qfsattr(ssp, fsa, scrp);
} else {
- if (nlen > (FSTYPSZ - 1))
- nlen = FSTYPSZ - 1;
- error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
+ error = smbfs_smb1_qfsattr(ssp, fsa, scrp);
}
/*
@@ -442,652 +138,113 @@ smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
SMB_SS_UNLOCK(ssp);
}
-out:
- smb_t2_done(t2p);
- return (0);
+ return (error);
}
int
smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scp)
{
- int error;
-
- if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
- error = smbfs_smb_statfsLM2(ssp, sbp, scp);
- else
- error = smbfs_smb_statfsLM1(ssp, sbp, scp);
-
- return (error);
-}
-
-int
-smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t bsize;
- uint32_t units, bpu, funits;
- uint64_t s, t, f;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
- t2p->t2_maxpcount = 4;
- t2p->t2_maxdcount = 4 * 4 + 2;
- error = smb_t2_request(t2p);
- if (error)
- goto out;
-
- mdp = &t2p->t2_rdata;
- md_get_uint32le(mdp, NULL); /* fs id */
- md_get_uint32le(mdp, &bpu);
- md_get_uint32le(mdp, &units);
- md_get_uint32le(mdp, &funits);
- error = md_get_uint16le(mdp, &bsize);
- if (error)
- goto out;
- s = bsize;
- s *= bpu;
- t = units;
- f = funits;
- /*
- * Don't allow over-large blocksizes as they determine
- * Finder List-view size granularities. On the other
- * hand, we mustn't let the block count overflow the
- * 31 bits available.
- */
- while (s > 16 * 1024) {
- if (t > LONG_MAX)
- break;
- s /= 2;
- t *= 2;
- f *= 2;
- }
- while (t > LONG_MAX) {
- t /= 2;
- f /= 2;
- s *= 2;
- }
- sbp->f_bsize = (ulong_t)s; /* file system block size */
- sbp->f_blocks = t; /* total data blocks in file system */
- sbp->f_bfree = f; /* free blocks in fs */
- sbp->f_bavail = f; /* free blocks avail to non-superuser */
- sbp->f_files = (-1); /* total file nodes in file system */
- sbp->f_ffree = (-1); /* free file nodes in fs */
-
-out:
- smb_t2_done(t2p);
- return (0);
-}
-
-int
-smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct mdchain *mdp;
- uint16_t units, bpu, bsize, funits;
- uint64_t s, t, f;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
- scrp);
- if (error)
- return (error);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (error)
- goto out;
-
- smb_rq_getreply(rqp, &mdp);
- md_get_uint16le(mdp, &units);
- md_get_uint16le(mdp, &bpu);
- md_get_uint16le(mdp, &bsize);
- error = md_get_uint16le(mdp, &funits);
- if (error)
- goto out;
- s = bsize;
- s *= bpu;
- t = units;
- f = funits;
- /*
- * Don't allow over-large blocksizes as they determine
- * Finder List-view size granularities. On the other
- * hand, we mustn't let the block count overflow the
- * 31 bits available.
- */
- while (s > 16 * 1024) {
- if (t > LONG_MAX)
- break;
- s /= 2;
- t *= 2;
- f *= 2;
- }
- while (t > LONG_MAX) {
- t /= 2;
- f /= 2;
- s *= 2;
- }
- sbp->f_bsize = (ulong_t)s; /* file system block size */
- sbp->f_blocks = t; /* total data blocks in file system */
- sbp->f_bfree = f; /* free blocks in fs */
- sbp->f_bavail = f; /* free blocks avail to non-superuser */
- sbp->f_files = (-1); /* total file nodes in file system */
- sbp->f_ffree = (-1); /* free file nodes in fs */
-
-out:
- smb_rq_done(rqp);
- return (0);
-}
-
-int
-smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
- else
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
- mb_put_uint16le(mbp, 0); /* pad */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint64le(mbp, newsize);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- smb_t2_done(t2p);
- return (error);
-}
-
-int
-smbfs_smb_setdisp(struct smbnode *np,
- uint16_t fid, uint8_t newdisp,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFORMATION);
- else
- mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFO);
- mb_put_uint16le(mbp, 0); /* pad */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint8(mbp, newdisp);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- smb_t2_done(t2p);
- return (error);
-}
-
-/*
- * On SMB1, the trans2 rename only allows a rename where the
- * source and target are in the same directory. If you give
- * the server any separators, you get "status not supported".
- */
-
-/*ARGSUSED*/
-int
-smbfs_smb_t2rename(struct smbnode *np,
- const char *tname, int tnlen, struct smb_cred *scrp,
- uint16_t fid, int overwrite)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_fs_size_info info;
struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int32_t *ucslenp;
+ uint32_t bps, spu;
int error;
- if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
- return (ENOTSUP);
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_statfs(ssp, &info, scp);
+ } else {
+ error = smbfs_smb1_statfs(ssp, &info, scp);
+ }
if (error)
return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
- mb_put_uint16le(mbp, 0); /* reserved, nowadays */
-
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint32le(mbp, overwrite); /* one or zero */
- mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
+ /* A bit of paranoia. */
+ bps = info.bytes_per_sect;
+ if (bps < DEV_BSIZE)
+ bps = DEV_BSIZE;
+ spu = info.sect_per_unit;
+ if (spu == 0)
+ spu = 1;
- ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
- mbp->mb_count = 0;
- error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
- if (error)
- goto out;
- *ucslenp = htolel(mbp->mb_count);
+ /* preferred file system block size */
+ sbp->f_bsize = bps * spu;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
-out:
- smb_t2_done(t2p);
- return (error);
-}
+ /* file system block size ("fragment size") */
+ sbp->f_frsize = bps;
-int
-smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
-{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
+ /* total blocks of f_frsize */
+ sbp->f_blocks = info.total_units * spu;
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ /* free blocks of f_frsize */
+ sbp->f_bfree = info.actual_avail * spu;
- if (!(np->n_flag & NFLUSHWIRE))
- return (0);
- if (np->n_fidrefs == 0)
- return (0); /* not open */
+ /* free blocks avail to non-superuser */
+ sbp->f_bavail = info.caller_avail * spu;
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- return (ESTALE);
+ sbp->f_files = (-1); /* total file nodes in file system */
+ sbp->f_ffree = (-1); /* free file nodes in fs */
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, np->n_fid);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- if (!error) {
- mutex_enter(&np->r_statelock);
- np->n_flag &= ~NFLUSHWIRE;
- mutex_exit(&np->r_statelock);
- }
return (error);
}
int
-smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
- struct smb_cred *scrp)
+smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fhp,
+ uint8_t disp, struct smb_cred *scrp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
+ int err;
- if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- /*
- * This call knows about 64-bit offsets.
- */
- error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
- if (!error) {
- mutex_enter(&np->r_statelock);
- np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
- mutex_exit(&np->r_statelock);
- return (0);
- }
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ err = smbfs_smb2_setdisp(ssp, &fhp->fh_fid2, disp, scrp);
+ } else {
+ err = smbfs_smb1_setdisp(ssp, fhp->fh_fid1, disp, scrp);
}
- /*
- * OK, so fallback to SMB_COM_WRITE, but note:
- * it only supports 32-bit file offsets.
- */
- if (newsize > UINT32_MAX)
- return (EFBIG);
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0);
- mb_put_uint32le(mbp, newsize);
- mb_put_uint16le(mbp, 0);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- mutex_enter(&np->r_statelock);
- np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
- mutex_exit(&np->r_statelock);
- return (error);
+ return (err);
}
-/*
- * Old method for getting file attributes.
- */
int
-smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp)
+smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fhp,
+ uint64_t size, struct smb_cred *scrp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc;
int error;
- uint16_t wattr;
- uint32_t longint;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
- name, nmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 10) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint,
- SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
- error = md_get_uint32le(mdp, &longint);
- fap->fa_size = longint;
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-/*
- * Set DOS file attributes. mtime should be NULL for dialects above lm10
- */
-int
-smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
- uint32_t attr, struct timespec *mtime,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- long time;
- int error, svtz;
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
- if (error)
- return (error);
- svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, (uint16_t)attr);
- if (mtime) {
- smb_time_local2server(mtime, svtz, &time);
- } else
- time = 0;
- mb_put_uint32le(mbp, time); /* mtime */
- mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_seteof(ssp, &fhp->fh_fid2, size, scrp);
+ } else {
+ error = smbfs_smb1_seteof(ssp, fhp->fh_fid1, size, scrp);
}
- mb_put_uint8(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smbfattr fa;
- int error;
- uint32_t attr;
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && !(attr & SMB_FA_HIDDEN)) {
- attr |= SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
return (error);
}
-int
-smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smbfattr fa;
- uint32_t attr;
- int error;
-
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && (attr & SMB_FA_HIDDEN)) {
- attr &= ~SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
- return (error);
-}
-
/*
* Set file attributes (optionally: DOS attr, atime, mtime)
- * either by open FID or by path name (FID == -1).
+ * Always have an open FID with set attr rights.
*/
int
smbfs_smb_setfattr(
- struct smbnode *np,
- int fid,
+ struct smb_share *ssp,
+ smb_fh_t *fhp,
uint32_t attr,
struct timespec *mtime,
struct timespec *atime,
struct smb_cred *scrp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
+ struct mbchain mb_info;
+ struct mbchain *mbp = &mb_info;
+ uint64_t tm;
int error;
/*
- * Normally can use the trans2 call.
- */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_setfattrNT(np, fid,
- attr, mtime, atime, scrp);
- return (error);
- }
-
- /*
- * Fall-back for older protocols.
+ * Build a struct FILE_BASIC_INFORMATION in mbp
+ * LARGE_INTEGER CreationTime;
+ * LARGE_INTEGER LastAccessTime;
+ * LARGE_INTEGER LastWriteTime;
+ * LARGE_INTEGER ChangeTime;
+ * ULONG FileAttributes;
+ * Zero in times means "no change".
*/
- if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
- error = smbfs_smb_setftime1(np, fid,
- mtime, atime, scrp);
- return (error);
- }
- error = smbfs_smb_setpattr1(np, NULL, 0,
- attr, mtime, scrp);
- return (error);
-}
-
-/*
- * Set file atime and mtime. Isn't supported by core dialect.
- */
-int
-smbfs_smb_setftime1(
- struct smbnode *np,
- uint16_t fid,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- uint16_t date, time;
- int error, tzoff;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
- if (error)
- return (error);
-
- tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint32le(mbp, 0); /* creation time */
-
- if (atime)
- smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- if (mtime)
- smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- SMBVDEBUG("%d\n", error);
- smb_rq_done(rqp);
- return (error);
-}
-
-/*
- * Set DOS file attributes, either via open FID or by path name.
- * Looks like this call can be used only if CAP_NT_SMBS bit is on.
- *
- * When setting via path (fid == -1):
- * *BASIC_INFO works with Samba, but Win2K servers say it is an
- * invalid information level on a SET_PATH_INFO. Note Win2K does
- * support *BASIC_INFO on a SET_FILE_INFO, and they support the
- * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
- */
-int
-smbfs_smb_setfattrNT(
- struct smbnode *np,
- int fid, /* if fid == -1, set by path */
- uint32_t attr,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
-{
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- uint64_t tm;
- int error;
- uint16_t cmd, level;
-
- if (fid == -1) {
- cmd = SMB_TRANS2_SET_PATH_INFORMATION;
- } else {
- if (fid > UINT16_MAX)
- return (EINVAL);
- cmd = SMB_TRANS2_SET_FILE_INFORMATION;
- }
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- level = SMB_SFILEINFO_BASIC_INFORMATION;
- else
- level = SMB_SFILEINFO_BASIC_INFO;
-
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
-
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
-
- if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
- mb_put_uint16le(mbp, fid);
-
- mb_put_uint16le(mbp, level);
- mb_put_uint32le(mbp, 0); /* MBZ */
-
- if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error != 0)
- goto out;
- }
-
- /* FAT file systems don't support dates earlier than 1980. */
-
- mbp = &t2p->t2_tdata;
mb_init(mbp);
mb_put_uint64le(mbp, 0); /* creation time */
if (atime) {
@@ -1097,7 +254,7 @@ smbfs_smb_setfattrNT(
tm = NT1980;
} else
tm = 0;
- mb_put_uint64le(mbp, tm); /* access time */
+ mb_put_uint64le(mbp, tm); /* last access time */
if (mtime) {
smb_time_local2NT(mtime, &tm);
if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
@@ -1106,19 +263,35 @@ smbfs_smb_setfattrNT(
} else
tm = 0;
mb_put_uint64le(mbp, tm); /* last write time */
- mb_put_uint64le(mbp, 0); /* ctime (no change) */
+ mb_put_uint64le(mbp, 0); /* change time */
mb_put_uint32le(mbp, attr);
- mb_put_uint32le(mbp, 0); /* padding */
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
-out:
- smb_t2_done(t2p);
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_setfattr(ssp, &fhp->fh_fid2, mbp, scrp);
+ } else {
+ error = smbfs_smb1_setfattr(ssp, fhp->fh_fid1, mbp, scrp);
+ }
+
+ return (error);
+}
+
+int
+smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp)
+{
+ int error;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_flush(ssp, &fhp->fh_fid2, scrp);
+ } else {
+ error = smbfs_smb1_flush(ssp, fhp->fh_fid1, scrp);
+ }
return (error);
}
/*
* Modern create/open of file or directory.
+ * On success, fills in fhp->fh_fid* and fhp->fh_rights
*/
int
smbfs_smb_ntcreatex(
@@ -1132,7 +305,7 @@ smbfs_smb_ntcreatex(
uint32_t disp, /* open disposition */
uint32_t createopt, /* NTCREATEX_OPTIONS_ */
struct smb_cred *scrp,
- uint16_t *fidp, /* returned FID */
+ smb_fh_t *fhp, /* pre-made file handle to fill in */
uint32_t *cr_act_p, /* optional returned create action */
struct smbfattr *fap) /* optional returned attributes */
{
@@ -1153,7 +326,7 @@ smbfs_smb_ntcreatex(
0, /* NTCREATEX_FLAGS... */
req_acc, efa, share_acc, disp, createopt,
NTCREATEX_IMPERSONATION_IMPERSONATION,
- scrp, fidp, cr_act_p, fap);
+ scrp, fhp, cr_act_p, fap);
out:
mb_done(&name_mb);
@@ -1161,233 +334,68 @@ out:
return (err);
}
-static uint32_t
-smb_mode2rights(int mode)
-{
- mode = mode & SMB_AM_OPENMODE;
- uint32_t rights =
- STD_RIGHT_SYNCHRONIZE_ACCESS |
- STD_RIGHT_READ_CONTROL_ACCESS;
-
- if ((mode == SMB_AM_OPENREAD) ||
- (mode == SMB_AM_OPENRW)) {
- rights |=
- SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_READ_DATA;
- }
-
- if ((mode == SMB_AM_OPENWRITE) ||
- (mode == SMB_AM_OPENRW)) {
- rights |=
- SA_RIGHT_FILE_WRITE_ATTRIBUTES |
- SA_RIGHT_FILE_APPEND_DATA |
- SA_RIGHT_FILE_WRITE_DATA;
- }
-
- if (mode == SMB_AM_OPENEXEC) {
- rights |=
- SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_EXECUTE;
- }
-
- return (rights);
-}
-
-static int
-smb_rights2mode(uint32_t rights)
-{
- int accmode = SMB_AM_OPENEXEC; /* our fallback */
-
- if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
- SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
- SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
- STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
- accmode = SMB_AM_OPENWRITE;
- if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
- SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
- accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
- : SMB_AM_OPENRW;
- return (accmode);
-}
-
-static int
-smbfs_smb_oldopen(
- struct smbnode *np,
- const char *name,
- int nmlen,
- int xattr,
- int accmode,
- struct smb_cred *scrp,
- uint16_t *fidp,
- uint16_t *granted_mode_p,
- smbfattr_t *fap)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- struct mdchain *mdp;
- struct smbfattr fa;
- uint8_t wc;
- uint16_t wattr;
- uint32_t longint;
- int error;
-
- bzero(&fa, sizeof (fa));
-
- /*
- * XXX: move to callers...
- *
- * Use DENYNONE to give unixy semantics of permitting
- * everything not forbidden by permissions. Ie denial
- * is up to server with clients/openers needing to use
- * advisory locks for further control.
- */
- accmode |= SMB_SM_DENYNONE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, accmode);
- mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
- SMB_FA_DIR);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, vcp, np, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto done;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto done;
- smb_rq_getreply(rqp, &mdp);
- /*
- * 8/2002 a DAVE server returned wc of 15 so we ignore that.
- * (the actual packet length and data was correct)
- */
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto done;
- if (wc != 7 && wc != 15) {
- error = EBADRPC;
- goto done;
- }
- md_get_uint16le(mdp, fidp);
- md_get_uint16le(mdp, &wattr);
- fa.fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
- md_get_uint32le(mdp, &longint);
- fa.fa_size = longint;
- error = md_get_uint16le(mdp, granted_mode_p);
-
-done:
- smb_rq_done(rqp);
- if (error)
- return (error);
-
- if (fap)
- *fap = fa; /* struct copy */
-
- return (0);
-}
-
+/*
+ * Get a file handle with (at least) the specified rights.
+ *
+ * We'll try to borrow the node ->n_fid if we can. When we
+ * borrow n_fid, just take a hold on the smb_fh_t, and don't
+ * bump n_fidrefs as that tracks VFS-level opens. Similarly
+ * in _tmpclose we just release the smb_fh_t, not n_fidrefs.
+ */
int
smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
- uint16_t *fidp)
+ smb_fh_t **fhpp)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- int accmode, error;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+ smb_fh_t *fhp = NULL;
+ int error;
/* Can we re-use n_fid? or must we open anew? */
mutex_enter(&np->r_statelock);
if (np->n_fidrefs > 0 &&
- np->n_vcgenid == ssp->ss_vcgenid &&
- (rights & np->n_rights) == rights) {
- np->n_fidrefs++;
- *fidp = np->n_fid;
+ (fhp = np->n_fid) != NULL &&
+ fhp->fh_vcgenid == ssp->ss_vcgenid &&
+ (fhp->fh_rights & rights) == rights) {
+ smb_fh_hold(fhp);
+ *fhpp = fhp;
mutex_exit(&np->r_statelock);
return (0);
}
mutex_exit(&np->r_statelock);
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/* re-open an existing file. */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_ntcreatex(np,
- NULL, 0, 0, /* name nmlen xattr */
- rights, SMB_EFA_NORMAL,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_OPEN,
- 0, /* create options */
- scrp, fidp,
- NULL, NULL); /* cr_act_p fa_p */
- return (error);
- }
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp,
+ NULL, NULL); /* cr_act_p fa_p */
+ if (error != 0)
+ goto out;
+
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
- accmode = smb_rights2mode(rights);
- error = smbfs_smb_oldopen(np,
- NULL, 0, 0, /* name nmlen xattr */
- accmode, scrp,
- fidp,
- NULL, /* granted mode p */
- NULL); /* fa p */
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
return (error);
}
-int
-smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
+/* ARGSUSED */
+void
+smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- int error = 0;
- uint16_t oldfid = SMB_FID_UNUSED;
-
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
- mutex_enter(&np->r_statelock);
- if (fid == np->n_fid) {
- ASSERT(np->n_fidrefs > 0);
- if (--np->n_fidrefs == 0) {
- /*
- * Don't expect to find the last reference
- * here in tmpclose. Hard to deal with as
- * we don't have r_lkserlock exclusive.
- * Will close oldfid below.
- */
- oldfid = np->n_fid;
- np->n_fid = SMB_FID_UNUSED;
- }
- } else {
- /* Will close the passed fid. */
- oldfid = fid;
- }
- mutex_exit(&np->r_statelock);
-
- if (oldfid != SMB_FID_UNUSED)
- error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
-
- return (error);
+ smb_fh_rele(fhp);
}
int
@@ -1398,124 +406,47 @@ smbfs_smb_open(
int xattr,
uint32_t rights,
struct smb_cred *scrp,
- uint16_t *fidp,
- uint32_t *rightsp,
+ smb_fh_t **fhpp,
smbfattr_t *fap)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- int accmode, error;
- uint16_t grantedmode;
-
- /* open an existing file */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_ntcreatex(np,
- name, nmlen, xattr,
- rights, SMB_EFA_NORMAL,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_OPEN,
- 0, /* create options */
- scrp, fidp,
- NULL, fap); /* cr_act_p fa_p */
- if (error != 0)
- return (error);
- *rightsp = rights;
- return (0);
- }
+ // struct smb_vc *vcp = SSTOVC(ssp);
+ smb_fh_t *fhp = NULL;
+ int error;
- accmode = smb_rights2mode(rights);
- error = smbfs_smb_oldopen(np,
- name, nmlen, xattr, accmode, scrp,
- fidp, &grantedmode, fap);
+ error = smb_fh_create(ssp, &fhp);
if (error != 0)
- return (error);
- *rightsp = smb_mode2rights(grantedmode);
- (void) smbfs_smb_getfattr(np, fap, scrp);
+ goto out;
- return (0);
-}
+ /* open an existing file */
+ error = smbfs_smb_ntcreatex(np,
+ name, nmlen, xattr,
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp, NULL, fap);
+ if (error != 0)
+ goto out;
-int
-smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
- struct timespec *mtime, struct smb_cred *scrp)
-{
- int error;
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
- error = smb_smb_close(ssp, fid, mtime, scrp);
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
- /*
- * ENOTCONN isn't interesting - if the connection is closed,
- * so are all our FIDs - and EIO is also not interesting,
- * as it means a forced unmount was done. (was ENXIO)
- * Also ETIME, which means we sent the request but gave up
- * waiting before the response came back.
- *
- * Don't clog up the system log with warnings about these
- * uninteresting failures on closes.
- */
- switch (error) {
- case ENOTCONN:
- case ENXIO:
- case EIO:
- case ETIME:
- error = 0;
- }
- return (error);
+ return (0);
}
-static int
-smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
- int xattr, struct smb_cred *scrp, uint16_t *fidp)
+void
+smbfs_smb_close(smb_fh_t *fhp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- struct timespec ctime;
- uint8_t wc;
- long tm;
- int error;
- uint16_t attr = SMB_FA_ARCHIVE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- if (name && *name == '.')
- attr |= SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, attr); /* attributes */
- gethrestime(&ctime);
- smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
- mb_put_uint32le(mbp, tm);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto out;
-
- smb_rq_getreply(rqp, &mdp);
- md_get_uint8(mdp, &wc);
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, fidp);
-out:
- smb_rq_done(rqp);
- return (error);
+ smb_fh_close(fhp);
+ smb_fh_rele(fhp);
}
int
@@ -1526,759 +457,127 @@ smbfs_smb_create(
int xattr,
uint32_t disp,
struct smb_cred *scrp,
- uint16_t *fidp)
+ smb_fh_t **fhpp)
{
struct smb_share *ssp = dnp->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
+ // struct smb_vc *vcp = SSTOVC(ssp);
+ smb_fh_t *fhp = NULL;
uint32_t efa, rights;
int error;
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/*
* At present the only access we might need is to WRITE data,
* and that only if we are creating a "symlink". When/if the
* access needed gets more complex it should made a parameter
* and be set upstream.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- rights = SA_RIGHT_FILE_WRITE_DATA;
- efa = SMB_EFA_NORMAL;
- if (!xattr && name && *name == '.')
- efa = SMB_EFA_HIDDEN;
- error = smbfs_smb_ntcreatex(dnp,
- name, nmlen, xattr, rights, efa,
- NTCREATEX_SHARE_ACCESS_ALL,
- disp, /* != NTCREATEX_DISP_OPEN */
- NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
- scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
- return (error);
- }
+ rights = SA_RIGHT_FILE_WRITE_DATA;
+ efa = SMB_EFA_NORMAL;
+ if (!xattr && name && *name == '.')
+ efa = SMB_EFA_HIDDEN;
+ error = smbfs_smb_ntcreatex(dnp,
+ name, nmlen, xattr, rights, efa,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ disp, /* != NTCREATEX_DISP_OPEN */
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ scrp, fhp, NULL, NULL);
+ if (error != 0)
+ goto out;
- error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
- return (error);
-}
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ *fhpp = fhp;
+ fhp = NULL;
-int
-smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
- int nmlen, int xattr)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen,
- xattr ? ':' : '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
return (error);
}
int
-smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, struct smb_cred *scrp)
+smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *np,
+ struct smbnode *tdnp, const char *tname, int tnlen,
+ smb_fh_t *fhp, struct smb_cred *scrp)
{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
- uint16_t fa;
- char sep;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
- fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
- fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, fa);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ int err;
- /*
- * When we're not adding any component name, the
- * passed sep is ignored, so just pass sep=0.
- */
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
- if (error)
- goto out;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ err = smbfs_smb2_rename(np, tdnp, tname, tnlen, 0,
+ &fhp->fh_fid2, scrp);
+ return (err);
+ }
/*
- * After XATTR directories, separator is ":"
+ * SMB1 -- Want to use _t2rename if we can
+ * (rename in same dir and cap pass-through)
+ * Most SMB1 servers have cap pass-through.
*/
- sep = (src->n_flag & N_XATTR) ? ':' : '\\';
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
- if (error)
- goto out;
-
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-int
-smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
- mb_put_uint16le(mbp, 0x20); /* delete target file */
- mb_put_uint16le(mbp, flags);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
-out:
- smb_rq_done(rqp);
- return (error);
-}
-
-static int
-smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
- struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
+ if (sdnp == tdnp &&
+ (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) != 0) {
+ err = smbfs_smb1_t2rename(np, tname, tnlen, fhp->fh_fid1, scrp);
+ } else {
+ err = smbfs_smb1_oldrename(np, tdnp, tname, tnlen, scrp);
}
- smb_rq_done(rqp);
- return (error);
+
+ return (err);
}
int
smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
struct smb_cred *scrp)
{
+ smb_fh_t tmp_fh;
struct smb_share *ssp = dnp->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- uint32_t rights;
- uint16_t fid;
+ uint32_t efa, rights;
int error;
/*
+ * Using a faked-up handle here to avoid the work of
+ * creating and destroying a real "conn obj".
+ */
+ bzero(&tmp_fh, sizeof (tmp_fh));
+
+ /*
* We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
* just to be asking for something. The rights==0 case could
* easily be broken on some old or unusual servers.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- rights = SA_RIGHT_FILE_READ_DATA;
- error = smbfs_smb_ntcreatex(dnp,
- name, nmlen, 0, /* xattr */
- rights, SMB_EFA_DIRECTORY,
- NTCREATEX_SHARE_ACCESS_ALL,
- NTCREATEX_DISP_CREATE,
- NTCREATEX_OPTIONS_DIRECTORY,
- scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
- if (error)
- return (error);
- (void) smbfs_smb_close(ssp, fid, NULL, scrp);
- return (0);
+ rights = SA_RIGHT_FILE_READ_DATA;
+ efa = SMB_EFA_NORMAL;
+ if (name && *name == '.')
+ efa |= SMB_EFA_HIDDEN;
+ error = smbfs_smb_ntcreatex(dnp,
+ name, nmlen, 0, /* xattr */
+ rights, SMB_EFA_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY,
+ scrp, &tmp_fh, NULL, NULL);
+ if (error == 0) {
+ (void) smb_smb_close(ssp, &tmp_fh, scrp);
}
- error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
- return (error);
-}
-
-int
-smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
-{
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
return (error);
}
-static int
-smbfs_smb_search(struct smbfs_fctx *ctx)
-{
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc, bt;
- uint16_t ec, dlen, bc;
- int maxent, error, iseof = 0;
-
- maxent = min(ctx->f_left,
- (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
- if (ctx->f_rq) {
- smb_rq_done(ctx->f_rq);
- ctx->f_rq = NULL;
- }
- error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
- ctx->f_scred, &rqp);
- if (error)
- return (error);
- ctx->f_rq = rqp;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, maxent); /* max entries to return */
- mb_put_uint16le(mbp, ctx->f_attrmask);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, 0); /* context length */
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- } else {
- if (SMB_UNICODE_STRINGS(vcp)) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0);
- }
- mb_put_uint8(mbp, 0);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, SMB_SKEYLEN);
- mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- }
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
- error = 0;
- iseof = 1;
- ctx->f_flags |= SMBFS_RDD_EOF;
- } else if (error)
- return (error);
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- return (error);
- if (wc != 1)
- return (iseof ? ENOENT : EBADRPC);
- md_get_uint16le(mdp, &ec);
- md_get_uint16le(mdp, &bc);
- md_get_uint8(mdp, &bt);
- error = md_get_uint16le(mdp, &dlen);
- if (error)
- return (error);
- if (ec == 0)
- return (ENOENT);
- ctx->f_ecnt = ec;
- if (bc < 3)
- return (EBADRPC);
- bc -= 3;
- if (bt != SMB_DT_VARIABLE)
- return (EBADRPC);
- if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
- return (EBADRPC);
- return (0);
-}
-
-
-/*ARGSUSED*/
-static int
-smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
-{
-
- ctx->f_type = ft_LM1;
- ctx->f_attrmask = attr;
- if (wildcard) {
- if (wclen == 1 && wildcard[0] == '*') {
- ctx->f_wildcard = "*.*";
- ctx->f_wclen = 3;
- } else {
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- }
- } else {
- ctx->f_wildcard = NULL;
- ctx->f_wclen = 0;
- }
- ctx->f_name = (char *)ctx->f_fname;
- ctx->f_namesz = 0;
- return (0);
-}
-
-static int
-smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
-{
- struct mdchain *mdp;
- struct smb_rq *rqp;
- char *cp;
- uint8_t battr;
- uint16_t date, time;
- uint32_t size;
- int error;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_search(ctx);
- if (error)
- return (error);
- }
- rqp = ctx->f_rq;
- smb_rq_getreply(rqp, &mdp);
- md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- md_get_uint8(mdp, &battr);
- md_get_uint16le(mdp, &time);
- md_get_uint16le(mdp, &date);
- md_get_uint32le(mdp, &size);
- cp = ctx->f_name;
- error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
- cp[sizeof (ctx->f_fname) - 1] = 0;
- cp += strlen(cp) - 1;
- while (*cp == ' ' && cp >= ctx->f_name)
- *cp-- = 0;
- ctx->f_attr.fa_attr = battr;
- smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
- &ctx->f_attr.fa_mtime);
- ctx->f_attr.fa_size = size;
- ctx->f_nmlen = strlen(ctx->f_name);
- ctx->f_ecnt--;
- ctx->f_left--;
- return (0);
-}
-
-static int
-smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
-{
- if (ctx->f_rq)
- smb_rq_done(ctx->f_rq);
- return (0);
-}
-
/*
- * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
+ * Protocol-level directory open
*/
-static int
-smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
-{
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t ecnt, eos, lno, flags;
- int error;
-
- if (ctx->f_t2) {
- smb_t2_done(ctx->f_t2);
- ctx->f_t2 = NULL;
- }
- flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
- if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
- flags |= FIND2_CLOSE_AFTER_REQUEST;
- ctx->f_flags |= SMBFS_RDD_NOCLOSE;
- }
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_attrmask);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, flags);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- mb_put_uint32le(mbp, 0);
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- } else {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- /* Send whatever resume key we received... */
- mb_put_uint32le(mbp, ctx->f_rkey);
- mb_put_uint16le(mbp, flags);
- /* ... and the resume name if we have one. */
- if (ctx->f_rname) {
- /* resume file name */
- mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
- MB_MSYSTEM);
- }
- /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
- mb_put_uint8(mbp, 0);
- }
- t2p->t2_maxpcount = 5 * 2;
- t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
- error = smb_t2_request(t2p);
- if (error)
- return (error);
-
- /*
- * This is the "resume name" we just sent.
- * We want the new one (if any) that may be
- * found in the response we just received and
- * will now begin parsing. Free the old one
- * now so we'll know if we found a new one.
- */
- if (ctx->f_rname) {
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = NULL;
- ctx->f_rnamelen = 0;
- }
-
- mdp = &t2p->t2_rparam;
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
- goto nodata;
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- }
- md_get_uint16le(mdp, &ecnt); /* entry count */
- md_get_uint16le(mdp, &eos); /* end of search */
- md_get_uint16le(mdp, NULL); /* EA err. off. */
- error = md_get_uint16le(mdp, &lno); /* last name off. */
- if (error != 0)
- goto nodata;
-
- /*
- * The "end of search" flag from an XP server sometimes
- * comes back zero when the prior find_next returned exactly
- * the number of entries requested. in which case we'd try again
- * but the search has in fact been closed so an EBADF results.
- * our circumvention is to check here for a zero entry count.
- */
- ctx->f_ecnt = ecnt;
- if (eos || ctx->f_ecnt == 0)
- ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
- if (ctx->f_ecnt == 0)
- return (ENOENT);
-
- /* Last Name Off (LNO) is the entry with the resume name. */
- ctx->f_rnameofs = lno;
- ctx->f_eofs = 0;
- return (0);
-
-nodata:
- /*
- * Failed parsing the FindFirst or FindNext response.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
-}
-
-static int
-smbfs_smb_findclose2(struct smbfs_fctx *ctx)
-{
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
- ctx->f_scred);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- /* Ditto comments at _smb_close */
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- return (error);
-}
-
-/*ARGSUSED*/
-static int
-smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
-{
-
- ctx->f_type = ft_LM2;
- ctx->f_namesz = SMB_MAXFNAMELEN + 1;
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- ctx->f_namesz *= 2;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
- ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
- < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
- SMB_FIND_BOTH_DIRECTORY_INFO;
- ctx->f_attrmask = attr;
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- return (0);
-}
-
-static int
-smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
-{
- struct mdchain *mdp;
- struct smb_t2rq *t2p;
- char *cp;
- uint8_t tb;
- uint16_t date, time, wattr;
- uint32_t size, next, dattr, resumekey = 0;
- uint64_t llongint;
- int error, svtz, cnt, fxsz, nmlen, recsz;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_trans2find2(ctx);
- if (error)
- return (error);
- ctx->f_otws++;
- }
- t2p = ctx->f_t2;
- mdp = &t2p->t2_rdata;
- svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
- switch (ctx->f_infolevel) {
- case SMB_FIND_STANDARD:
- next = 0;
- fxsz = 0;
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz,
- &ctx->f_attr.fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
- md_get_uint32le(mdp, &size);
- ctx->f_attr.fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- ctx->f_attr.fa_allocsz = size;
- md_get_uint16le(mdp, &wattr);
- ctx->f_attr.fa_attr = wattr;
- error = md_get_uint8(mdp, &tb);
- if (error)
- goto nodata;
- size = nmlen = tb;
- fxsz = 23;
- recsz = next = 24 + nmlen; /* docs misses zero byte @end */
- break;
- case SMB_FIND_DIRECTORY_INFO:
- case SMB_FIND_BOTH_DIRECTORY_INFO:
- md_get_uint32le(mdp, &next);
- md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
- md_get_uint64le(mdp, &llongint); /* creation time */
- smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
- md_get_uint64le(mdp, &llongint); /* file size */
- ctx->f_attr.fa_size = llongint;
- md_get_uint64le(mdp, &llongint); /* alloc. size */
- ctx->f_attr.fa_allocsz = llongint;
- md_get_uint32le(mdp, &dattr); /* ext. file attributes */
- ctx->f_attr.fa_attr = dattr;
- error = md_get_uint32le(mdp, &size); /* name len */
- if (error)
- goto nodata;
- fxsz = 64; /* size ofinfo up to filename */
- if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
- /*
- * Skip EaSize(4 bytes), a byte of ShortNameLength,
- * a reserved byte, and ShortName(8.3 means 24 bytes,
- * as Leach defined it to always be Unicode)
- */
- error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
- if (error)
- goto nodata;
- fxsz += 30;
- }
- recsz = next ? next : fxsz + size;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
- return (EINVAL);
- }
-
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- nmlen = min(size, SMB_MAXFNAMELEN * 2);
- else
- nmlen = min(size, SMB_MAXFNAMELEN);
-
- /* Allocated f_name in findopen */
- ASSERT(nmlen < ctx->f_namesz);
- cp = ctx->f_name;
-
- error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
- if (error)
- goto nodata;
- if (next) {
- /* How much data to skip? */
- cnt = next - nmlen - fxsz;
- if (cnt < 0) {
- SMBVDEBUG("out of sync\n");
- goto nodata;
- }
- if (cnt > 0)
- md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
- }
- /* Don't count any trailing null in the name. */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
- if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
- nmlen -= 2;
- } else {
- if (nmlen && cp[nmlen - 1] == 0)
- nmlen--;
- }
- if (nmlen == 0)
- goto nodata;
-
- /*
- * On a find-next we expect that the server will:
- * 1) if the continue bit is set, use the server's offset,
- * 2) else if the resume key is non-zero, use that offset,
- * 3) else if the resume name is set, use that offset,
- * 4) else use the server's idea of current offset.
- *
- * We always set the resume key flag. If the server returns
- * a resume key then we should always send it back to them.
- */
- ctx->f_rkey = resumekey;
-
- next = ctx->f_eofs + recsz;
- if (ctx->f_rnameofs &&
- ctx->f_rnameofs >= ctx->f_eofs &&
- ctx->f_rnameofs < (int)next) {
- /*
- * This entry is the "resume name".
- * Save it for the next request.
- */
- if (ctx->f_rnamelen != nmlen) {
- if (ctx->f_rname)
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
- ctx->f_rnamelen = nmlen;
- }
- bcopy(ctx->f_name, ctx->f_rname, nmlen);
- }
- ctx->f_nmlen = nmlen;
- ctx->f_eofs = next;
- ctx->f_ecnt--;
- ctx->f_left--;
-
- smbfs_fname_tolocal(ctx);
- return (0);
-
-nodata:
- /*
- * Something bad has happened and we ran out of data
- * before we could parse all f_ecnt entries expected.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- SMBVDEBUG("ran out of data\n");
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
-}
-
-static int
-smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
-{
- int error = 0;
- if (ctx->f_name)
- kmem_free(ctx->f_name, ctx->f_namesz);
- if (ctx->f_t2)
- smb_t2_done(ctx->f_t2);
- /*
- * If SMBFS_RDD_FINDFIRST is still set, we were opened
- * but never saw a findfirst, so we don't have any
- * search handle to close.
- */
- if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
- error = smbfs_smb_findclose2(ctx);
- return (error);
-}
-
int
smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
int attr, struct smb_cred *scrp,
struct smbfs_fctx **ctxpp)
{
+ struct smb_share *ssp = dnp->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
struct smbfs_fctx *ctx;
int error;
@@ -2287,50 +586,56 @@ smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
ctx->f_flags = SMBFS_RDD_FINDFIRST;
ctx->f_dnp = dnp;
ctx->f_scred = scrp;
- ctx->f_ssp = dnp->n_mount->smi_share;
+ ctx->f_ssp = ssp;
if (dnp->n_flag & N_XATTR) {
error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
goto out;
}
- if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
- error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_findopen(ctx, dnp, wild, wlen, attr);
} else {
error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
}
out:
- if (error)
- (void) smbfs_smb_findclose(ctx, scrp);
- else
+ ctx->f_scred = NULL;
+ if (error) {
+ kmem_free(ctx, sizeof (*ctx));
+ } else {
*ctxpp = ctx;
+ }
+
return (error);
}
int
smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
{
- int error;
+ int error = 0;
+ uint16_t lim;
/*
* Note: "limit" (maxcount) needs to fit in a short!
*/
if (limit > 0xffff)
limit = 0xffff;
+ lim = (uint16_t)limit;
ctx->f_scred = scrp;
for (;;) {
bzero(&ctx->f_attr, sizeof (ctx->f_attr));
switch (ctx->f_type) {
- case ft_LM1:
- error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
+
+ case ft_SMB2:
+ error = smbfs_smb2_findnext(ctx, lim);
break;
case ft_LM2:
- error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
+ error = smbfs_smb_findnextLM2(ctx, lim);
break;
case ft_XA:
- error = smbfs_xa_findnext(ctx, (uint16_t)limit);
+ error = smbfs_xa_findnext(ctx, lim);
break;
default:
ASSERT(0);
@@ -2338,7 +643,7 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
break;
}
if (error)
- return (error);
+ break;
/*
* Skip "." or ".." - easy now that ctx->f_name
* has already been converted to utf-8 format.
@@ -2349,14 +654,18 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
continue;
break;
}
+ ctx->f_scred = NULL;
+ if (error != 0)
+ return (error);
- /*
- * Moved the smbfs_fname_tolocal(ctx) call into
- * the ..._findnext functions above.
- */
+ ctx->f_inum = smbfs_getino(ctx->f_dnp,
+ ctx->f_name, ctx->f_nmlen);
- ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
- return (0);
+#ifdef DEBUG
+ SMBVDEBUG("findnext: (%s)\n", ctx->f_name);
+#endif
+
+ return (error);
}
@@ -2367,8 +676,8 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
ctx->f_scred = scrp;
switch (ctx->f_type) {
- case ft_LM1:
- error = smbfs_smb_findcloseLM1(ctx);
+ case ft_SMB2:
+ error = smbfs_smb2_findclose(ctx);
break;
case ft_LM2:
error = smbfs_smb_findcloseLM2(ctx);
@@ -2376,7 +685,11 @@ smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
case ft_XA:
error = smbfs_xa_findclose(ctx);
break;
+ default:
+ error = ENOSYS;
+ break;
}
+ ctx->f_scred = NULL;
if (ctx->f_rname)
kmem_free(ctx->f_rname, ctx->f_rnamelen);
if (ctx->f_firstnm)
@@ -2416,25 +729,12 @@ smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
}
/*
- * XXX: Should use _qpathinfo here instead.
- * (if SMB_CAP_NT_SMBS)
- */
-
- /*
* Shared lock for n_fid use (smb_flush).
*/
intr = dnp->n_mount->smi_flags & SMI_INT;
if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
return (EINTR);
- /*
- * This hides a server bug observable in Win98:
- * size changes may not show until a CLOSE or a FLUSH op
- * XXX: Make this conditional on !NTSMBs
- */
- error = smbfs_smb_flush(dnp, scrp);
- if (error)
- goto out;
error = smbfs_smb_findopen(dnp, name, nmlen,
SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
if (error)
@@ -2468,148 +768,49 @@ out:
* which the caller should free.
*/
int
-smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector,
- mblk_t **res, uint32_t *reslen)
+smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fhp,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
{
- struct smb_ntrq *ntp;
- struct mbchain *mbp;
- struct mdchain *mdp;
+ struct smb_vc *vcp = SSTOVC(ssp);
int error, len;
- error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
- scrp, &ntp);
- if (error)
- return (error);
-
- /* Parameters part */
- mbp = &ntp->nt_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, selector);
- /* Data part (none) */
-
- /* Max. returned parameters and data. */
- ntp->nt_maxpcount = 4;
- ntp->nt_maxdcount = *reslen;
-
- error = smb_nt_request(ntp);
- if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
- goto done;
*res = NULL;
- /*
- * if there's more data than we said we could receive, here
- * is where we pick up the length of it
- */
- mdp = &ntp->nt_rparam;
- md_get_uint32le(mdp, reslen);
- if (error)
- goto done;
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_getsec(ssp, &fhp->fh_fid2,
+ selector, res, reslen, scrp);
+ } else {
+ error = smbfs_smb1_getsec(ssp, fhp->fh_fid1,
+ selector, res, reslen, scrp);
+ }
/*
* get the data part.
*/
- mdp = &ntp->nt_rdata;
- if (mdp->md_top == NULL) {
- SMBVDEBUG("null md_top? fid 0x%x\n", fid);
+ if (*res == NULL) {
error = EBADRPC;
goto done;
}
/*
- * The returned parameter SD_length should match
- * the length of the returned data. Unfortunately,
- * we have to work around server bugs here.
- */
- len = m_fixhdr(mdp->md_top);
- if (len != *reslen) {
- SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
- len, *reslen, fid);
- }
-
- /*
- * Actual data provided is < returned SD_length.
- *
- * The following "if (len < *reslen)" handles a Windows bug
- * observed when the underlying filesystem is FAT32. In that
- * case a 32 byte security descriptor comes back (S-1-1-0, ie
- * "Everyone") but the Parameter Block claims 44 is the length
- * of the security descriptor. (The Data Block length
- * claimed is 32. This server bug was reported against NT
- * first and I've personally observed it with W2K.
+ * If message length is < returned SD_length,
+ * correct *reslen (reduce it). It greater,
+ * just ignore the extra data.
*/
+ len = m_fixhdr(*res);
if (len < *reslen)
*reslen = len;
- /*
- * Actual data provided is > returned SD_length.
- * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
- * Narrow work-around for returned SD_length==0.
- */
- if (len > *reslen) {
- /*
- * Increase *reslen, but carefully.
- */
- if (*reslen == 0 && len <= ntp->nt_maxdcount)
- *reslen = len;
- }
- error = md_get_mbuf(mdp, len, res);
-
done:
if (error == 0 && *res == NULL) {
ASSERT(*res);
error = EBADRPC;
}
- smb_nt_done(ntp);
return (error);
}
-#ifdef APPLE
-/*
- * Wrapper for _getsd() compatible with darwin code.
- */
-int
-smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
- uint32_t selector, struct ntsecdesc **res)
-{
- int error;
- uint32_t len, olen;
- struct mdchain *mdp, md_store;
- struct mbuf *m;
-
- bzero(mdp, sizeof (*mdp));
- len = 500; /* "overlarge" values => server errors */
-again:
- olen = len;
- error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
- /*
- * Server may give us an error indicating that we
- * need a larger data buffer to receive the SD,
- * and the size we'll need. Use the given size,
- * but only after a sanity check.
- *
- * XXX: Check for specific error values here?
- * XXX: also ... && len <= MAX_RAW_SD_SIZE
- */
- if (error && len > olen)
- goto again;
-
- if (error)
- return (error);
-
- mdp = &md_store;
- md_initm(mdp, m);
- MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
- error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
- md_done(mdp);
-
- return (error);
-}
-#endif /* APPLE */
-
/*
* OTW function to Set a security descriptor (SD).
* Caller data are carried in an mbchain_t.
@@ -2617,108 +818,21 @@ again:
* Note: This normally consumes mbp->mb_top, and clears
* that pointer when it does.
*/
-int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
-{
- struct smb_ntrq *ntp;
- struct mbchain *mbp;
- int error;
-
- error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
- scrp, &ntp);
- if (error)
- return (error);
-
- /* Parameters part */
- mbp = &ntp->nt_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, selector);
-
- /* Data part */
- mbp = &ntp->nt_tdata;
- mb_initm(mbp, *mp);
- *mp = NULL; /* consumed */
-
- /* No returned parameters or data. */
- ntp->nt_maxpcount = 0;
- ntp->nt_maxdcount = 0;
-
- error = smb_nt_request(ntp);
- smb_nt_done(ntp);
-
- return (error);
-}
-
-#ifdef APPLE
-/*
- * This function builds the SD given the various parts.
- */
int
-smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
- uint32_t selector, uint16_t flags, struct ntsid *owner,
- struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
+smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fhp,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp)
{
- struct mbchain *mbp, mb_store;
- struct ntsecdesc ntsd;
- int error, off;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ int error;
- /*
- * Build the SD as its own mbuf chain and pass it to
- * smbfs_smb_setsec_m()
- */
- mbp = &mb_store;
- mb_init(mbp);
- bzero(&ntsd, sizeof (ntsd));
- wset_sdrevision(&ntsd);
- /*
- * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
- * We set here only those bits we can be sure must be set. The rest
- * are up to the caller. In particular, the caller may intentionally
- * set an acl PRESENT bit while giving us a null pointer for the
- * acl - that sets a null acl, giving access to everyone. Note also
- * that the AUTO_INHERITED bits should probably always be set unless
- * the server is NT.
- */
- flags |= SD_SELF_RELATIVE;
- off = sizeof (ntsd);
- if (owner) {
- wset_sdowneroff(&ntsd, off);
- off += sidlen(owner);
- }
- if (group) {
- wset_sdgroupoff(&ntsd, off);
- off += sidlen(group);
- }
- if (sacl) {
- flags |= SD_SACL_PRESENT;
- wset_sdsacloff(&ntsd, off);
- off += acllen(sacl);
- }
- if (dacl) {
- flags |= SD_DACL_PRESENT;
- wset_sddacloff(&ntsd, off);
+ if (vcp->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_setsec(ssp, &fhp->fh_fid2,
+ selector, mp, scrp);
+ } else {
+ error = smbfs_smb1_setsec(ssp, fhp->fh_fid1,
+ selector, mp, scrp);
}
- wset_sdflags(&ntsd, flags);
- mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
- if (owner)
- mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
- if (group)
- mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
- if (sacl)
- mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
- if (dacl)
- mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
-
- /*
- * Just pass the mbuf to _setsec_m
- * It will clear mb_top if consumed.
- */
- error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
- mb_done(mbp);
return (error);
}
-
-#endif /* APPLE */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c
new file mode 100644
index 0000000000..6c00816133
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb1.c
@@ -0,0 +1,926 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/inttypes.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Todo: locking over-the-wire
+ */
+#if 0 // todo
+
+int
+smbfs_smb1_lockandx(struct smbnode *np, int op, uint32_t pid,
+ offset_t start, uint64_t len, int largelock,
+ struct smb_cred *scrp, uint32_t timeout)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ uint8_t ltype = 0;
+ int error;
+
+ /* Shared lock for n_fid use below. */
+ ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+ /* After reconnect, n_fid is invalid */
+ if (np->n_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ if (op == SMB_LOCK_SHARED)
+ ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
+ /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
+ if (largelock)
+ ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint8(mbp, 0xff); /* secondary command */
+ mb_put_uint8(mbp, 0); /* MBZ */
+ mb_put_uint16le(mbp, 0);
+ mb_put_uint16le(mbp, np->n_fid);
+ mb_put_uint8(mbp, ltype); /* locktype */
+ mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
+ mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
+ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
+ mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ mb_put_uint16le(mbp, pid);
+ if (!largelock) {
+ mb_put_uint32le(mbp, start);
+ mb_put_uint32le(mbp, len);
+ } else {
+ mb_put_uint16le(mbp, 0); /* pad */
+ mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
+ mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
+ mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
+ mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
+ }
+ smb_rq_bend(rqp);
+ /*
+ * Don't want to risk missing a successful
+ * unlock send or lock response, or we could
+ * lose track of an outstanding lock.
+ */
+ if (op == SMB_LOCK_RELEASE)
+ rqp->sr_flags |= SMBR_NOINTR_SEND;
+ else
+ rqp->sr_flags |= SMBR_NOINTR_RECV;
+
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+#endif // todo
+
+/*
+ * Common function for QueryFileInfo, QueryPathInfo.
+ */
+int
+smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid,
+ struct smbfattr *fap, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct smb_t2rq *t2p;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t cmd;
+ uint16_t infolevel = SMB_QFILEINFO_ALL_INFO;
+ int error;
+
+ /*
+ * If we have a valid open FID, use it.
+ */
+ if (fid != SMB_FID_UNUSED)
+ cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
+ else
+ cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+
+ if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
+ mb_put_uint16le(mbp, fid);
+
+ mb_put_uint16le(mbp, infolevel);
+
+ if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
+ mb_put_uint32le(mbp, 0);
+ /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
+ error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
+ if (error)
+ goto out;
+ }
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = vcp->vc_txmax;
+ error = smb_t2_request(t2p);
+ if (error)
+ goto out;
+
+ /*
+ * Parse the SMB_QFILEINFO_ALL_INFO
+ */
+ mdp = &t2p->t2_rdata;
+ error = smbfs_decode_file_all_info(ssp, mdp, fap);
+
+out:
+ smb_t2_done(t2p);
+
+ return (error);
+}
+
+/*
+ * Get some FS information
+ */
+static int
+smbfs_smb1_query_fs_info(struct smb_share *ssp, struct mdchain *info_mdp,
+ uint16_t level, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ int error;
+
+ error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
+ scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, level);
+ t2p->t2_maxpcount = 4;
+ t2p->t2_maxdcount = 1024;
+ error = smb_t2_request(t2p);
+ if (error)
+ goto out;
+
+ mdp = &t2p->t2_rdata;
+ *info_mdp = *mdp;
+ bzero(mdp, sizeof (*mdp));
+
+out:
+ smb_t2_done(t2p);
+ return (error);
+}
+
+/*
+ * Get FILE_FS_ATTRIBUTE_INFORMATION
+ */
+int
+smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb1_query_fs_info(ssp, mdp,
+ SMB_QFS_ATTRIBUTE_INFO, scrp);
+ if (error)
+ goto out;
+ error = smbfs_decode_fs_attr_info(ssp, mdp, fsa);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsFullSizeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb1_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint16_t level;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_QFS_FULL_SIZE_INFORMATION;
+ else
+ level = SMB_QFS_SIZE_INFO;
+ error = smbfs_smb1_query_fs_info(ssp, mdp, level, scrp);
+ if (error)
+ goto out;
+
+ md_get_uint64le(mdp, &info->total_units);
+ md_get_uint64le(mdp, &info->caller_avail);
+ if (level == SMB_QFS_FULL_SIZE_INFORMATION)
+ md_get_uint64le(mdp, &info->actual_avail);
+ else
+ info->actual_avail = info->caller_avail;
+
+ md_get_uint32le(mdp, &info->sect_per_unit);
+ error = md_get_uint32le(mdp, &info->bytes_per_sect);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+int
+smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, fid);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*
+ * Set file info via an open handle.
+ * Caller provides payload, info level.
+ */
+static int
+smbfs_smb1_setinfo_file(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *info_mbp, uint16_t level, struct smb_cred *scrp)
+{
+ struct smb_t2rq *t2p = NULL;
+ struct mbchain *mbp;
+ uint16_t cmd = SMB_TRANS2_SET_FILE_INFORMATION;
+ int error;
+
+ ASSERT(fid != SMB_FID_UNUSED);
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, level);
+ mb_put_uint16le(mbp, 0); /* pad */
+
+ /* put the payload */
+ mbp = &t2p->t2_tdata;
+ mb_init(mbp);
+ error = mb_put_mbchain(mbp, info_mbp);
+ if (error)
+ goto out;
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = 0;
+ error = smb_t2_request(t2p);
+
+out:
+ smb_t2_done(t2p);
+
+ return (error);
+}
+
+int
+smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid,
+ uint64_t newsize, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
+ else
+ level = SMB_SFILEINFO_END_OF_FILE_INFO;
+
+ mb_init(mbp);
+ error = mb_put_uint64le(mbp, newsize);
+ if (error)
+ goto out;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+ return (error);
+}
+
+int
+smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid,
+ uint8_t newdisp, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
+ else
+ level = SMB_SFILEINFO_DISPOSITION_INFO;
+
+ mb_init(mbp);
+ error = mb_put_uint8(mbp, newdisp);
+ if (error)
+ goto out;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Set FileBasicInformation on an open handle
+ * Caller builds the mbchain.
+ * Always have a FID here.
+ */
+int
+smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *mbp, struct smb_cred *scrp)
+{
+ uint16_t level;
+ int error;
+
+ if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+ level = SMB_SFILEINFO_BASIC_INFORMATION;
+ else
+ level = SMB_SFILEINFO_BASIC_INFO;
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+ return (error);
+}
+
+/*
+ * On SMB1, the trans2 rename only allows a rename where the
+ * source and target are in the same directory. If you give
+ * the server any separators, you get "status not supported".
+ *
+ * Why bother using this instead of smbfs_smb1_oldrename?
+ * Because it works with an open file, and some servers don't
+ * allow oldrename of a file that's currently open. We call
+ * this when deleting an open file in smbfsremove(), where
+ * the rename is always in the same directory.
+ */
+/*ARGSUSED*/
+int
+smbfs_smb1_t2rename(struct smbnode *np,
+ const char *tname, int tnlen,
+ uint16_t fid, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct mbchain data_mb, *mbp = &data_mb;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint32_t *name_lenp;
+ uint16_t level = SMB_SFILEINFO_RENAME_INFORMATION;
+ int base, len;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint32le(mbp, 0); /* don't overwrite */
+ mb_put_uint32le(mbp, 0); /* obsolete target dir fid */
+ name_lenp = mb_reserve(mbp, 4); /* name len */
+
+ /* New name */
+ base = mbp->mb_count;
+ error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
+ if (error)
+ goto out;
+ len = mbp->mb_count - base;
+ *name_lenp = htolel(len);
+
+ error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
+
+out:
+ mb_done(mbp);
+ return (error);
+}
+
+/*
+ * Do an SMB1 (old style) rename using a full dest. path.
+ * This is used when renaming to a different directory,
+ * because the (preferred) t2rename can't do that.
+ */
+int
+smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, struct smb_cred *scrp)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = src->n_mount->smi_share;
+ struct mbchain *mbp;
+ int error;
+ uint16_t fa;
+ char sep;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
+ fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
+ fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
+ mb_put_uint16le(mbp, fa);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+
+ /*
+ * When we're not adding any component name, the
+ * passed sep is ignored, so just pass sep=0.
+ */
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
+ if (error)
+ goto out;
+
+ /*
+ * After XATTR directories, separator is ":"
+ */
+ sep = (src->n_flag & N_XATTR) ? ':' : '\\';
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
+ if (error)
+ goto out;
+
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+out:
+ smb_rq_done(rqp);
+ return (error);
+}
+
+
+/*
+ * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
+ */
+static int
+smbfs_smb1_trans2find2(struct smbfs_fctx *ctx)
+{
+ struct smb_t2rq *t2p;
+ struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t ecnt, eos, lno, flags;
+ uint16_t amask, limit;
+ int error;
+
+ /* smbfs_smb_findnextLM2 sets this */
+ limit = ctx->f_limit;
+ amask = (uint16_t)ctx->f_attrmask;
+
+ if (ctx->f_t2) {
+ smb_t2_done(ctx->f_t2);
+ ctx->f_t2 = NULL;
+ }
+ flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
+ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
+ flags |= FIND2_CLOSE_AFTER_REQUEST;
+ ctx->f_flags |= SMBFS_RDD_NOCLOSE;
+ }
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+ error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
+ ctx->f_scred, &t2p);
+ if (error)
+ return (error);
+ ctx->f_t2 = t2p;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, amask);
+ mb_put_uint16le(mbp, limit);
+ mb_put_uint16le(mbp, flags);
+ mb_put_uint16le(mbp, ctx->f_infolevel);
+ mb_put_uint32le(mbp, 0);
+ error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
+ ctx->f_wildcard, ctx->f_wclen, '\\');
+ if (error)
+ return (error);
+ } else {
+ error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
+ ctx->f_scred, &t2p);
+ if (error)
+ return (error);
+ ctx->f_t2 = t2p;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, ctx->f_Sid);
+ mb_put_uint16le(mbp, limit);
+ mb_put_uint16le(mbp, ctx->f_infolevel);
+ /* Send whatever resume key we received... */
+ mb_put_uint32le(mbp, ctx->f_rkey);
+ mb_put_uint16le(mbp, flags);
+ /* ... and the resume name if we have one. */
+ if (ctx->f_rname) {
+ /* resume file name */
+ mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
+ MB_MSYSTEM);
+ }
+ /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
+ if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+ mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
+ mb_put_uint8(mbp, 0);
+ }
+ t2p->t2_maxpcount = 5 * 2;
+ t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
+ error = smb_t2_request(t2p);
+ if (error)
+ return (error);
+
+ /*
+ * This is the "resume name" we just sent.
+ * We want the new one (if any) that may be
+ * found in the response we just received and
+ * will now begin parsing. Free the old one
+ * now so we'll know if we found a new one.
+ */
+ if (ctx->f_rname) {
+ kmem_free(ctx->f_rname, ctx->f_rnamelen);
+ ctx->f_rname = NULL;
+ ctx->f_rnamelen = 0;
+ }
+
+ mdp = &t2p->t2_rparam;
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+ if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
+ goto nodata;
+ ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
+ }
+ md_get_uint16le(mdp, &ecnt); /* entry count */
+ md_get_uint16le(mdp, &eos); /* end of search */
+ md_get_uint16le(mdp, NULL); /* EA err. off. */
+ error = md_get_uint16le(mdp, &lno); /* last name off. */
+ if (error != 0)
+ goto nodata;
+
+ /*
+ * The "end of search" flag from an XP server sometimes
+ * comes back zero when the prior find_next returned exactly
+ * the number of entries requested. in which case we'd try again
+ * but the search has in fact been closed so an EBADF results.
+ * our circumvention is to check here for a zero entry count.
+ */
+ ctx->f_ecnt = ecnt;
+ if (eos || ctx->f_ecnt == 0)
+ ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
+ if (ctx->f_ecnt == 0)
+ return (ENOENT);
+
+ /* Last Name Off (LNO) is the entry with the resume name. */
+ ctx->f_rnameofs = lno;
+ ctx->f_eofs = 0;
+
+ /*
+ * Have data. Put the payload in ctx->f_mdchain
+ * Note struct assignments here.
+ */
+ mdp = &t2p->t2_rdata;
+ md_done(&ctx->f_mdchain);
+ ctx->f_mdchain = *mdp;
+ ctx->f_left = m_fixhdr(mdp->md_top);
+ bzero(mdp, sizeof (*mdp));
+
+ return (0);
+
+nodata:
+ /*
+ * Failed parsing the FindFirst or FindNext response.
+ * Force this directory listing closed, otherwise the
+ * calling process may hang in an infinite loop.
+ */
+ ctx->f_ecnt = 0; /* Force closed. */
+ ctx->f_flags |= SMBFS_RDD_EOF;
+ return (EIO);
+}
+
+static int
+smbfs_smb1_findclose2(struct smbfs_fctx *ctx)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
+ ctx->f_scred);
+ if (error)
+ return (error);
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, ctx->f_Sid);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ /* Ditto comments at _smb_close */
+ rqp->sr_flags |= SMBR_NOINTR_SEND;
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr)
+{
+
+ ctx->f_type = ft_LM2;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = SMB_FIND_FULL_DIRECTORY_INFO;
+ ctx->f_attrmask = attr;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
+ return (0);
+}
+
+int
+smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
+{
+ int error = 0;
+ if (ctx->f_name)
+ kmem_free(ctx->f_name, ctx->f_namesz);
+ if (ctx->f_t2)
+ smb_t2_done(ctx->f_t2);
+ md_done(&ctx->f_mdchain);
+
+ /*
+ * If SMBFS_RDD_FINDFIRST is still set, we were opened
+ * but never saw a findfirst, so we don't have any
+ * search handle to close.
+ */
+ if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
+ error = smbfs_smb1_findclose2(ctx);
+ return (error);
+}
+
+/*
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
+ */
+int
+smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
+
+ /*
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
+ */
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_smb1_trans2find2(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
+
+ /*
+ * Decode one entry, advance f_eofs
+ */
+ error = smbfs_decode_dirent(ctx);
+
+ return (error);
+}
+
+/*
+ * Helper for smbfs_xa_get_streaminfo
+ * Query stream info
+ */
+int
+smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp)
+{
+ smb_share_t *ssp = np->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct smb_t2rq *t2p = NULL;
+ struct mbchain *mbp;
+ mblk_t *m;
+ uint16_t cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
+ int error;
+
+ error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
+ if (error)
+ return (error);
+
+ mbp = &t2p->t2_tparam;
+ (void) mb_init(mbp);
+ (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
+ (void) mb_put_uint32le(mbp, 0);
+ error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, 0);
+ if (error)
+ goto out;
+
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = INT16_MAX;
+ error = smb_t2_request(t2p);
+ if (error) {
+ if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * Have data. Move it to *mdp
+ */
+ m = t2p->t2_rdata.md_top;
+ if (m == NULL) {
+ error = EBADRPC;
+ goto out;
+ }
+ t2p->t2_rdata.md_top = NULL;
+ md_initm(mdp, m);
+
+out:
+ smb_t2_done(t2p);
+ return (error);
+}
+
+/*
+ * OTW function to Get a security descriptor (SD).
+ *
+ * The *reslen param is bufsize(in) / length(out)
+ * Note: On success, this fills in mdp->md_top,
+ * which the caller should free.
+ */
+int
+smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
+{
+ struct smb_ntrq *ntp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t dlen;
+ int error;
+
+ *res = NULL;
+
+ error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
+ scrp, &ntp);
+ if (error)
+ return (error);
+
+ /* Parameters part */
+ mbp = &ntp->nt_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, selector);
+ /* Data part (none) */
+
+ /* Max. returned parameters and data. */
+ ntp->nt_maxpcount = 4;
+ ntp->nt_maxdcount = *reslen; // out buf size
+
+ error = smb_nt_request(ntp);
+ if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
+ goto done;
+
+ /* Get data len */
+ mdp = &ntp->nt_rparam;
+ error = md_get_uint32le(mdp, &dlen);
+ if (error)
+ goto done;
+
+ /*
+ * if there's more data than we said we could receive,
+ * here is where we pick up the length of it
+ */
+ *reslen = dlen;
+ if (dlen == 0) {
+ error = EBADRPC;
+ goto done;
+ }
+
+ /*
+ * get the SD data part.
+ */
+ mdp = &ntp->nt_rdata;
+ error = md_get_mbuf(mdp, dlen, res);
+
+done:
+ if (error == 0 && *res == NULL) {
+ ASSERT(*res);
+ error = EBADRPC;
+ }
+
+ smb_nt_done(ntp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Set a security descriptor (SD).
+ * Caller data are carried in an mbchain_t.
+ *
+ * Note: This normally consumes mbp->mb_top, and clears
+ * that pointer when it does.
+ */
+int
+smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
+{
+ struct smb_ntrq *ntp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
+ scrp, &ntp);
+ if (error)
+ return (error);
+
+ /* Parameters part */
+ mbp = &ntp->nt_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, fid);
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, selector);
+
+ /* Data part */
+ mbp = &ntp->nt_tdata;
+ mb_initm(mbp, *mp);
+ *mp = NULL; /* consumed */
+
+ /* No returned parameters or data. */
+ ntp->nt_maxpcount = 0;
+ ntp->nt_maxdcount = 0;
+
+ error = smb_nt_request(ntp);
+ smb_nt_done(ntp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c
new file mode 100644
index 0000000000..80afc327c3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb2.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/inttypes.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+
+#include <netsmb/smb_osdep.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb2_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Todo: locking over-the-wire
+ */
+#if 0 // todo
+
+int
+smbfs_smb2_locking(struct smbnode *np, int op, uint32_t pid,
+ offset_t start, uint64_t len, int largelock,
+ struct smb_cred *scrp, uint32_t timeout)
+{
+ return (ENOTSUP);
+}
+
+#endif // todo
+
+/*
+ * Helper for smbfs_getattr_otw
+ * used when we don't have an open FID
+ *
+ * For SMB2 we need to do an attribute-only open. The
+ * data returned by open gets us everything we need, so
+ * just close the handle and we're done.
+ */
+int
+smbfs_smb2_getpattr(
+ struct smbnode *np,
+ struct smbfattr *fap,
+ struct smb_cred *scrp)
+{
+ smb_fh_t tmp_fh;
+ struct smb_share *ssp = np->n_mount->smi_share;
+ uint32_t rights = (STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES);
+ int error;
+
+ bzero(&tmp_fh, sizeof (tmp_fh));
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, &tmp_fh,
+ NULL, fap);
+ if (error == 0) {
+ (void) smb_smb_close(ssp, &tmp_fh, scrp);
+ }
+
+ return (error);
+}
+
+/*
+ * Common SMB2 query file info
+ */
+static int
+smbfs_smb2_query_info(struct smb_share *ssp, smb2fid_t *fid,
+ struct mdchain *info_mdp, uint32_t *iolen,
+ uint8_t type, uint8_t level, uint32_t addl_info,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint32_t dlen = 0;
+ uint16_t doff = 0;
+ uint16_t ssize = 0;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_QUERY_INFO, scrp, &rqp);
+ if (error)
+ goto out;
+
+ /*
+ * Build the SMB 2 Query Info req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 41); // struct size
+ mb_put_uint8(mbp, type);
+ mb_put_uint8(mbp, level);
+ mb_put_uint32le(mbp, *iolen); // out buf len
+ mb_put_uint16le(mbp, 0); // in buf off
+ mb_put_uint16le(mbp, 0); // reserved
+ mb_put_uint32le(mbp, 0); // in buf len
+ mb_put_uint32le(mbp, addl_info);
+ mb_put_uint32le(mbp, 0); // flags
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ error = smb2_rq_simple(rqp);
+ if (error) {
+ if (rqp->sr_error == NT_STATUS_INVALID_PARAMETER)
+ error = ENOTSUP;
+ goto out;
+ }
+
+ /*
+ * Parse SMB 2 Query Info response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 9 */
+ md_get_uint16le(mdp, &ssize);
+ if (ssize != 9) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ /* Get data off, len */
+ md_get_uint16le(mdp, &doff);
+ md_get_uint32le(mdp, &dlen);
+ *iolen = dlen;
+
+ /*
+ * Skip ahead to the payload, as needed.
+ * Current offset is SMB2_HDRLEN + 8.
+ */
+ if (dlen != 0) {
+ mblk_t *m = NULL;
+ int skip = (int)doff - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ error = md_get_mbuf(mdp, dlen, &m);
+ if (error)
+ goto out;
+ md_initm(info_mdp, m);
+ }
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+
+/*
+ * Get FileAllInformation for an open file
+ * and parse into *fap
+ */
+int
+smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
+ struct smbfattr *fap, struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ uint32_t iolen = 1024;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_info(ssp, fid, mdp, &iolen,
+ SMB2_0_INFO_FILE, FileAllInformation, 0, scrp);
+ if (error)
+ goto out;
+
+ error = smbfs_decode_file_all_info(ssp, mdp, fap);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get some SMB2_0_INFO_FILESYSTEM info
+ *
+ * Note: This can be called during mount. We don't have any
+ * smbfs_node_t or pathname, so do our own attr. open on
+ * the root of the share to get a handle for this request.
+ */
+static int
+smbfs_smb2_query_fs_info(struct smb_share *ssp, struct mdchain *mdp,
+ uint8_t level, struct smb_cred *scrp)
+{
+ smb2fid_t fid;
+ uint32_t iolen = 1024;
+ boolean_t opened = B_FALSE;
+ int error;
+
+ /*
+ * Need a FID for smb2, and this is called during mount
+ * so "go behind" the usual open/close functions.
+ */
+ error = smb2_smb_ntcreate(
+ ssp, NULL, // name
+ NULL, NULL, // create ctx in, out
+ 0, /* NTCREATEX_FLAGS... */
+ SA_RIGHT_FILE_READ_ATTRIBUTES,
+ SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ NTCREATEX_IMPERSONATION_IMPERSONATION,
+ scrp, &fid, NULL, NULL);
+ if (error != 0)
+ goto out;
+ opened = B_TRUE;
+
+ error = smbfs_smb2_query_info(ssp, &fid, mdp, &iolen,
+ SMB2_0_INFO_FILESYSTEM, level, 0, scrp);
+
+out:
+ if (opened)
+ (void) smb2_smb_close(ssp, &fid, scrp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsAttributeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_fs_info(ssp, mdp,
+ FileFsAttributeInformation, scrp);
+ if (error)
+ goto out;
+ error = smbfs_decode_fs_attr_info(ssp, mdp, info);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+/*
+ * Get FileFsFullSizeInformation and
+ * parse into *info
+ */
+int
+smbfs_smb2_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_fs_info(ssp, mdp,
+ FileFsFullSizeInformation, scrp);
+ if (error)
+ goto out;
+
+ md_get_uint64le(mdp, &info->total_units);
+ md_get_uint64le(mdp, &info->caller_avail);
+ md_get_uint64le(mdp, &info->actual_avail);
+
+ md_get_uint32le(mdp, &info->sect_per_unit);
+ error = md_get_uint32le(mdp, &info->bytes_per_sect);
+
+out:
+ md_done(mdp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp)
+{
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_FLUSH, scrp, &rqp);
+ if (error)
+ return (error);
+
+ /*
+ * Build the SMB 2 Flush Request
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 24); /* struct size */
+ mb_put_uint16le(mbp, 0); /* reserved */
+ mb_put_uint32le(mbp, 0); /* reserved */
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ rqp->sr_flags |= SMBR_NORECONNECT;
+ error = smb2_rq_simple(rqp);
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+/*
+ * Set file info via an open handle.
+ * Caller provides payload, info level.
+ */
+static int
+smbfs_smb2_set_info(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *info_mbp, uint8_t type, uint8_t level,
+ uint32_t addl_info, struct smb_cred *scrp)
+{
+ struct smb_rq *rqp = NULL;
+ struct mbchain *mbp;
+ uint32_t *buffer_lenp;
+ int base, len;
+ int error;
+
+ error = smb_rq_alloc(SSTOCP(ssp), SMB2_SET_INFO, scrp, &rqp);
+ if (error)
+ goto out;
+
+ /*
+ * Build the SMB 2 Set Info req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+ mb_put_uint16le(mbp, 33); // struct size
+ mb_put_uint8(mbp, type);
+ mb_put_uint8(mbp, level);
+ buffer_lenp = mb_reserve(mbp, sizeof (uint32_t));
+ mb_put_uint16le(mbp, SMB2_HDRLEN + 32); // Buffer Offset
+ mb_put_uint16le(mbp, 0); // Reserved
+ mb_put_uint32le(mbp, addl_info); // Additional Info
+
+ mb_put_uint64le(mbp, fid->fid_persistent);
+ mb_put_uint64le(mbp, fid->fid_volatile);
+
+ /*
+ * Now the payload
+ */
+ base = mbp->mb_count;
+ error = mb_put_mbchain(mbp, info_mbp);
+ if (error)
+ goto out;
+ len = mbp->mb_count - base;
+ *buffer_lenp = htolel(len);
+ if (error)
+ goto out;
+
+ /*
+ * Run the request.
+ * Don't care about the (empty) reply.
+ */
+ error = smb2_rq_simple(rqp);
+
+out:
+ smb_rq_done(rqp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid,
+ uint64_t newsize, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint8_t level = FileEndOfFileInformation;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint64le(mbp, newsize);
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ mb_done(mbp);
+
+ return (error);
+}
+
+int
+smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid,
+ uint8_t newdisp, struct smb_cred *scrp)
+{
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint8_t level = FileDispositionInformation;
+ int error;
+
+ mb_init(mbp);
+ mb_put_uint8(mbp, newdisp);
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Set FileBasicInformation on an open handle
+ * Caller builds the mbchain.
+ */
+int
+smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *mbp, struct smb_cred *scrp)
+{
+ uint8_t level = FileBasicInformation;
+ int error;
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+ return (error);
+}
+
+/*
+ * Build a FileRenameInformation and call setinfo
+ */
+int
+smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
+ const char *tname, int tnlen, int overwrite,
+ smb2fid_t *fid, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ struct mbchain data_mb, *mbp = &data_mb;
+ uint32_t *name_lenp;
+ uint8_t level = FileRenameInformation;
+ int base, len;
+ int error;
+
+ mb_init(mbp);
+
+ mb_put_uint32le(mbp, (overwrite & 1));
+ mb_put_uint32le(mbp, 0); // reserved
+ mb_put_uint64le(mbp, 0); // Root Dir
+ name_lenp = mb_reserve(mbp, 4);
+
+ /* Target name (full path) */
+ base = mbp->mb_count;
+ if (tnlen > 0) {
+ error = smbfs_fullpath(mbp, SSTOVC(ssp),
+ tdnp, tname, tnlen, '\\');
+ if (error)
+ goto out;
+ }
+ len = mbp->mb_count - base;
+ *name_lenp = htolel(len);
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_FILE, level, 0, scrp);
+
+out:
+ mb_done(mbp);
+
+ return (error);
+}
+
+/*
+ * Later servers have maxtransact at a megabyte or more,
+ * but we don't want to buffer up that much data, so use
+ * the lesser of that or 64k.
+ */
+#define SMBFS_QDIR_MAX_BUF (1<<16)
+
+/*
+ * SMB2 query directory
+ */
+static int
+smbfs_smb2_qdir(struct smbfs_fctx *ctx)
+{
+ smb_fh_t *fhp = ctx->f_fhp;
+ smb_share_t *ssp = ctx->f_ssp;
+ smb_vc_t *vcp = SSTOVC(ssp);
+ struct smb_rq *rqp;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ uint16_t *name_lenp;
+ uint8_t level, flags;
+ uint16_t ssize = 0;
+ uint16_t obuf_off = 0;
+ uint32_t obuf_len = 0;
+ uint32_t obuf_req;
+ int error;
+
+ level = (uint8_t)ctx->f_infolevel;
+ flags = 0;
+ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE)
+ flags |= SMB2_QDIR_FLAG_SINGLE;
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST)
+ ctx->f_rkey = 0;
+ else
+ flags |= SMB2_QDIR_FLAG_INDEX;
+
+ obuf_req = SMBFS_QDIR_MAX_BUF;
+ if (obuf_req > vcp->vc_sopt.sv2_maxtransact)
+ obuf_req = vcp->vc_sopt.sv2_maxtransact;
+
+ if (ctx->f_rq) {
+ smb_rq_done(ctx->f_rq);
+ ctx->f_rq = NULL;
+ }
+ error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB2_QUERY_DIRECTORY,
+ ctx->f_scred, &rqp);
+ if (error)
+ return (error);
+ ctx->f_rq = rqp;
+
+ /*
+ * Build an SMB2 Query Dir req.
+ */
+ smb_rq_getrequest(rqp, &mbp);
+
+ mb_put_uint16le(mbp, 33); /* Struct size */
+ mb_put_uint8(mbp, level);
+ mb_put_uint8(mbp, flags);
+ mb_put_uint32le(mbp, ctx->f_rkey); /* FileIndex */
+
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
+ mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
+
+ mb_put_uint16le(mbp, 96);
+ name_lenp = mb_reserve(mbp, sizeof (uint16_t)); /* FileNameLen */
+ mb_put_uint32le(mbp, obuf_req); /* Output Buf Len */
+
+ /* Add in the name if any */
+ if (ctx->f_wclen > 0) {
+ int base, len;
+
+ /* Put the match pattern. */
+ base = mbp->mb_count;
+ error = smb_put_dmem(mbp, vcp,
+ ctx->f_wildcard, ctx->f_wclen,
+ SMB_CS_NONE, NULL);
+ if (error)
+ return (error);
+
+ /* Update the FileNameLen */
+ len = mbp->mb_count - base;
+ *name_lenp = htoles(len);
+ } else {
+ /* Empty string */
+ mb_put_uint16le(mbp, 0);
+ *name_lenp = 0;
+ }
+
+ error = smb2_rq_simple(rqp);
+ if (error != 0)
+ goto out;
+
+ /*
+ * Parse the SMB2 Query Dir response
+ */
+ smb_rq_getreply(rqp, &mdp);
+
+ /* Check structure size is 9 */
+ md_get_uint16le(mdp, &ssize);
+ if (ssize != 9) {
+ error = EBADRPC;
+ goto out;
+ }
+
+ /* Get output buffer offset, length */
+ md_get_uint16le(mdp, &obuf_off);
+ md_get_uint32le(mdp, &obuf_len);
+
+ /*
+ * After read at EOF we'll have just one word:
+ * NextEntryOffset == 0 Allow some padding.
+ */
+ if (obuf_len < 8) {
+ error = ENOENT;
+ goto out;
+ }
+
+ /*
+ * If this reply is shorter than requested by 1k
+ * or more, we must have reached EOF.
+ */
+ if ((obuf_len + 1024) < obuf_req)
+ ctx->f_flags |= SMBFS_RDD_EOF;
+
+ /*
+ * Have data. Put the payload in ctx->f_mdchain
+ * Current offset is SMB2_HDRLEN + 8.
+ */
+ {
+ mblk_t *m = NULL;
+ int skip = (int)obuf_off - (SMB2_HDRLEN + 8);
+ if (skip < 0) {
+ error = EBADRPC;
+ goto out;
+ }
+ if (skip > 0) {
+ md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
+ }
+ error = md_get_mbuf(mdp, obuf_len, &m);
+ if (error)
+ goto out;
+ md_done(&ctx->f_mdchain);
+ md_initm(&ctx->f_mdchain, m);
+ }
+
+ /*
+ * SMB2 Query Directory does not provie an EntryCount.
+ * Instead, we'll advance f_eofs (entry offset)
+ * through the range [0..f_left]
+ */
+ ctx->f_left = obuf_len;
+ ctx->f_eofs = 0;
+ return (0);
+
+out:
+ if (error != 0) {
+ /*
+ * Failed parsing the FindFirst or FindNext response.
+ * Force this directory listing closed, otherwise the
+ * calling process may hang in an infinite loop.
+ */
+ ctx->f_left = 0;
+ ctx->f_eofs = 0;
+ ctx->f_flags |= SMBFS_RDD_EOF;
+ }
+
+ return (error);
+}
+
+int
+smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr)
+{
+ smb_fh_t *fhp = NULL;
+ uint32_t rights =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES |
+ SA_RIGHT_FILE_READ_DATA;
+ int error;
+
+ /*
+ * Set f_type no matter what, so cleanup will call
+ * smbfs_smb2_findclose, error or not.
+ */
+ ctx->f_type = ft_SMB2;
+ ASSERT(ctx->f_dnp == dnp);
+
+ /*
+ * Get a file handle on the directory
+ */
+ error = smb_fh_create(ctx->f_ssp, &fhp);
+ if (error != 0)
+ goto errout;
+
+ error = smbfs_smb_ntcreatex(dnp,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ ctx->f_scred, fhp,
+ NULL, NULL); /* cr_act_p fa_p */
+ if (error != 0)
+ goto errout;
+
+ fhp->fh_rights = rights;
+ smb_fh_opened(fhp);
+ ctx->f_fhp = fhp;
+
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = FileFullDirectoryInformation;
+ ctx->f_attrmask = attr;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
+
+ return (0);
+
+errout:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+ return (error);
+}
+
+int
+smbfs_smb2_findclose(struct smbfs_fctx *ctx)
+{
+ smb_fh_t *fhp = NULL;
+
+ if ((fhp = ctx->f_fhp) != NULL) {
+ ctx->f_fhp = NULL;
+ smb_fh_rele(fhp);
+ }
+ if (ctx->f_name)
+ kmem_free(ctx->f_name, ctx->f_namesz);
+ if (ctx->f_rq)
+ smb_rq_done(ctx->f_rq);
+ md_done(&ctx->f_mdchain);
+
+ return (0);
+}
+
+/*
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
+ */
+int
+smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
+
+ /*
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
+ */
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_smb2_qdir(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
+
+ /*
+ * Decode one entry
+ */
+ error = smbfs_decode_dirent(ctx);
+
+ return (error);
+}
+
+
+/*
+ * Helper for smbfs_xa_get_streaminfo
+ * Query stream info
+ */
+int
+smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp)
+{
+ smb_share_t *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp = NULL;
+ uint32_t rights =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_READ_ATTRIBUTES;
+ uint32_t iolen = INT16_MAX;
+ int error;
+
+ /*
+ * Get a file handle on the object
+ * with read attr. rights.
+ */
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+ error = smbfs_smb_ntcreatex(np,
+ NULL, 0, 0, /* name nmlen xattr */
+ rights, SMB_EFA_NORMAL,
+ NTCREATEX_SHARE_ACCESS_ALL,
+ NTCREATEX_DISP_OPEN,
+ 0, /* create options */
+ scrp, fhp, NULL, NULL);
+ if (error != 0)
+ goto out;
+
+ smb_fh_opened(fhp);
+
+ /*
+ * Query stream info
+ */
+ error = smbfs_smb2_query_info(ssp, &fhp->fh_fid2, mdp, &iolen,
+ SMB2_0_INFO_FILE, FileStreamInformation, 0, scrp);
+
+out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Get a security descriptor (SD).
+ *
+ * The *reslen param is bufsize(in) / length(out)
+ * Note: On success, this fills in mdp->md_top,
+ * which the caller should free.
+ */
+int
+smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp)
+{
+ struct mdchain info_mdc, *mdp = &info_mdc;
+ int error;
+
+ bzero(mdp, sizeof (*mdp));
+
+ error = smbfs_smb2_query_info(ssp, fid, mdp, reslen,
+ SMB2_0_INFO_SECURITY, 0, selector, scrp);
+ if (error)
+ goto out;
+
+ if (mdp->md_top == NULL) {
+ error = EBADRPC;
+ goto out;
+ }
+ *res = mdp->md_top;
+ mdp->md_top = NULL;
+
+out:
+ md_done(mdp);
+ return (error);
+}
+
+
+/*
+ * OTW function to Set a security descriptor (SD).
+ * Caller data are carried in an mbchain_t.
+ *
+ * Note: This normally consumes mbp->mb_top, and clears
+ * that pointer when it does.
+ */
+int
+smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
+{
+ struct mbchain info_mbp, *mbp = &info_mbp;
+ int error;
+
+ ASSERT(*mp != NULL);
+ mb_initm(mbp, *mp);
+ *mp = NULL; /* consumed */
+
+ error = smbfs_smb2_set_info(ssp, fid, mbp,
+ SMB2_0_INFO_SECURITY, 0, selector, scrp);
+
+ mb_done(mbp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
index 71d49c49b4..0b5eb411f1 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -47,6 +48,7 @@
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -73,10 +75,11 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
int error;
- if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
- caseopt |= SMB_CS_UPPER;
-
- if (unicode) {
+ /*
+ * SMB1 may need an alignment pad before (not SMB2)
+ */
+ if (((vcp)->vc_flags & SMBV_SMB2) == 0 &&
+ ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) {
error = mb_put_padbyte(mbp);
if (error)
return (error);
@@ -122,11 +125,14 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
if (error)
return (error);
}
- /* Put NULL termination. */
- if (unicode)
- error = mb_put_uint16le(mbp, 0);
- else
- error = mb_put_uint8(mbp, 0);
+
+ /* SMB1 wants NULL termination. */
+ if (((vcp)->vc_flags & SMBV_SMB2) == 0) {
+ if (unicode)
+ error = mb_put_uint16le(mbp, 0);
+ else
+ error = mb_put_uint8(mbp, 0);
+ }
return (error);
}
@@ -183,3 +189,271 @@ errout:
*/
(void) strlcpy(ctx->f_name, "?", ctx->f_namesz);
}
+
+/*
+ * Decode a directory entry from OtW form into ctx->f_attr
+ *
+ * Caller already put some (wire-format) directory entries
+ * into ctx->f_mdchain and we expect to find one.
+ *
+ * Advancing correctly through the buffer can be tricky if one
+ * tries to add up the size of an entry as you go (which is how
+ * the darwin code this is derived from did it). The easiest way
+ * to correctly advance the position is to get a whole dirent
+ * into another mdchain (entry_mdc) based on NextEntryOffset,
+ * and then scan the data from that mdchain. On the last entry,
+ * we don't know the entire length, so just scan directly from
+ * what remains of the multi-entry buffer instead of trying to
+ * figure out the length to copy into a separate mdchain.
+ */
+int
+smbfs_decode_dirent(struct smbfs_fctx *ctx)
+{
+ struct mdchain entry_mdc;
+ struct mdchain *mdp = &ctx->f_mdchain;
+ size_t nmlen;
+ uint64_t llongint;
+ uint32_t nmsize, dattr;
+ uint32_t nextoff = 0;
+ int error;
+
+ /* In case we error out... */
+ ctx->f_nmlen = 0;
+ ctx->f_rkey = (uint32_t)-1;
+ bzero(&entry_mdc, sizeof (entry_mdc));
+
+ /*
+ * Setup mdp to point to an mbchain holding
+ * what should be a single directory entry.
+ */
+ error = md_get_uint32le(mdp, &nextoff);
+ if (error != 0)
+ goto errout;
+ if (nextoff >= 4) {
+ /*
+ * More entries follow. Make a new mbchain
+ * holding just this one entry, then advance.
+ */
+ mblk_t *m = NULL;
+ error = md_get_mbuf(mdp, nextoff - 4, &m);
+ if (error != 0)
+ goto errout;
+ md_initm(&entry_mdc, m);
+ mdp = &entry_mdc;
+ ctx->f_eofs += nextoff;
+ } else {
+ /* Scan directly from ctx->f_mdchain */
+ ctx->f_eofs = ctx->f_left;
+ }
+
+ /*
+ * Decode the fixed-size parts
+ */
+ switch (ctx->f_infolevel) {
+ case FileFullDirectoryInformation:
+ case SMB_FIND_FULL_DIRECTORY_INFO:
+ md_get_uint32le(mdp, &ctx->f_rkey); /* resume key (idx) */
+ md_get_uint64le(mdp, &llongint); /* creation time */
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
+ md_get_uint64le(mdp, &llongint); /* file size */
+ ctx->f_attr.fa_size = llongint;
+ md_get_uint64le(mdp, &llongint); /* alloc. size */
+ ctx->f_attr.fa_allocsz = llongint;
+ md_get_uint32le(mdp, &dattr); /* ext. file attributes */
+ ctx->f_attr.fa_attr = dattr;
+ error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */
+ if (error)
+ goto errout;
+ md_get_uint32le(mdp, NULL); /* Ea size */
+ break;
+
+ case FileStreamInformation:
+ error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */
+ md_get_uint64le(mdp, &llongint); /* file size */
+ ctx->f_attr.fa_size = llongint;
+ md_get_uint64le(mdp, &llongint); /* alloc. size */
+ ctx->f_attr.fa_allocsz = llongint;
+ /*
+ * Stream names start with a ':' that we want to skip.
+ * This is the easiest place to take care of that.
+ * Always unicode here.
+ */
+ if (nmsize >= 2) {
+ struct mdchain save_mdc;
+ uint16_t wch;
+ save_mdc = *mdp;
+ md_get_uint16le(mdp, &wch);
+ if (wch == ':') {
+ /* OK, we skipped the ':' */
+ nmsize -= 2;
+ } else {
+ SMBVDEBUG("No leading : in stream?\n");
+ /* restore position */
+ *mdp = save_mdc;
+ }
+ }
+ break;
+
+ default:
+ SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
+ error = EINVAL;
+ goto errout;
+ }
+
+ /*
+ * Get the filename, and convert to utf-8
+ * Allocated f_name in findopen
+ */
+ nmlen = ctx->f_namesz;
+ error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp),
+ ctx->f_name, &nmlen, nmsize);
+ if (error != 0)
+ goto errout;
+ ctx->f_nmlen = (int)nmlen;
+ md_done(&entry_mdc);
+ return (0);
+
+errout:
+ /*
+ * Something bad has happened and we ran out of data
+ * before we could parse all f_ecnt entries expected.
+ * Give up on the current buffer.
+ */
+ SMBVDEBUG("ran out of data\n");
+ ctx->f_eofs = ctx->f_left;
+ md_done(&entry_mdc);
+ return (error);
+}
+
+/*
+ * Decode FileAllInformation
+ *
+ * The data is a concatenation of:
+ * FileBasicInformation
+ * FileStandardInformation
+ * FileInternalInformation
+ * FileEaInformation
+ * FilePositionInformation
+ * FileModeInformation
+ * FileAlignmentInformation
+ * FileNameInformation
+ */
+/*ARGSUSED*/
+int
+smbfs_decode_file_all_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smbfattr *fap)
+{
+ uint64_t llongint, lsize;
+ uint32_t dattr;
+ int error;
+
+ /*
+ * This part is: FileBasicInformation
+ */
+
+ /* creation time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_createtime);
+
+ /* last access time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_atime);
+
+ /* last write time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_mtime);
+
+ /* last change time */
+ md_get_uint64le(mdp, &llongint);
+ smb_time_NT2local(llongint, &fap->fa_ctime);
+
+ /* attributes */
+ md_get_uint32le(mdp, &dattr);
+ fap->fa_attr = dattr;
+
+ /* reserved */
+ md_get_uint32le(mdp, NULL);
+
+ /*
+ * This part is: FileStandardInformation
+ */
+
+ /* allocation size */
+ md_get_uint64le(mdp, &lsize);
+ fap->fa_allocsz = lsize;
+
+ /* File size */
+ error = md_get_uint64le(mdp, &lsize);
+ fap->fa_size = lsize;
+
+ /*
+ * There's more after this but we don't need it:
+ * Remainder of FileStandardInformation
+ * NumLlinks, DeletOnClose, IsDir, reserved.
+ * Then:
+ * FileInternalInformation
+ * FileEaInformation
+ * FilePositionInformation
+ * FileModeInformation
+ * FileAlignmentInformation
+ * FileNameInformation
+ */
+
+ return (error);
+}
+
+/*
+ * Decode FileFsAttributeInformation
+ *
+ * ULONG FileSystemAttributes;
+ * LONG MaximumComponentNameLength;
+ * ULONG FileSystemNameLength;
+ * WCHAR FileSystemName[1];
+ */
+int
+smbfs_decode_fs_attr_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smb_fs_attr_info *fsa)
+{
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint32_t nlen;
+ int error;
+
+ md_get_uint32le(mdp, &fsa->fsa_aflags);
+ md_get_uint32le(mdp, &fsa->fsa_maxname);
+ error = md_get_uint32le(mdp, &nlen); /* fs name length */
+ if (error)
+ goto out;
+
+ /*
+ * Get the FS type name.
+ */
+ bzero(fsa->fsa_tname, FSTYPSZ);
+ if (SMB_UNICODE_STRINGS(vcp)) {
+ uint16_t tmpbuf[FSTYPSZ];
+ size_t tmplen, outlen;
+
+ if (nlen > sizeof (tmpbuf))
+ nlen = sizeof (tmpbuf);
+ error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
+ if (error != 0)
+ goto out;
+ tmplen = nlen / 2; /* UCS-2 chars */
+ outlen = FSTYPSZ - 1;
+ error = uconv_u16tou8(tmpbuf, &tmplen,
+ (uchar_t *)fsa->fsa_tname, &outlen,
+ UCONV_IN_LITTLE_ENDIAN);
+ } else {
+ if (nlen > (FSTYPSZ - 1))
+ nlen = FSTYPSZ - 1;
+ error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
+ }
+
+out:
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
index fc7a4ffa26..f8d708b5a3 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _FS_SMBFS_SMBFS_SUBR_H_
@@ -85,6 +86,7 @@ struct timespec;
typedef enum {
ft_LM1 = 1,
ft_LM2,
+ ft_SMB2,
ft_XA
} smbfs_fctx_type_t;
@@ -120,31 +122,33 @@ struct smbfs_fctx {
/*
* Internal variables
*/
+ uint16_t f_infolevel;
uint16_t f_limit; /* maximum number of entries */
- uint16_t f_attrmask; /* SMB_FA_ */
+ uint32_t f_attrmask; /* SMB_FA_ */
int f_wclen;
const char *f_wildcard;
struct smbnode *f_dnp;
struct smb_cred *f_scred;
struct smb_share *f_ssp;
+ struct smb_fh *f_fhp;
union {
struct smb_rq *uf_rq;
struct smb_t2rq *uf_t2;
- } f_urq;
+ } f_urq; // XXX remove and use...
+ struct mdchain f_mdchain;
int f_left; /* entries left */
int f_ecnt; /* entries left in current response */
int f_eofs; /* entry offset in data block */
uchar_t f_skey[SMB_SKEYLEN]; /* server side search context */
uchar_t f_fname[8 + 1 + 3 + 1]; /* for 8.3 filenames */
uint16_t f_Sid; /* Search handle (like a FID) */
- uint16_t f_infolevel;
int f_rnamelen;
char *f_rname; /* resume name */
int f_rnameofs;
int f_otws; /* # over-the-wire ops so far */
char *f_firstnm; /* first filename we got back */
int f_firstnmlen;
- int f_rkey; /* resume key */
+ uint32_t f_rkey; /* resume key */
};
typedef struct smbfs_fctx smbfs_fctx_t;
@@ -152,73 +156,163 @@ typedef struct smbfs_fctx smbfs_fctx_t;
#define f_t2 f_urq.uf_t2
/*
- * smb level (smbfs_smb.c)
+ * Internal form of FileFsFullSizeInformation
+ * [MS-FSCC] 2.5.4 FileFsFullSizeInformation
+ * for the _statfs functions.
+ */
+struct smb_fs_size_info {
+ uint64_t total_units;
+ uint64_t caller_avail;
+ uint64_t actual_avail;
+ uint32_t sect_per_unit;
+ uint32_t bytes_per_sect;
+};
+
+/*
+ * smb common functions (smbfs_smbx.c)
*/
int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
offset_t start, uint64_t len, int largelock,
struct smb_cred *scrp, uint32_t timeout);
+int smbfs_smb_getfattr(struct smbnode *np, smb_fh_t *fhp,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb_getpattr(struct smbnode *np, struct smbfattr *fap,
+ struct smb_cred *scrp);
int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
struct smb_cred *scrp);
int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scrp);
-
-int smbfs_smb_setdisp(struct smbnode *np, uint16_t fid, uint8_t newdisp,
- struct smb_cred *scrp);
-int smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
+int smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fid, uint8_t newdisp,
struct smb_cred *scrp);
-
-int smbfs_smb_getfattr(struct smbnode *np, struct smbfattr *fap,
+int smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fid, uint64_t newsize,
struct smb_cred *scrp);
-
-int smbfs_smb_setfattr(struct smbnode *np, int fid,
+int smbfs_smb_setfattr(struct smb_share *ssp, smb_fh_t *fid,
uint32_t attr, struct timespec *mtime, struct timespec *atime,
struct smb_cred *scrp);
+int smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fid,
+ struct smb_cred *scrp);
+
+int smbfs_smb_ntcreatex(
+ struct smbnode *np, const char *name, int nmlen, int xattr,
+ uint32_t req_acc, uint32_t efa, uint32_t share_acc,
+ uint32_t disp, uint32_t createopt, struct smb_cred *scrp,
+ smb_fh_t *fhpp, uint32_t *cr_act_p, struct smbfattr *fap);
+int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights,
+ struct smb_cred *scrp, smb_fh_t **fidpp);
+void smbfs_smb_tmpclose(struct smbnode *ssp, smb_fh_t *fid);
int smbfs_smb_open(struct smbnode *np, const char *name, int nmlen,
int xattr, uint32_t rights, struct smb_cred *scrp,
- uint16_t *fidp, uint32_t *rightsp, struct smbfattr *fap);
-int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights,
- struct smb_cred *scrp, uint16_t *fidp);
-int smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
- struct timespec *mtime, struct smb_cred *scrp);
-int smbfs_smb_tmpclose(struct smbnode *ssp, uint16_t fid,
- struct smb_cred *scrp);
+ smb_fh_t **fidpp, struct smbfattr *fap);
+void smbfs_smb_close(smb_fh_t *fid);
int smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
- int xattr, uint32_t disp, struct smb_cred *scrp, uint16_t *fidp);
-int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp,
- const char *name, int len, int xattr);
-int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, struct smb_cred *scrp);
-int smbfs_smb_t2rename(struct smbnode *np, const char *tname, int tnmlen,
- struct smb_cred *scrp, uint16_t fid, int replace);
-int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp);
+ int xattr, uint32_t disp, struct smb_cred *scrp, smb_fh_t **fidpp);
+int smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *src,
+ struct smbnode *tdnp, const char *tname, int tnmlen,
+ smb_fh_t *fid, struct smb_cred *scrp);
int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
struct smb_cred *scrp);
-int smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp);
+
int smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp);
int smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit,
struct smb_cred *scrp);
int smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp);
-int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
- struct smbnode *dnp, const char *name, int nmlen, uint8_t sep);
+
int smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
struct smbfattr *fap, struct smb_cred *scrp);
-int smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp);
-int smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp);
-int smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp);
-int smbfs_0extend(vnode_t *vp, uint16_t fid, len_t from, len_t to,
- struct smb_cred *scredp, int timo);
/* get/set security descriptor */
-int smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector,
- mblk_t **res, uint32_t *reslen);
-int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
- struct smb_cred *scrp, uint32_t selector, mblk_t **mp);
+int smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fid,
+ uint32_t selector, mblk_t **mp, struct smb_cred *scrp);
+
+/*
+ * SMB1 functions
+ */
+int smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
+ struct smb_cred *scrp);
+int smbfs_smb1_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info, struct smb_cred *scrp);
+int smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
+ struct smb_cred *scrp);
+int smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid, uint8_t newdisp,
+ struct smb_cred *scrp);
+int smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
+ struct mbchain *, struct smb_cred *);
+int smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid,
+ struct smb_cred *scrp);
+int smbfs_smb1_t2rename(struct smbnode *np, const char *tname, int tnmlen,
+ uint16_t fid, struct smb_cred *scrp);
+int smbfs_smb1_oldrename(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, struct smb_cred *scrp);
+
+int smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr);
+int smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit);
+int smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx);
+int smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp);
+
+int smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp);
+
+/*
+ * SMB2 functions
+ */
+
+int smbfs_smb2_getpattr(struct smbnode *np, struct smbfattr *fap,
+ struct smb_cred *scrp);
+int smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
+ struct smbfattr *fap, struct smb_cred *scrp);
+int smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
+ struct smb_cred *scrp);
+int smbfs_smb2_statfs(struct smb_share *ssp,
+ struct smb_fs_size_info *info, struct smb_cred *scrp);
+int smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid, uint64_t newsize,
+ struct smb_cred *scrp);
+int smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid, uint8_t newdisp,
+ struct smb_cred *scrp);
+int smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
+ struct smb_cred *scrp);
+int smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
+ struct mbchain *, struct smb_cred *);
+int smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
+ const char *tname, int tnlen, int overwrite,
+ smb2fid_t *fid, struct smb_cred *scrp);
+
+int smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, uint32_t attr);
+int smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit);
+int smbfs_smb2_findclose(struct smbfs_fctx *ctx);
+int smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
+ struct smb_cred *scrp);
+
+int smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **res, uint32_t *reslen,
+ struct smb_cred *scrp);
+int smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
+ uint32_t selector, mblk_t **mp,
+ struct smb_cred *scrp);
+
+
+/* smbfs_subr.c */
+
+int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
+ struct smbnode *dnp, const char *name, int nmlen, uint8_t sep);
+int smbfs_decode_dirent(struct smbfs_fctx *ctx);
+int smbfs_decode_file_all_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smbfattr *fap);
+int smbfs_decode_fs_attr_info(struct smb_share *ssp,
+ struct mdchain *mdp, struct smb_fs_attr_info *fsa);
/*
* VFS-level init, fini stuff
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
index 798c26a09b..768664b610 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c
@@ -27,6 +27,7 @@
*/
/*
* Copyright (c) 2017 by Delphix. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -39,7 +40,9 @@
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/vnode.h>
+#include <sys/atomic.h>
#include <sys/bitmap.h>
+#include <sys/buf.h>
#include <sys/dnlc.h>
#include <sys/kmem.h>
#include <sys/sunddi.h>
@@ -430,7 +433,7 @@ start:
np->r_vnode = vp;
np->n_mount = mi;
- np->n_fid = SMB_FID_UNUSED;
+ np->n_fid = NULL;
np->n_uid = mi->smi_uid;
np->n_gid = mi->smi_gid;
/* Leave attributes "stale." */
@@ -1231,7 +1234,7 @@ smbfs_subrinit(void)
nsmbnode_max = (ulong_t)((kmem_maxavail() >> 2) /
sizeof (struct smbnode));
if (nsmbnode > nsmbnode_max || (nsmbnode == 0 && ncsize == 0)) {
- zcmn_err(GLOBAL_ZONEID, CE_NOTE,
+ cmn_err(CE_NOTE,
"setting nsmbnode to max value of %ld", nsmbnode_max);
nsmbnode = nsmbnode_max;
}
@@ -1249,7 +1252,7 @@ smbfs_subrinit(void)
* Assign unique major number for all smbfs mounts
*/
if ((smbfs_major = getudev()) == -1) {
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfs: init: can't get unique device number");
smbfs_major = 0;
}
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
index 0122d52115..7dad8d2a70 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
@@ -34,9 +34,9 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/systm.h>
@@ -76,6 +76,17 @@
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
+#ifndef _KERNEL
+
+#include <libfksmbfs.h>
+
+#define STRUCT_DECL(s, a) struct s a
+#define STRUCT_FGET(handle, field) ((handle).field)
+#define _init(v) fksmbfs_init(v)
+#define _fini(v) fksmbfs_fini(v)
+
+#endif /* !_KERNEL */
+
/*
* Should smbfs mount enable "-o acl" by default? There are good
* arguments for both. The most common use case is individual users
@@ -98,7 +109,10 @@ int smbfs_tq_nthread = 1;
*/
int smbfsinit(int fstyp, char *name);
void smbfsfini();
+
+#ifdef _KERNEL
static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *);
+#endif /* _KERNEL */
/*
* SMBFS Mount options table for MS_OPTIONSTR
@@ -123,7 +137,11 @@ static mntopt_t mntopts[] = {
{ MNTOPT_ACL, acl_cancel, NULL, 0, 0 },
{ MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 },
{ MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 },
- { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 }
+ { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 },
+#ifndef _KERNEL
+ /* See vfs_optionisset MNTOPT_NOAC below. */
+ { MNTOPT_NOAC, NULL, NULL, 0, 0 },
+#endif /* !_KERNEL */
};
static mntopts_t smbfs_mntopts = {
@@ -141,6 +159,7 @@ static vfsdef_t vfw = {
&smbfs_mntopts /* mount options table prototype */
};
+#ifdef _KERNEL
static struct modlfs modlfs = {
&mod_fsops,
"SMBFS filesystem",
@@ -150,6 +169,7 @@ static struct modlfs modlfs = {
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlfs, NULL
};
+#endif /* _KERNEL */
/*
* Mutex to protect the following variables:
@@ -222,7 +242,12 @@ _init(void)
return (error);
}
+#ifdef _KERNEL
error = mod_install((struct modlinkage *)&modlinkage);
+#else /* _KERNEL */
+ error = fake_installfs(&vfw);
+#endif /* _KERNEL */
+
return (error);
}
@@ -244,7 +269,11 @@ _fini(void)
if (smbfs_mountcount)
return (EBUSY);
+#ifdef _KERNEL
error = mod_remove(&modlinkage);
+#else /* _KERNEL */
+ error = fake_removefs(&vfw);
+#endif /* _KERNEL */
if (error)
return (error);
@@ -267,17 +296,19 @@ _fini(void)
/*
* Return information about the module
*/
+#ifdef _KERNEL
int
_info(struct modinfo *modinfop)
{
return (mod_info((struct modlinkage *)&modlinkage, modinfop));
}
+#endif /* _KERNEL */
/*
* Initialize the vfs structure
*/
-int smbfsfstyp;
+int smbfs_fstyp;
vfsops_t *smbfs_vfsops = NULL;
static const fs_operation_def_t smbfs_vfsops_template[] = {
@@ -292,6 +323,10 @@ static const fs_operation_def_t smbfs_vfsops_template[] = {
{ NULL, NULL }
};
+/*
+ * This is the VFS switch initialization routine, normally called
+ * via vfssw[x].vsw_init by vfsinit() or mod_install
+ */
int
smbfsinit(int fstyp, char *name)
{
@@ -299,7 +334,7 @@ smbfsinit(int fstyp, char *name)
error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops);
if (error != 0) {
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfsinit: bad vfs ops template");
return (error);
}
@@ -307,12 +342,12 @@ smbfsinit(int fstyp, char *name)
error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops);
if (error != 0) {
(void) vfs_freevfsops_by_type(fstyp);
- zcmn_err(GLOBAL_ZONEID, CE_WARN,
+ cmn_err(CE_WARN,
"smbfsinit: bad vnode ops template");
return (error);
}
- smbfsfstyp = fstyp;
+ smbfs_fstyp = fstyp;
return (0);
}
@@ -321,7 +356,7 @@ void
smbfsfini()
{
if (smbfs_vfsops) {
- (void) vfs_freevfsops_by_type(smbfsfstyp);
+ (void) vfs_freevfsops_by_type(smbfs_fstyp);
smbfs_vfsops = NULL;
}
if (smbfs_vnodeops) {
@@ -336,8 +371,10 @@ smbfs_free_smi(smbmntinfo_t *smi)
if (smi == NULL)
return;
+#ifdef _KERNEL
if (smi->smi_zone_ref.zref_zone != NULL)
zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS);
+#endif /* _KERNEL */
if (smi->smi_share != NULL)
smb_share_rele(smi->smi_share);
@@ -364,16 +401,21 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
dev_t smbfs_dev;
int version;
int devfd;
- zone_t *zone = curproc->p_zone;
+ zone_t *zone = curzone;
+#ifdef _KERNEL
zone_t *mntzone = NULL;
+#else /* _KERNEL */
+ short minclsyspri = MINCLSYSPRI;
+#endif /* _KERNEL */
smb_share_t *ssp = NULL;
smb_cred_t scred;
int flags, sec;
-
STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */
+#ifdef _KERNEL
if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
return (error);
+#endif /* _KERNEL */
if (mvp->v_type != VDIR)
return (ENOTDIR);
@@ -384,11 +426,17 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* uap->datalen might be different from sizeof (args)
* in a compatible situation.
*/
+#ifdef _KERNEL
STRUCT_INIT(args, get_udatamodel());
bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE));
if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen,
SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE))))
return (EFAULT);
+#else /* _KERNEL */
+ bzero(&args, sizeof (args));
+ if (copyin(data, &args, MIN(uap->datalen, sizeof (args))))
+ return (EFAULT);
+#endif /* _KERNEL */
/*
* Check mount program version
@@ -439,6 +487,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* See: ssp, smi, rtnp, mntzone
*/
+#ifdef _KERNEL
/*
* Determine the zone we're being mounted into.
*/
@@ -482,6 +531,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
}
}
+#endif /* _KERNEL */
/* Prevent unload. */
atomic_inc_32(&smbfs_mountcount);
@@ -504,6 +554,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
smi->smi_share = ssp;
ssp = NULL;
+#ifdef _KERNEL
/*
* Convert the anonymous zone hold acquired via zone_hold() above
* into a zone reference.
@@ -512,15 +563,22 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS);
zone_rele(mntzone);
mntzone = NULL;
+#else /* _KERNEL */
+ smi->smi_zone_ref.zref_zone = curzone;
+#endif /* _KERNEL */
/*
* Initialize option defaults
*/
- smi->smi_flags = SMI_LLOCK;
smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN);
smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX);
smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN);
smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX);
+ smi->smi_flags = SMI_LLOCK;
+#ifndef _KERNEL
+ /* Always direct IO with fakekernel */
+ smi->smi_flags |= SMI_DIRECTIO;
+#endif /* _KERNEL */
/*
* All "generic" mount options have already been
@@ -541,10 +599,30 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* starting with args.flags (SMBFS_MF_xxx)
*/
flags = STRUCT_FGET(args, flags);
- smi->smi_uid = STRUCT_FGET(args, uid);
- smi->smi_gid = STRUCT_FGET(args, gid);
smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777;
smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777;
+#ifdef _KERNEL
+ smi->smi_uid = STRUCT_FGET(args, uid);
+ smi->smi_gid = STRUCT_FGET(args, gid);
+#else /* _KERNEL */
+ /*
+ * Need uid/gid to match our fake cred we'll fail in
+ * smbfs_access_rwx later.
+ */
+ smi->smi_uid = crgetuid(cr);
+ smi->smi_gid = crgetgid(cr);
+
+ /*
+ * Our user-level do_mount() passes the mount options sting
+ * as-is, where the real mount program would convert some
+ * of those options to bits set in smbfs_args.flags.
+ * To avoid replicating all that conversion code, this
+ * uses the generic vfs option support to handle those
+ * option flag bits we need, i.e.: "noac"
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_NOAC, NULL))
+ flags |= SMBFS_MF_NOAC;
+#endif /* _KERNEL */
/*
* Hande the SMBFS_MF_xxx flags.
@@ -615,9 +693,9 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
mutex_exit(&smbfs_minor_lock);
vfsp->vfs_dev = smbfs_dev;
- vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp);
+ vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfs_fstyp);
vfsp->vfs_data = (caddr_t)smi;
- vfsp->vfs_fstype = smbfsfstyp;
+ vfsp->vfs_fstype = smbfs_fstyp;
vfsp->vfs_bsize = MAXBSIZE;
vfsp->vfs_bcount = 0;
@@ -657,6 +735,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
*/
return (0);
+#ifdef _KERNEL
errout:
vfsp->vfs_data = NULL;
if (smi != NULL)
@@ -669,6 +748,7 @@ errout:
smb_share_rele(ssp);
return (error);
+#endif /* _KERNEL */
}
/*
@@ -682,8 +762,10 @@ smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
smi = VFTOSMI(vfsp);
+#ifdef _KERNEL
if (secpolicy_fs_unmount(cr, vfsp) != 0)
return (EPERM);
+#endif /* _KERNEL */
if ((flag & MS_FORCE) == 0) {
smbfs_rflush(vfsp, cr);
@@ -976,6 +1058,7 @@ smbfs_freevfs(vfs_t *vfsp)
atomic_dec_32(&smbfs_mountcount);
}
+#ifdef _KERNEL
/*
* smbfs_mount_label_policy:
* Determine whether the mount is allowed according to MAC check,
@@ -1066,3 +1149,4 @@ out:
label_rele(zlabel);
return (retv);
}
+#endif /* _KERNEL */
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
index 23c9f8f15d..3fca806155 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
@@ -34,6 +34,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -60,8 +61,9 @@
#include <sys/sdt.h>
#include <sys/taskq_impl.h>
#include <sys/zone.h>
-#include <sys/vmsystm.h>
+#ifdef _KERNEL
+#include <sys/vmsystm.h> // for desfree
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/page.h>
@@ -70,6 +72,7 @@
#include <vm/seg_map.h>
#include <vm/seg_kpm.h>
#include <vm/seg_vn.h>
+#endif // _KERNEL
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
@@ -83,6 +86,10 @@
#include <sys/fs/smbfs_ioctl.h>
#include <fs/fs_subr.h>
+#ifndef MAXOFF32_T
+#define MAXOFF32_T 0x7fffffff
+#endif
+
/*
* We assign directory offsets like the NFS client, where the
* offset increments by _one_ after each directory entry.
@@ -137,18 +144,15 @@ static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
static int smbfs_accessx(void *, int, cred_t *);
static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
caller_context_t *);
+static int smbfsflush(smbnode_t *, struct smb_cred *);
static void smbfs_rele_fid(smbnode_t *, struct smb_cred *);
static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
-static int smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static int smbfs_bio(struct buf *, int, cred_t *);
-static int smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
- struct uio *uiop, int pgcreated);
-
static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+
static int smbfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
caller_context_t *);
+#ifdef _KERNEL
static int smbfs_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
enum seg_rw, cred_t *);
@@ -156,6 +160,13 @@ static int smbfs_putapage(vnode_t *, page_t *, u_offset_t *, size_t *,
int, cred_t *);
static void smbfs_delmap_async(void *);
+static int smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
+ cred_t *);
+static int smbfs_bio(struct buf *, int, cred_t *);
+static int smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
+ struct uio *uiop, int pgcreated);
+#endif // _KERNEL
+
/*
* Error flags used to pass information about certain special errors
* which need to be handled specially.
@@ -191,14 +202,13 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
smbnode_t *np;
vnode_t *vp;
smbfattr_t fa;
- u_int32_t rights, rightsrcvd;
- u_int16_t fid, oldfid;
- int oldgenid;
+ smb_fh_t *fid = NULL;
+ smb_fh_t *oldfid;
+ uint32_t rights;
struct smb_cred scred;
smbmntinfo_t *smi;
smb_share_t *ssp;
cred_t *oldcr;
- int tmperror;
int error = 0;
vp = *vpp;
@@ -270,14 +280,15 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
* check whether the rights are sufficient for FID reuse.
*/
if (np->n_fidrefs > 0 &&
- np->n_vcgenid == ssp->ss_vcgenid) {
+ (fid = np->n_fid) != NULL &&
+ fid->fh_vcgenid == ssp->ss_vcgenid) {
int upgrade = 0;
if ((flag & FWRITE) &&
- !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
+ !(fid->fh_rights & SA_RIGHT_FILE_WRITE_DATA))
upgrade = 1;
if ((flag & FREAD) &&
- !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
+ !(fid->fh_rights & SA_RIGHT_FILE_READ_DATA))
upgrade = 1;
if (!upgrade) {
/*
@@ -286,8 +297,9 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
np->n_fidrefs++;
goto have_fid;
}
+ fid = NULL;
}
- rights = np->n_fidrefs ? np->n_rights : 0;
+ rights = (fid != NULL) ? fid->fh_rights : 0;
/*
* we always ask for READ_CONTROL so we can always get the
@@ -306,7 +318,7 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
error = smbfs_smb_open(np,
NULL, 0, 0, /* name nmlen xattr */
rights, &scred,
- &fid, &rightsrcvd, &fa);
+ &fid, &fa);
if (error)
goto out;
smbfs_attrcache_fa(vp, &fa);
@@ -315,24 +327,10 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
* We have a new FID and access rights.
*/
oldfid = np->n_fid;
- oldgenid = np->n_vcgenid;
np->n_fid = fid;
- np->n_vcgenid = ssp->ss_vcgenid;
- np->n_rights = rightsrcvd;
np->n_fidrefs++;
- if (np->n_fidrefs > 1 &&
- oldgenid == ssp->ss_vcgenid) {
- /*
- * We already had it open (presumably because
- * it was open with insufficient rights.)
- * Close old wire-open.
- */
- tmperror = smbfs_smb_close(ssp,
- oldfid, NULL, &scred);
- if (tmperror)
- SMBVDEBUG("error %d closing %s\n",
- tmperror, np->n_rpath);
- }
+ if (oldfid != NULL)
+ smb_fh_rele(oldfid);
/*
* This thread did the open.
@@ -478,13 +476,11 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
static void
smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
{
- smb_share_t *ssp;
cred_t *oldcr;
struct smbfs_fctx *fctx;
int error;
- uint16_t ofid;
+ smb_fh_t *ofid;
- ssp = np->n_mount->smi_share;
error = 0;
/* Make sure we serialize for n_dirseq use. */
@@ -513,13 +509,9 @@ smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
ASSERT(np->n_fidrefs > 0);
if (--np->n_fidrefs)
return;
- if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
- np->n_fid = SMB_FID_UNUSED;
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid == ssp->ss_vcgenid) {
- error = smbfs_smb_close(
- ssp, ofid, NULL, scred);
- }
+ if ((ofid = np->n_fid) != NULL) {
+ np->n_fid = NULL;
+ smb_fh_rele(ofid);
}
break;
@@ -557,20 +549,12 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
struct vattr va;
smbnode_t *np;
smbmntinfo_t *smi;
- smb_share_t *ssp;
offset_t endoff;
ssize_t past_eof;
int error;
- caddr_t base;
- u_offset_t off;
- size_t n;
- int on;
- uint_t flags;
-
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -632,12 +616,8 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
return (EINTR);
smb_credinit(&scred, cr);
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_READ,
- uiop, &scred, smb_timo_read);
+ error = smb_rwuio(np->n_fid, UIO_READ,
+ uiop, &scred, smb_timo_read);
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -648,8 +628,15 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
return (error);
}
+#ifdef _KERNEL
/* (else) Do I/O through segmap. */
do {
+ caddr_t base;
+ u_offset_t off;
+ size_t n;
+ int on;
+ uint_t flags;
+
off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
n = MIN(MAXBSIZE - on, uiop->uio_resid);
@@ -698,6 +685,9 @@ smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
}
}
} while (!error && uiop->uio_resid > 0);
+#else // _KERNEL
+ error = ENOSYS;
+#endif // _KERNEL
/* undo adjustment of resid */
uiop->uio_resid += past_eof;
@@ -715,22 +705,17 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
struct vattr va;
smbnode_t *np;
smbmntinfo_t *smi;
- smb_share_t *ssp;
offset_t endoff, limit;
ssize_t past_limit;
int error, timo;
- caddr_t base;
- u_offset_t off;
- size_t n;
- int on;
- uint_t flags;
u_offset_t last_off;
size_t last_resid;
+#ifdef _KERNEL
uint_t bsize;
+#endif
np = VTOSMB(vp);
smi = VTOSMI(vp);
- ssp = smi->smi_share;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EIO);
@@ -789,12 +774,14 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
limit = MAXOFFSET_T;
if (uiop->uio_loffset >= limit) {
+#ifdef _KERNEL
proc_t *p = ttoproc(curthread);
mutex_enter(&p->p_lock);
(void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE],
p->p_rctls, p, RCA_UNSAFE_SIGINFO);
mutex_exit(&p->p_lock);
+#endif // _KERNEL
return (EFBIG);
}
if (endoff > limit) {
@@ -813,7 +800,9 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
np->r_mapcnt == 0 && np->r_inmap == 0 &&
!vn_has_cached_data(vp))) {
+#ifdef _KERNEL
smbfs_fwrite:
+#endif // _KERNEL
if (np->r_flags & RSTALE) {
last_resid = uiop->uio_resid;
last_off = uiop->uio_loffset;
@@ -837,12 +826,8 @@ smbfs_fwrite:
return (EINTR);
smb_credinit(&scred, cr);
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
- uiop, &scred, timo);
+ error = smb_rwuio(np->n_fid, UIO_WRITE,
+ uiop, &scred, timo);
if (error == 0) {
mutex_enter(&np->r_statelock);
@@ -852,7 +837,7 @@ smbfs_fwrite:
mutex_exit(&np->r_statelock);
if (ioflag & (FSYNC | FDSYNC)) {
/* Don't error the I/O if this fails. */
- (void) smbfs_smb_flush(np, &scred);
+ (void) smbfsflush(np, &scred);
}
}
@@ -865,10 +850,17 @@ smbfs_fwrite:
return (error);
}
+#ifdef _KERNEL
/* (else) Do I/O through segmap. */
bsize = vp->v_vfsp->vfs_bsize;
do {
+ caddr_t base;
+ u_offset_t off;
+ size_t n;
+ int on;
+ uint_t flags;
+
off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
n = MIN(MAXBSIZE - on, uiop->uio_resid);
@@ -993,6 +985,11 @@ smbfs_fwrite:
goto smbfs_fwrite;
}
} while (!error && uiop->uio_resid > 0);
+#else // _KERNEL
+ last_resid = uiop->uio_resid;
+ last_off = uiop->uio_loffset;
+ error = ENOSYS;
+#endif // _KERNEL
bottom:
/* undo adjustment of resid */
@@ -1006,6 +1003,8 @@ bottom:
return (error);
}
+#ifdef _KERNEL
+
/*
* Like nfs_client.c: writerp()
*
@@ -1245,7 +1244,6 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
struct smb_cred scred;
smbnode_t *np = VTOSMB(bp->b_vp);
smbmntinfo_t *smi = np->n_mount;
- smb_share_t *ssp = smi->smi_share;
offset_t offset;
offset_t endoff;
size_t count;
@@ -1301,12 +1299,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
if (bp->b_flags & B_READ) {
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_READ,
- &auio, &scred, smb_timo_read);
+ error = smb_rwuio(np->n_fid, UIO_READ,
+ &auio, &scred, smb_timo_read);
/* Like NFS, only set b_error here. */
bp->b_error = error;
@@ -1320,12 +1314,8 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
}
} else {
- /* After reconnect, n_fid is invalid */
- if (np->n_vcgenid != ssp->ss_vcgenid)
- error = ESTALE;
- else
- error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
- &auio, &scred, smb_timo_write);
+ error = smb_rwuio(np->n_fid, UIO_WRITE,
+ &auio, &scred, smb_timo_write);
/* Like NFS, only set b_error here. */
bp->b_error = error;
@@ -1334,7 +1324,7 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
if (!error && auio.uio_resid != 0)
error = EIO;
if (!error && sync) {
- (void) smbfs_smb_flush(np, &scred);
+ (void) smbfsflush(np, &scred);
}
}
@@ -1361,6 +1351,7 @@ smbfs_bio(struct buf *bp, int sync, cred_t *cr)
return (error);
}
+#endif // _KERNEL
/*
* Here NFS has: nfs3write, nfs3read
@@ -1588,12 +1579,12 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
{
int error = 0;
smbnode_t *np = VTOSMB(vp);
+ smbmntinfo_t *smi = np->n_mount;
uint_t mask = vap->va_mask;
struct timespec *mtime, *atime;
struct smb_cred scred;
- int cerror, modified = 0;
- unsigned short fid;
- int have_fid = 0;
+ int modified = 0;
+ smb_fh_t *fid = NULL;
uint32_t rights = 0;
uint32_t dosattr = 0;
@@ -1645,9 +1636,6 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
* with a partially complete request.
*/
- /* Shared lock for (possible) n_fid use. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
smb_credinit(&scred, cr);
/*
@@ -1685,7 +1673,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
error, np->n_rpath);
goto out;
}
- have_fid = 1;
+ ASSERT(fid != NULL);
}
/*
@@ -1704,8 +1692,9 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
/*
* Set the file size to vap->va_size.
*/
- ASSERT(have_fid);
- error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
+ ASSERT(fid != NULL);
+ error = smbfs_smb_setfsize(smi->smi_share, fid,
+ vap->va_size, &scred);
if (error) {
SMBVDEBUG("setsize error %d file %s\n",
error, np->n_rpath);
@@ -1717,6 +1706,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
*/
mutex_enter(&np->r_statelock);
np->r_size = vap->va_size;
+ np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
mutex_exit(&np->r_statelock);
modified = 1;
}
@@ -1733,8 +1723,8 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
/*
* Always use the handle-based set attr call now.
*/
- ASSERT(have_fid);
- error = smbfs_smb_setfattr(np, fid,
+ ASSERT(fid != NULL);
+ error = smbfs_smb_setfattr(smi->smi_share, fid,
dosattr, mtime, atime, &scred);
if (error) {
SMBVDEBUG("set times error %d file %s\n",
@@ -1745,15 +1735,10 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
}
out:
- if (have_fid) {
- cerror = smbfs_smb_tmpclose(np, fid, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing %s\n",
- cerror, np->n_rpath);
- }
+ if (fid != NULL)
+ smbfs_smb_tmpclose(np, fid);
smb_credrele(&scred);
- smbfs_rw_exit(&np->r_lkserlock);
if (modified) {
/*
@@ -2022,7 +2007,7 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
return (EINTR);
smb_credinit(&scred, cr);
- error = smbfs_smb_flush(np, &scred);
+ error = smbfsflush(np, &scred);
smb_credrele(&scred);
smbfs_rw_exit(&np->r_lkserlock);
@@ -2030,6 +2015,37 @@ smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
return (error);
}
+static int
+smbfsflush(smbnode_t *np, struct smb_cred *scrp)
+{
+ struct smb_share *ssp = np->n_mount->smi_share;
+ smb_fh_t *fhp;
+ int error;
+
+ /* Shared lock for n_fid use below. */
+ ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+ if (!(np->n_flag & NFLUSHWIRE))
+ return (0);
+ if (np->n_fidrefs == 0)
+ return (0); /* not open */
+ if ((fhp = np->n_fid) == NULL)
+ return (0);
+
+ /* After reconnect, n_fid is invalid */
+ if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+ return (ESTALE);
+
+ error = smbfs_smb_flush(ssp, fhp, scrp);
+
+ if (!error) {
+ mutex_enter(&np->r_statelock);
+ np->n_flag &= ~NFLUSHWIRE;
+ mutex_exit(&np->r_statelock);
+ }
+ return (error);
+}
+
/*
* Last reference to vnode went away.
*/
@@ -2119,8 +2135,8 @@ smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
case VREG:
if (np->n_fidrefs == 0)
break;
- SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
- np->n_fidrefs, np->n_fid, np->n_rpath);
+ SMBVDEBUG("open file: refs %d path %s\n",
+ np->n_fidrefs, np->n_rpath);
/* Force last close. */
np->n_fidrefs = 1;
smbfs_rele_fid(np, &scred);
@@ -2198,6 +2214,14 @@ smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
smbfs_rw_exit(&dnp->r_rwlock);
+ /*
+ * If the caller passes an invalid name here, we'll have
+ * error == EINVAL but want to return ENOENT. This is
+ * common with things like "ls foo*" with no matches.
+ */
+ if (error == EINVAL)
+ error = ENOENT;
+
return (error);
}
@@ -2225,14 +2249,7 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
-#ifdef NOT_YET
- vcp = SSTOVC(smi->smi_share);
-
- /* XXX: Should compute this once and store it in smbmntinfo_t */
- supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
-#else
supplen = 255;
-#endif
/*
* RWlock must be held, either reader or writer.
@@ -2519,7 +2536,6 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
vsecattr_t *vsecp)
{
int error;
- int cerror;
vfs_t *vfsp;
vnode_t *vp;
smbnode_t *np;
@@ -2531,7 +2547,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
const char *name = (const char *)nm;
int nmlen = strlen(nm);
uint32_t disp;
- uint16_t fid;
+ smb_fh_t *fid = NULL;
int xattr;
vfsp = dvp->v_vfsp;
@@ -2693,11 +2709,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* Should use the fid to get/set the size
* while we have it opened here. See above.
*/
-
- cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
- if (cerror)
- SMBVDEBUG("error %d closing %s\\%s\n",
- cerror, dnp->n_rpath, name);
+ smbfs_smb_close(fid);
/*
* In the open case, the name may differ a little
@@ -2766,14 +2778,30 @@ smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
/* Lookup the file to remove. */
error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
- if (error == 0) {
- /*
- * Do the real remove work
- */
- error = smbfsremove(dvp, vp, &scred, flags);
- VN_RELE(vp);
+ if (error != 0)
+ goto out;
+
+ /* Don't allow unlink of a directory. */
+ if (vp->v_type == VDIR) {
+ error = EPERM;
+ goto out;
}
+ /*
+ * Do the real remove work
+ */
+ error = smbfsremove(dvp, vp, &scred, flags);
+ if (error != 0)
+ goto out;
+
+#ifdef SMBFS_VNEVENT
+ vnevent_remove(vp, dvp, nm, ct);
+#endif
+
+out:
+ if (vp != NULL)
+ VN_RELE(vp);
+
smb_credrele(&scred);
smbfs_rw_exit(&dnp->r_rwlock);
@@ -2808,11 +2836,11 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
{
smbnode_t *dnp = VTOSMB(dvp);
smbnode_t *np = VTOSMB(vp);
+ smbmntinfo_t *smi = np->n_mount;
char *tmpname = NULL;
int tnlen;
int error;
- unsigned short fid;
- boolean_t have_fid = B_FALSE;
+ smb_fh_t *fid = NULL;
boolean_t renamed = B_FALSE;
/*
@@ -2820,10 +2848,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
*/
ASSERT(dnp->r_rwlock.owner == curthread);
- /* Never allow link/unlink directories on SMB. */
- if (vp->v_type == VDIR)
- return (EPERM);
-
/*
* We need to flush any dirty pages which happen to
* be hanging around before removing the file. This
@@ -2842,10 +2866,6 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
}
}
- /* Shared lock for n_fid use in smbfs_smb_setdisp etc. */
- if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
- return (EINTR);
-
/*
* Get a file handle with delete access.
* Close this FID before return.
@@ -2857,16 +2877,18 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
error, np->n_rpath);
goto out;
}
- have_fid = B_TRUE;
+ ASSERT(fid != NULL);
/*
* If we have the file open, try to rename it to a temporary name.
* If we can't rename, continue on and try setting DoC anyway.
+ * Unnecessary for directories.
*/
- if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
+ if (vp->v_type != VDIR && vp->v_count > 1 && np->n_fidrefs > 0) {
tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
tnlen = smbfs_newname(tmpname, MAXNAMELEN);
- error = smbfs_smb_t2rename(np, tmpname, tnlen, scred, fid, 0);
+ error = smbfs_smb_rename(dnp, np, dnp, tmpname, tnlen,
+ fid, scred);
if (error != 0) {
SMBVDEBUG("error %d renaming %s -> %s\n",
error, np->n_rpath, tmpname);
@@ -2880,7 +2902,7 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
* Mark the file as delete-on-close. If we can't,
* undo what we did and err out.
*/
- error = smbfs_smb_setdisp(np, fid, 1, scred);
+ error = smbfs_smb_setdisp(smi->smi_share, fid, 1, scred);
if (error != 0) {
SMBVDEBUG("error %d setting DoC on %s\n",
error, np->n_rpath);
@@ -2897,8 +2919,8 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
oldname = np->n_rpath + (dnp->n_rplen + 1);
oldnlen = np->n_rplen - (dnp->n_rplen + 1);
- err2 = smbfs_smb_t2rename(np, oldname, oldnlen,
- scred, fid, 0);
+ err2 = smbfs_smb_rename(dnp, np, dnp, oldname, oldnlen,
+ fid, scred);
SMBVDEBUG("error %d un-renaming %s -> %s\n",
err2, tmpname, np->n_rpath);
}
@@ -2906,19 +2928,14 @@ smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
goto out;
}
/* Done! */
+ smbfs_attrcache_remove(np);
smbfs_attrcache_prune(np);
-#ifdef SMBFS_VNEVENT
- vnevent_remove(vp, dvp, nm, ct);
-#endif
-
out:
if (tmpname != NULL)
kmem_free(tmpname, MAXNAMELEN);
-
- if (have_fid)
- (void) smbfs_smb_tmpclose(np, fid, scred);
- smbfs_rw_exit(&np->r_lkserlock);
+ if (fid != NULL)
+ smbfs_smb_tmpclose(np, fid);
if (error == 0) {
/* Keep lookup from finding this node anymore. */
@@ -3050,6 +3067,7 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
vnode_t *nvp = NULL;
int error;
int nvp_locked = 0;
+ smb_fh_t *fid = NULL;
/* Things our caller should have checked. */
ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
@@ -3130,8 +3148,23 @@ smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
nvp = NULL;
} /* nvp */
+ /*
+ * Get a file handle with delete access.
+ * Close this FID before return.
+ */
+ error = smbfs_smb_tmpopen(onp, STD_RIGHT_DELETE_ACCESS,
+ scred, &fid);
+ if (error) {
+ SMBVDEBUG("error %d opening %s\n",
+ error, onp->n_rpath);
+ goto out;
+ }
+
smbfs_attrcache_remove(onp);
- error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), scred);
+ error = smbfs_smb_rename(odnp, onp, ndnp, nnm, strlen(nnm),
+ fid, scred);
+
+ smbfs_smb_tmpclose(onp, fid);
/*
* If the old name should no longer exist,
@@ -3172,7 +3205,7 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
struct smbfattr fattr;
const char *name = (const char *) nm;
int nmlen = strlen(name);
- int error, hiderr;
+ int error;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
return (EPERM);
@@ -3213,10 +3246,6 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
if (error)
goto out;
- if (name[0] == '.')
- if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
- SMBVDEBUG("hide failure %d\n", hiderr);
-
/* Success! */
*vpp = vp;
error = 0;
@@ -3240,12 +3269,12 @@ static int
smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
caller_context_t *ct, int flags)
{
+ struct smb_cred scred;
vnode_t *vp = NULL;
int vp_locked = 0;
struct smbmntinfo *smi = VTOSMI(dvp);
struct smbnode *dnp = VTOSMB(dvp);
struct smbnode *np;
- struct smb_cred scred;
int error;
if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
@@ -3254,17 +3283,16 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
return (EIO);
- if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
- return (EINTR);
- smb_credinit(&scred, cr);
-
/*
- * Require w/x access in the containing directory.
- * Server handles all other access checks.
+ * Verify access to the dirctory.
*/
- error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
+ error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
if (error)
- goto out;
+ return (error);
+
+ if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
+ return (EINTR);
+ smb_credinit(&scred, cr);
/*
* First lookup the entry to be removed.
@@ -3297,23 +3325,17 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
goto out;
}
- smbfs_attrcache_remove(np);
- error = smbfs_smb_rmdir(np, &scred);
-
/*
- * Similar to smbfs_remove
+ * Do the real rmdir work
*/
- switch (error) {
- case 0:
- case ENOENT:
- case ENOTDIR:
- smbfs_attrcache_prune(np);
- break;
- }
-
+ error = smbfsremove(dvp, vp, &scred, flags);
if (error)
goto out;
+#ifdef SMBFS_VNEVENT
+ vnevent_rmdir(vp, dvp, nm, ct);
+#endif
+
mutex_enter(&np->r_statelock);
dnp->n_flag |= NMODIFIED;
mutex_exit(&np->r_statelock);
@@ -3692,6 +3714,8 @@ smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
/* mmap support ******************************************************** */
+#ifdef _KERNEL
+
#ifdef DEBUG
static int smbfs_lostpage = 0; /* number of times we lost original page */
#endif
@@ -4011,6 +4035,8 @@ again:
* No read-ahead in smbfs yet.
*/
+#endif // _KERNEL
+
/*
* Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
* If len == 0, do from off to EOF.
@@ -4026,6 +4052,7 @@ static int
smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
caller_context_t *ct)
{
+#ifdef _KERNEL
smbnode_t *np;
smbmntinfo_t *smi;
page_t *pp;
@@ -4157,8 +4184,14 @@ smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
}
return (error);
+
+#else // _KERNEL
+ return (ENOSYS);
+#endif // _KERNEL
}
+#ifdef _KERNEL
+
/*
* Write out a single page, possibly klustering adjacent dirty pages.
*
@@ -4331,6 +4364,9 @@ smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
return (error);
}
+#endif // _KERNEL
+
+
/*
* NFS has this in nfs_client.c (shared by v2,v3,...)
* We have it here so smbfs_putapage can be file scope.
@@ -4355,8 +4391,10 @@ smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
/* Here NFSv3 has np->r_truncaddr = off; */
mutex_exit(&np->r_statelock);
+#ifdef _KERNEL
(void) pvn_vplist_dirty(vp, off, smbfs_putapage,
B_INVAL | B_TRUNC, cr);
+#endif // _KERNEL
mutex_enter(&np->r_statelock);
np->r_flags &= ~RTRUNCATE;
@@ -4364,6 +4402,8 @@ smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
mutex_exit(&np->r_statelock);
}
+#ifdef _KERNEL
+
/* Like nfs3_map */
/* ARGSUSED */
@@ -4659,6 +4699,8 @@ smbfs_delmap_async(void *varg)
/* No smbfs_pageio() or smbfs_dispose() ops. */
+#endif // _KERNEL
+
/* misc. ******************************************************** */
@@ -4961,11 +5003,13 @@ const fs_operation_def_t smbfs_vnodeops_template[] = {
VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock },
VOPNAME_SPACE, { .vop_space = smbfs_space },
VOPNAME_REALVP, { .vop_realvp = smbfs_realvp },
+#ifdef _KERNEL
VOPNAME_GETPAGE, { .vop_getpage = smbfs_getpage },
VOPNAME_PUTPAGE, { .vop_putpage = smbfs_putpage },
VOPNAME_MAP, { .vop_map = smbfs_map },
VOPNAME_ADDMAP, { .vop_addmap = smbfs_addmap },
VOPNAME_DELMAP, { .vop_delmap = smbfs_delmap },
+#endif // _KERNEL
VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf },
VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr },
VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr },
diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
index 75241cc1f0..323b8c8d10 100644
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -29,6 +30,7 @@
*/
#include <sys/systm.h>
+#include <sys/inttypes.h>
#include <sys/cred.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
@@ -43,7 +45,9 @@
#include <sys/u8_textprep.h>
#include <netsmb/smb_osdep.h>
+
#include <netsmb/smb.h>
+#include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
@@ -289,32 +293,20 @@ smbfs_xa_getfattr(struct smbnode *xnp, struct smbfattr *fap,
}
/*
- * Fetch the entire attribute list here in findopen.
- * Will parse the results in findnext.
+ * Actually go OtW to get the list of "streams".
*
* This is called on the XATTR directory, so we
* have to get the (real) parent object first.
*/
-/* ARGSUSED */
-int
-smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen)
+static int
+smbfs_xa_get_streaminfo(struct smbfs_fctx *ctx)
{
vnode_t *pvp; /* parent */
smbnode_t *pnp;
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct mbchain *mbp;
+ smbnode_t *dnp = ctx->f_dnp;
+ struct mdchain *mdp;
int error;
- ASSERT(dnp->n_flag & N_XATTR);
-
- ctx->f_type = ft_XA;
- ctx->f_namesz = SMB_MAXFNAMELEN + 1;
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- ctx->f_namesz *= 2;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
-
error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
if (error)
return (error);
@@ -322,40 +314,31 @@ smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
/* Note: pvp has a VN_HOLD */
pnp = VTOSMB(pvp);
- if (ctx->f_t2) {
- smb_t2_done(ctx->f_t2);
- ctx->f_t2 = NULL;
- }
+ /*
+ * Get stream info into f_mdchain
+ */
+ mdp = &ctx->f_mdchain;
+ md_done(mdp);
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp),
- SMB_TRANS2_QUERY_PATH_INFORMATION,
- ctx->f_scred, &t2p);
+ if (SSTOVC(ctx->f_ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_get_streaminfo(pnp, mdp, ctx->f_scred);
+ } else {
+ error = smbfs_smb1_get_streaminfo(pnp, mdp, ctx->f_scred);
+ }
if (error)
goto out;
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- (void) mb_init(mbp);
- (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
- (void) mb_put_uint32le(mbp, 0);
- error = smbfs_fullpath(mbp, vcp, pnp, NULL, NULL, 0);
- if (error)
- goto out;
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = INT16_MAX;
- error = smb_t2_request(t2p);
- if (error) {
- if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
- error = ENOTSUP;
- }
/*
- * No returned parameters to parse.
- * Returned data are in t2_rdata,
- * which we'll parse in _findnext.
- * However, save the wildcard.
+ * Have stream info in ctx->f_mdchain
+ * Initialize buffer length, position.
*/
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
+ ctx->f_left = m_fixhdr(mdp->md_top);
+ ctx->f_eofs = 0;
+
+ /*
+ * After one successful call, we're at EOF.
+ */
+ ctx->f_flags |= SMBFS_RDD_EOF;
out:
VN_RELE(pvp);
@@ -363,83 +346,62 @@ out:
}
/*
- * Get the next name in an XATTR directory into f_name
+ * Get a buffer of directory entries (if we don't already have
+ * some remaining in the current buffer) then decode one.
*/
-/* ARGSUSED */
int
-smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen)
{
- struct mdchain *mdp;
- struct smb_t2rq *t2p;
- uint32_t size, next;
- uint64_t llongint;
- int error, skip, used, nmlen;
- t2p = ctx->f_t2;
- mdp = &t2p->t2_rdata;
+ ASSERT(dnp->n_flag & N_XATTR);
- if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
- ASSERT(ctx->f_wildcard);
- SMBVDEBUG("wildcard: %s\n", ctx->f_wildcard);
- }
+ ctx->f_type = ft_XA;
+ ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+ ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
+ ctx->f_infolevel = FileStreamInformation;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
-again:
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
-
- /* Parse FILE_STREAM_INFORMATION */
- if ((error = md_get_uint32le(mdp, &next)) != 0) /* offset to */
- return (ENOENT);
- if ((error = md_get_uint32le(mdp, &size)) != 0) /* name len */
- return (ENOENT);
- (void) md_get_uint64le(mdp, &llongint); /* file size */
- ctx->f_attr.fa_size = llongint;
- (void) md_get_uint64le(mdp, NULL); /* alloc. size */
- used = 4 + 4 + 8 + 8; /* how much we consumed */
+ return (0);
+}
- /*
- * Copy the string, but skip the first char (":")
- * Watch out for zero-length strings here.
- */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
- if (size >= 2) {
- size -= 2; used += 2;
- (void) md_get_uint16le(mdp, NULL);
- }
- nmlen = min(size, SMB_MAXFNAMELEN * 2);
- } else {
- if (size >= 1) {
- size -= 1; used += 1;
- (void) md_get_uint8(mdp, NULL);
- }
- nmlen = min(size, SMB_MAXFNAMELEN);
- }
- ASSERT(nmlen < ctx->f_namesz);
- ctx->f_nmlen = nmlen;
- error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM);
- if (error)
- return (error);
- used += nmlen;
+/*
+ * Get the next name in an XATTR directory
+ */
+/* ARGSUSED */
+int
+smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
+{
+ int error;
/*
- * Convert UCS-2 to UTF-8
+ * If we've scanned to the end of the current buffer
+ * try to read anohther buffer of dir entries.
+ * Treat anything less than 8 bytes as an "empty"
+ * buffer to ensure we can read something.
+ * (There may be up to 8 bytes of padding.)
*/
- smbfs_fname_tolocal(ctx);
- if (nmlen)
- SMBVDEBUG("name: %s\n", ctx->f_name);
- else
- SMBVDEBUG("null name!\n");
+again:
+ if ((ctx->f_eofs + 8) > ctx->f_left) {
+ /* Scanned the whole buffer. */
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return (ENOENT);
+ ctx->f_limit = limit;
+ error = smbfs_xa_get_streaminfo(ctx);
+ if (error)
+ return (error);
+ ctx->f_otws++;
+ }
/*
- * Skip padding until next offset
+ * Decode one entry, advance f_eofs
*/
- if (next > used) {
- skip = next - used;
- (void) md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
- }
- if (next == 0)
- ctx->f_flags |= SMBFS_RDD_EOF;
+ error = smbfs_decode_dirent(ctx);
+ if (error)
+ return (error);
+ SMBVDEBUG("name: %s\n", ctx->f_name);
/*
* Chop off the trailing ":$DATA"
@@ -462,8 +424,10 @@ again:
goto again;
/*
- * If this is a lookup of a specific name,
- * skip past any non-matching names.
+ * When called by lookup, we'll have the "single" flag,
+ * and a name with no wildcards. We need to filter here
+ * because smbfs_xa_get_streaminfo() gets ALL the names
+ * (not just those matching our pattern).
*/
if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
if (ctx->f_wclen != ctx->f_nmlen)
@@ -488,8 +452,6 @@ smbfs_xa_findclose(struct smbfs_fctx *ctx)
if (ctx->f_name)
kmem_free(ctx->f_name, ctx->f_namesz);
- if (ctx->f_t2)
- smb_t2_done(ctx->f_t2);
return (0);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
index f4a9f9a948..4ed5cba79c 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
@@ -22,7 +22,7 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -31,7 +31,7 @@
*/
#include <smbsrv/smb2_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
struct smb2_ioctbl_ent {
uint32_t te_code;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
index ffe230f888..6176a8b002 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
@@ -30,7 +30,7 @@
#include <smbsrv/string.h>
#include <smbsrv/nmpipes.h>
#include <smbsrv/mailslot.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* count of bytes in server response packet
@@ -943,7 +943,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
data_off, /* Data offset from header start */
data_disp, /* Data displacement */
n_setup, /* suwcnt */
- &xa->rep_setup_mb, /* setup[] */
+ &xa->rep_setup_mb, /* setup[] */
tot_packet_bytes, /* Total data bytes */
param_pad,
&xa->rep_param_mb,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
index 495965859b..03c565e9e4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dfs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dfs.c
@@ -22,13 +22,13 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_dfs.h>
#include <smbsrv/smb_door.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* Get Referral response header flags
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
index c0ab285bd5..f355e314bc 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
@@ -20,11 +20,11 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
index 273a2f7297..c08cba0ac6 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -35,7 +35,7 @@
#include <sys/filio.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_xdr.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
static uint32_t smb_opipe_transceive(smb_request_t *, smb_fsctl_t *);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
index df874ffe1d..918bf78727 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
@@ -22,11 +22,11 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
/*
* [MS-CIFS]
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vss.c b/usr/src/uts/common/fs/smbsrv/smb_vss.c
index 211bc467a8..72657ae3be 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_vss.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_vss.c
@@ -41,7 +41,7 @@
#include <smbsrv/smb_kproto.h>
#include <smbsrv/string.h>
-#include <smbsrv/winioctl.h>
+#include <smb/winioctl.h>
#include <smbsrv/smb_door.h>
/* Size of the token on the wire due to encoding */
diff --git a/usr/src/uts/common/fs/zfs/arc.c b/usr/src/uts/common/fs/zfs/arc.c
index 469106c7d7..9fa4487ab7 100644
--- a/usr/src/uts/common/fs/zfs/arc.c
+++ b/usr/src/uts/common/fs/zfs/arc.c
@@ -469,8 +469,13 @@ typedef struct arc_stats {
*/
kstat_named_t arcstat_mutex_miss;
/*
+ * Number of buffers skipped when updating the access state due to the
+ * header having already been released after acquiring the hash lock.
+ */
+ kstat_named_t arcstat_access_skip;
+ /*
* Number of buffers skipped because they have I/O in progress, are
- * indrect prefetch buffers that have not lived long enough, or are
+ * indirect prefetch buffers that have not lived long enough, or are
* not from the spa we're trying to evict from.
*/
kstat_named_t arcstat_evict_skip;
@@ -712,6 +717,7 @@ static arc_stats_t arc_stats = {
{ "mfu_ghost_hits", KSTAT_DATA_UINT64 },
{ "deleted", KSTAT_DATA_UINT64 },
{ "mutex_miss", KSTAT_DATA_UINT64 },
+ { "access_skip", KSTAT_DATA_UINT64 },
{ "evict_skip", KSTAT_DATA_UINT64 },
{ "evict_not_enough", KSTAT_DATA_UINT64 },
{ "evict_l2_cached", KSTAT_DATA_UINT64 },
@@ -4715,6 +4721,50 @@ arc_access(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
}
}
+/*
+ * This routine is called by dbuf_hold() to update the arc_access() state
+ * which otherwise would be skipped for entries in the dbuf cache.
+ */
+void
+arc_buf_access(arc_buf_t *buf)
+{
+ mutex_enter(&buf->b_evict_lock);
+ arc_buf_hdr_t *hdr = buf->b_hdr;
+
+ /*
+ * Avoid taking the hash_lock when possible as an optimization.
+ * The header must be checked again under the hash_lock in order
+ * to handle the case where it is concurrently being released.
+ */
+ if (hdr->b_l1hdr.b_state == arc_anon || HDR_EMPTY(hdr)) {
+ mutex_exit(&buf->b_evict_lock);
+ return;
+ }
+
+ kmutex_t *hash_lock = HDR_LOCK(hdr);
+ mutex_enter(hash_lock);
+
+ if (hdr->b_l1hdr.b_state == arc_anon || HDR_EMPTY(hdr)) {
+ mutex_exit(hash_lock);
+ mutex_exit(&buf->b_evict_lock);
+ ARCSTAT_BUMP(arcstat_access_skip);
+ return;
+ }
+
+ mutex_exit(&buf->b_evict_lock);
+
+ ASSERT(hdr->b_l1hdr.b_state == arc_mru ||
+ hdr->b_l1hdr.b_state == arc_mfu);
+
+ DTRACE_PROBE1(arc__hit, arc_buf_hdr_t *, hdr);
+ arc_access(hdr, hash_lock);
+ mutex_exit(hash_lock);
+
+ ARCSTAT_BUMP(arcstat_hits);
+ ARCSTAT_CONDSTAT(!HDR_PREFETCH(hdr),
+ demand, prefetch, !HDR_ISTYPE_METADATA(hdr), data, metadata, hits);
+}
+
/* a generic arc_done_func_t which you can use */
/* ARGSUSED */
void
diff --git a/usr/src/uts/common/fs/zfs/dbuf.c b/usr/src/uts/common/fs/zfs/dbuf.c
index 62458bad77..979bb8848e 100644
--- a/usr/src/uts/common/fs/zfs/dbuf.c
+++ b/usr/src/uts/common/fs/zfs/dbuf.c
@@ -1581,6 +1581,9 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
FTAG);
}
}
+
+ if (tx->tx_txg > dn->dn_dirty_txg)
+ dn->dn_dirty_txg = tx->tx_txg;
mutex_exit(&dn->dn_mtx);
if (db->db_blkid == DMU_SPILL_BLKID)
@@ -2661,8 +2664,10 @@ top:
return (SET_ERROR(ENOENT));
}
- if (db->db_buf != NULL)
+ if (db->db_buf != NULL) {
+ arc_buf_access(db->db_buf);
ASSERT3P(db->db.db_data, ==, db->db_buf->b_data);
+ }
ASSERT(db->db_buf == NULL || arc_referenced(db->db_buf));
diff --git a/usr/src/uts/common/fs/zfs/ddt_zap.c b/usr/src/uts/common/fs/zfs/ddt_zap.c
index d6a991c7c1..6618137433 100644
--- a/usr/src/uts/common/fs/zfs/ddt_zap.c
+++ b/usr/src/uts/common/fs/zfs/ddt_zap.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018 by Delphix. All rights reserved.
*/
#include <sys/zfs_context.h>
@@ -114,7 +115,18 @@ ddt_zap_walk(objset_t *os, uint64_t object, ddt_entry_t *dde, uint64_t *walk)
zap_attribute_t za;
int error;
- zap_cursor_init_serialized(&zc, os, object, *walk);
+ if (*walk == 0) {
+ /*
+ * We don't want to prefetch the entire ZAP object, because
+ * it can be enormous. Also the primary use of DDT iteration
+ * is for scrubbing, in which case we will be issuing many
+ * scrub i/os for each ZAP block that we read in, so
+ * reading the ZAP is unlikely to be the bottleneck.
+ */
+ zap_cursor_init_noprefetch(&zc, os, object);
+ } else {
+ zap_cursor_init_serialized(&zc, os, object, *walk);
+ }
if ((error = zap_cursor_retrieve(&zc, &za)) == 0) {
uchar_t cbuf[sizeof (dde->dde_phys) + 1];
uint64_t csize = za.za_num_integers;
diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c
index da84226c14..e299096351 100644
--- a/usr/src/uts/common/fs/zfs/dmu.c
+++ b/usr/src/uts/common/fs/zfs/dmu.c
@@ -88,6 +88,13 @@ uint32_t zfs_per_txg_dirty_frees_percent = 30;
*/
int zfs_object_remap_one_indirect_delay_ticks = 0;
+/*
+ * Limit the amount we can prefetch with one call to this amount. This
+ * helps to limit the amount of memory that can be used by prefetching.
+ * Larger objects should be prefetched a bit at a time.
+ */
+uint64_t dmu_prefetch_max = 8 * SPA_MAXBLOCKSIZE;
+
const dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES] = {
{ DMU_BSWAP_UINT8, TRUE, FALSE, "unallocated" },
{ DMU_BSWAP_ZAP, TRUE, TRUE, "object directory" },
@@ -638,6 +645,11 @@ dmu_prefetch(objset_t *os, uint64_t object, int64_t level, uint64_t offset,
}
/*
+ * See comment before the definition of dmu_prefetch_max.
+ */
+ len = MIN(len, dmu_prefetch_max);
+
+ /*
* XXX - Note, if the dnode for the requested object is not
* already cached, we will do a *synchronous* read in the
* dnode_hold() call. The same is true for any indirects.
diff --git a/usr/src/uts/common/fs/zfs/dmu_object.c b/usr/src/uts/common/fs/zfs/dmu_object.c
index 9895cf4776..f835987e7d 100644
--- a/usr/src/uts/common/fs/zfs/dmu_object.c
+++ b/usr/src/uts/common/fs/zfs/dmu_object.c
@@ -263,7 +263,7 @@ dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
{
return (dmu_object_reclaim_dnsize(os, object, ot, blocksize, bonustype,
- bonuslen, 0, tx));
+ bonuslen, DNODE_MIN_SIZE, tx));
}
int
diff --git a/usr/src/uts/common/fs/zfs/dmu_objset.c b/usr/src/uts/common/fs/zfs/dmu_objset.c
index db0fff702e..36e6391d57 100644
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c
@@ -1247,10 +1247,23 @@ dmu_objset_sync_dnodes(multilist_sublist_t *list, dmu_tx_t *tx)
ASSERT3U(dn->dn_nlevels, <=, DN_MAX_LEVELS);
multilist_sublist_remove(list, dn);
+ /*
+ * If we are not doing useraccounting (os_synced_dnodes == NULL)
+ * we are done with this dnode for this txg. Unset dn_dirty_txg
+ * if later txgs aren't dirtying it so that future holders do
+ * not get a stale value. Otherwise, we will do this in
+ * userquota_updates_task() when processing has completely
+ * finished for this txg.
+ */
multilist_t *newlist = dn->dn_objset->os_synced_dnodes;
if (newlist != NULL) {
(void) dnode_add_ref(dn, newlist);
multilist_insert(newlist, dn);
+ } else {
+ mutex_enter(&dn->dn_mtx);
+ if (dn->dn_dirty_txg == tx->tx_txg)
+ dn->dn_dirty_txg = 0;
+ mutex_exit(&dn->dn_mtx);
}
dnode_sync(dn, tx);
@@ -1610,6 +1623,8 @@ userquota_updates_task(void *arg)
dn->dn_id_flags |= DN_ID_CHKED_BONUS;
}
dn->dn_id_flags &= ~(DN_ID_NEW_EXIST);
+ if (dn->dn_dirty_txg == spa_syncing_txg(os->os_spa))
+ dn->dn_dirty_txg = 0;
mutex_exit(&dn->dn_mtx);
multilist_sublist_remove(list, dn);
diff --git a/usr/src/uts/common/fs/zfs/dmu_recv.c b/usr/src/uts/common/fs/zfs/dmu_recv.c
new file mode 100644
index 0000000000..bee41bd95e
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/dmu_recv.c
@@ -0,0 +1,2264 @@
+/*
+ * 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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright 2014 HybridCluster. All rights reserved.
+ * Copyright 2016 RackTop Systems.
+ * Copyright (c) 2014 Integros [integros.com]
+ */
+
+#include <sys/dmu.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/dbuf.h>
+#include <sys/dnode.h>
+#include <sys/zfs_context.h>
+#include <sys/dmu_objset.h>
+#include <sys/dmu_traverse.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_pool.h>
+#include <sys/dsl_synctask.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zap.h>
+#include <sys/zio_checksum.h>
+#include <sys/zfs_znode.h>
+#include <zfs_fletcher.h>
+#include <sys/avl.h>
+#include <sys/ddt.h>
+#include <sys/zfs_onexit.h>
+#include <sys/dmu_recv.h>
+#include <sys/dsl_destroy.h>
+#include <sys/blkptr.h>
+#include <sys/dsl_bookmark.h>
+#include <sys/zfeature.h>
+#include <sys/bqueue.h>
+
+int zfs_recv_queue_length = SPA_MAXBLOCKSIZE;
+
+static char *dmu_recv_tag = "dmu_recv_tag";
+const char *recv_clone_name = "%recv";
+
+static void byteswap_record(dmu_replay_record_t *drr);
+
+typedef struct dmu_recv_begin_arg {
+ const char *drba_origin;
+ dmu_recv_cookie_t *drba_cookie;
+ cred_t *drba_cred;
+ uint64_t drba_snapobj;
+} dmu_recv_begin_arg_t;
+
+static int
+recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
+ uint64_t fromguid)
+{
+ uint64_t val;
+ int error;
+ dsl_pool_t *dp = ds->ds_dir->dd_pool;
+
+ /* temporary clone name must not exist */
+ error = zap_lookup(dp->dp_meta_objset,
+ dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, recv_clone_name,
+ 8, 1, &val);
+ if (error != ENOENT)
+ return (error == 0 ? EBUSY : error);
+
+ /* new snapshot name must not exist */
+ error = zap_lookup(dp->dp_meta_objset,
+ dsl_dataset_phys(ds)->ds_snapnames_zapobj,
+ drba->drba_cookie->drc_tosnap, 8, 1, &val);
+ if (error != ENOENT)
+ return (error == 0 ? EEXIST : error);
+
+ /*
+ * Check snapshot limit before receiving. We'll recheck again at the
+ * end, but might as well abort before receiving if we're already over
+ * the limit.
+ *
+ * Note that we do not check the file system limit with
+ * dsl_dir_fscount_check because the temporary %clones don't count
+ * against that limit.
+ */
+ error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT,
+ NULL, drba->drba_cred);
+ if (error != 0)
+ return (error);
+
+ if (fromguid != 0) {
+ dsl_dataset_t *snap;
+ uint64_t obj = dsl_dataset_phys(ds)->ds_prev_snap_obj;
+
+ /* Find snapshot in this dir that matches fromguid. */
+ while (obj != 0) {
+ error = dsl_dataset_hold_obj(dp, obj, FTAG,
+ &snap);
+ if (error != 0)
+ return (SET_ERROR(ENODEV));
+ if (snap->ds_dir != ds->ds_dir) {
+ dsl_dataset_rele(snap, FTAG);
+ return (SET_ERROR(ENODEV));
+ }
+ if (dsl_dataset_phys(snap)->ds_guid == fromguid)
+ break;
+ obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
+ dsl_dataset_rele(snap, FTAG);
+ }
+ if (obj == 0)
+ return (SET_ERROR(ENODEV));
+
+ if (drba->drba_cookie->drc_force) {
+ drba->drba_snapobj = obj;
+ } else {
+ /*
+ * If we are not forcing, there must be no
+ * changes since fromsnap.
+ */
+ if (dsl_dataset_modified_since_snap(ds, snap)) {
+ dsl_dataset_rele(snap, FTAG);
+ return (SET_ERROR(ETXTBSY));
+ }
+ drba->drba_snapobj = ds->ds_prev->ds_object;
+ }
+
+ dsl_dataset_rele(snap, FTAG);
+ } else {
+ /* if full, then must be forced */
+ if (!drba->drba_cookie->drc_force)
+ return (SET_ERROR(EEXIST));
+ /* start from $ORIGIN@$ORIGIN, if supported */
+ drba->drba_snapobj = dp->dp_origin_snap != NULL ?
+ dp->dp_origin_snap->ds_object : 0;
+ }
+
+ return (0);
+
+}
+
+static int
+dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
+{
+ dmu_recv_begin_arg_t *drba = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
+ uint64_t fromguid = drrb->drr_fromguid;
+ int flags = drrb->drr_flags;
+ int error;
+ uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+ dsl_dataset_t *ds;
+ const char *tofs = drba->drba_cookie->drc_tofs;
+
+ /* already checked */
+ ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+ ASSERT(!(featureflags & DMU_BACKUP_FEATURE_RESUMING));
+
+ if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
+ DMU_COMPOUNDSTREAM ||
+ drrb->drr_type >= DMU_OST_NUMTYPES ||
+ ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL))
+ return (SET_ERROR(EINVAL));
+
+ /* Verify pool version supports SA if SA_SPILL feature set */
+ if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) &&
+ spa_version(dp->dp_spa) < SPA_VERSION_SA)
+ return (SET_ERROR(ENOTSUP));
+
+ if (drba->drba_cookie->drc_resumable &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EXTENSIBLE_DATASET))
+ return (SET_ERROR(ENOTSUP));
+
+ /*
+ * The receiving code doesn't know how to translate a WRITE_EMBEDDED
+ * record to a plain WRITE record, so the pool must have the
+ * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED
+ * records. Same with WRITE_EMBEDDED records that use LZ4 compression.
+ */
+ if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA))
+ return (SET_ERROR(ENOTSUP));
+ if ((featureflags & DMU_BACKUP_FEATURE_LZ4) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
+ return (SET_ERROR(ENOTSUP));
+
+ /*
+ * The receiving code doesn't know how to translate large blocks
+ * to smaller ones, so the pool must have the LARGE_BLOCKS
+ * feature enabled if the stream has LARGE_BLOCKS. Same with
+ * large dnodes.
+ */
+ if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
+ return (SET_ERROR(ENOTSUP));
+ if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE))
+ return (SET_ERROR(ENOTSUP));
+
+ error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
+ if (error == 0) {
+ /* target fs already exists; recv into temp clone */
+
+ /* Can't recv a clone into an existing fs */
+ if (flags & DRR_FLAG_CLONE || drba->drba_origin) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+
+ error = recv_begin_check_existing_impl(drba, ds, fromguid);
+ dsl_dataset_rele(ds, FTAG);
+ } else if (error == ENOENT) {
+ /* target fs does not exist; must be a full backup or clone */
+ char buf[ZFS_MAX_DATASET_NAME_LEN];
+
+ /*
+ * If it's a non-clone incremental, we are missing the
+ * target fs, so fail the recv.
+ */
+ if (fromguid != 0 && !(flags & DRR_FLAG_CLONE ||
+ drba->drba_origin))
+ return (SET_ERROR(ENOENT));
+
+ /*
+ * If we're receiving a full send as a clone, and it doesn't
+ * contain all the necessary free records and freeobject
+ * records, reject it.
+ */
+ if (fromguid == 0 && drba->drba_origin &&
+ !(flags & DRR_FLAG_FREERECORDS))
+ return (SET_ERROR(EINVAL));
+
+ /* Open the parent of tofs */
+ ASSERT3U(strlen(tofs), <, sizeof (buf));
+ (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1);
+ error = dsl_dataset_hold(dp, buf, FTAG, &ds);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Check filesystem and snapshot limits before receiving. We'll
+ * recheck snapshot limits again at the end (we create the
+ * filesystems and increment those counts during begin_sync).
+ */
+ error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
+ ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred);
+ if (error != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (error);
+ }
+
+ error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
+ ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred);
+ if (error != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (error);
+ }
+
+ if (drba->drba_origin != NULL) {
+ dsl_dataset_t *origin;
+ error = dsl_dataset_hold(dp, drba->drba_origin,
+ FTAG, &origin);
+ if (error != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (error);
+ }
+ if (!origin->ds_is_snapshot) {
+ dsl_dataset_rele(origin, FTAG);
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+ if (dsl_dataset_phys(origin)->ds_guid != fromguid &&
+ fromguid != 0) {
+ dsl_dataset_rele(origin, FTAG);
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(ENODEV));
+ }
+ dsl_dataset_rele(origin, FTAG);
+ }
+ dsl_dataset_rele(ds, FTAG);
+ error = 0;
+ }
+ return (error);
+}
+
+static void
+dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
+{
+ dmu_recv_begin_arg_t *drba = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ objset_t *mos = dp->dp_meta_objset;
+ struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
+ const char *tofs = drba->drba_cookie->drc_tofs;
+ dsl_dataset_t *ds, *newds;
+ uint64_t dsobj;
+ int error;
+ uint64_t crflags = 0;
+
+ if (drrb->drr_flags & DRR_FLAG_CI_DATA)
+ crflags |= DS_FLAG_CI_DATASET;
+
+ error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
+ if (error == 0) {
+ /* create temporary clone */
+ dsl_dataset_t *snap = NULL;
+ if (drba->drba_snapobj != 0) {
+ VERIFY0(dsl_dataset_hold_obj(dp,
+ drba->drba_snapobj, FTAG, &snap));
+ }
+ dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
+ snap, crflags, drba->drba_cred, tx);
+ if (drba->drba_snapobj != 0)
+ dsl_dataset_rele(snap, FTAG);
+ dsl_dataset_rele(ds, FTAG);
+ } else {
+ dsl_dir_t *dd;
+ const char *tail;
+ dsl_dataset_t *origin = NULL;
+
+ VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail));
+
+ if (drba->drba_origin != NULL) {
+ VERIFY0(dsl_dataset_hold(dp, drba->drba_origin,
+ FTAG, &origin));
+ }
+
+ /* Create new dataset. */
+ dsobj = dsl_dataset_create_sync(dd,
+ strrchr(tofs, '/') + 1,
+ origin, crflags, drba->drba_cred, tx);
+ if (origin != NULL)
+ dsl_dataset_rele(origin, FTAG);
+ dsl_dir_rele(dd, FTAG);
+ drba->drba_cookie->drc_newfs = B_TRUE;
+ }
+ VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds));
+
+ if (drba->drba_cookie->drc_resumable) {
+ dsl_dataset_zapify(newds, tx);
+ if (drrb->drr_fromguid != 0) {
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_FROMGUID,
+ 8, 1, &drrb->drr_fromguid, tx));
+ }
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_TOGUID,
+ 8, 1, &drrb->drr_toguid, tx));
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_TONAME,
+ 1, strlen(drrb->drr_toname) + 1, drrb->drr_toname, tx));
+ uint64_t one = 1;
+ uint64_t zero = 0;
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_OBJECT,
+ 8, 1, &one, tx));
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_OFFSET,
+ 8, 1, &zero, tx));
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_BYTES,
+ 8, 1, &zero, tx));
+ if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+ DMU_BACKUP_FEATURE_LARGE_BLOCKS) {
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_LARGEBLOCK,
+ 8, 1, &one, tx));
+ }
+ if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+ DMU_BACKUP_FEATURE_EMBED_DATA) {
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_EMBEDOK,
+ 8, 1, &one, tx));
+ }
+ if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+ DMU_BACKUP_FEATURE_COMPRESSED) {
+ VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_COMPRESSOK,
+ 8, 1, &one, tx));
+ }
+ }
+
+ dmu_buf_will_dirty(newds->ds_dbuf, tx);
+ dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
+
+ /*
+ * If we actually created a non-clone, we need to create the
+ * objset in our new dataset.
+ */
+ rrw_enter(&newds->ds_bp_rwlock, RW_READER, FTAG);
+ if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) {
+ (void) dmu_objset_create_impl(dp->dp_spa,
+ newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx);
+ }
+ rrw_exit(&newds->ds_bp_rwlock, FTAG);
+
+ drba->drba_cookie->drc_ds = newds;
+
+ spa_history_log_internal_ds(newds, "receive", tx, "");
+}
+
+static int
+dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx)
+{
+ dmu_recv_begin_arg_t *drba = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
+ int error;
+ uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+ dsl_dataset_t *ds;
+ const char *tofs = drba->drba_cookie->drc_tofs;
+
+ /* 6 extra bytes for /%recv */
+ char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
+
+ /* already checked */
+ ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+ ASSERT(featureflags & DMU_BACKUP_FEATURE_RESUMING);
+
+ if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
+ DMU_COMPOUNDSTREAM ||
+ drrb->drr_type >= DMU_OST_NUMTYPES)
+ return (SET_ERROR(EINVAL));
+
+ /* Verify pool version supports SA if SA_SPILL feature set */
+ if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) &&
+ spa_version(dp->dp_spa) < SPA_VERSION_SA)
+ return (SET_ERROR(ENOTSUP));
+
+ /*
+ * The receiving code doesn't know how to translate a WRITE_EMBEDDED
+ * record to a plain WRITE record, so the pool must have the
+ * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED
+ * records. Same with WRITE_EMBEDDED records that use LZ4 compression.
+ */
+ if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA))
+ return (SET_ERROR(ENOTSUP));
+ if ((featureflags & DMU_BACKUP_FEATURE_LZ4) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
+ return (SET_ERROR(ENOTSUP));
+
+ /*
+ * The receiving code doesn't know how to translate large blocks
+ * to smaller ones, so the pool must have the LARGE_BLOCKS
+ * feature enabled if the stream has LARGE_BLOCKS. Same with
+ * large dnodes.
+ */
+ if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
+ return (SET_ERROR(ENOTSUP));
+ if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
+ !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE))
+ return (SET_ERROR(ENOTSUP));
+
+ (void) snprintf(recvname, sizeof (recvname), "%s/%s",
+ tofs, recv_clone_name);
+
+ if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) {
+ /* %recv does not exist; continue in tofs */
+ error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
+ if (error != 0)
+ return (error);
+ }
+
+ /* check that ds is marked inconsistent */
+ if (!DS_IS_INCONSISTENT(ds)) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+
+ /* check that there is resuming data, and that the toguid matches */
+ if (!dsl_dataset_is_zapified(ds)) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+ uint64_t val;
+ error = zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val);
+ if (error != 0 || drrb->drr_toguid != val) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+
+ /*
+ * Check if the receive is still running. If so, it will be owned.
+ * Note that nothing else can own the dataset (e.g. after the receive
+ * fails) because it will be marked inconsistent.
+ */
+ if (dsl_dataset_has_owner(ds)) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EBUSY));
+ }
+
+ /* There should not be any snapshots of this fs yet. */
+ if (ds->ds_prev != NULL && ds->ds_prev->ds_dir == ds->ds_dir) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+
+ /*
+ * Note: resume point will be checked when we process the first WRITE
+ * record.
+ */
+
+ /* check that the origin matches */
+ val = 0;
+ (void) zap_lookup(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val);
+ if (drrb->drr_fromguid != val) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+
+ dsl_dataset_rele(ds, FTAG);
+ return (0);
+}
+
+static void
+dmu_recv_resume_begin_sync(void *arg, dmu_tx_t *tx)
+{
+ dmu_recv_begin_arg_t *drba = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ const char *tofs = drba->drba_cookie->drc_tofs;
+ dsl_dataset_t *ds;
+ uint64_t dsobj;
+ /* 6 extra bytes for /%recv */
+ char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
+
+ (void) snprintf(recvname, sizeof (recvname), "%s/%s",
+ tofs, recv_clone_name);
+
+ if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) {
+ /* %recv does not exist; continue in tofs */
+ VERIFY0(dsl_dataset_hold(dp, tofs, FTAG, &ds));
+ drba->drba_cookie->drc_newfs = B_TRUE;
+ }
+
+ /* clear the inconsistent flag so that we can own it */
+ ASSERT(DS_IS_INCONSISTENT(ds));
+ dmu_buf_will_dirty(ds->ds_dbuf, tx);
+ dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
+ dsobj = ds->ds_object;
+ dsl_dataset_rele(ds, FTAG);
+
+ VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &ds));
+
+ dmu_buf_will_dirty(ds->ds_dbuf, tx);
+ dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT;
+
+ rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG);
+ ASSERT(!BP_IS_HOLE(dsl_dataset_get_blkptr(ds)));
+ rrw_exit(&ds->ds_bp_rwlock, FTAG);
+
+ drba->drba_cookie->drc_ds = ds;
+
+ spa_history_log_internal_ds(ds, "resume receive", tx, "");
+}
+
+/*
+ * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
+ * succeeds; otherwise we will leak the holds on the datasets.
+ */
+int
+dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin,
+ boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc)
+{
+ dmu_recv_begin_arg_t drba = { 0 };
+
+ bzero(drc, sizeof (dmu_recv_cookie_t));
+ drc->drc_drr_begin = drr_begin;
+ drc->drc_drrb = &drr_begin->drr_u.drr_begin;
+ drc->drc_tosnap = tosnap;
+ drc->drc_tofs = tofs;
+ drc->drc_force = force;
+ drc->drc_resumable = resumable;
+ drc->drc_cred = CRED();
+ drc->drc_clone = (origin != NULL);
+
+ if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
+ drc->drc_byteswap = B_TRUE;
+ (void) fletcher_4_incremental_byteswap(drr_begin,
+ sizeof (dmu_replay_record_t), &drc->drc_cksum);
+ byteswap_record(drr_begin);
+ } else if (drc->drc_drrb->drr_magic == DMU_BACKUP_MAGIC) {
+ (void) fletcher_4_incremental_native(drr_begin,
+ sizeof (dmu_replay_record_t), &drc->drc_cksum);
+ } else {
+ return (SET_ERROR(EINVAL));
+ }
+
+ drba.drba_origin = origin;
+ drba.drba_cookie = drc;
+ drba.drba_cred = CRED();
+
+ if (DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo) &
+ DMU_BACKUP_FEATURE_RESUMING) {
+ return (dsl_sync_task(tofs,
+ dmu_recv_resume_begin_check, dmu_recv_resume_begin_sync,
+ &drba, 5, ZFS_SPACE_CHECK_NORMAL));
+ } else {
+ return (dsl_sync_task(tofs,
+ dmu_recv_begin_check, dmu_recv_begin_sync,
+ &drba, 5, ZFS_SPACE_CHECK_NORMAL));
+ }
+}
+
+struct receive_record_arg {
+ dmu_replay_record_t header;
+ void *payload; /* Pointer to a buffer containing the payload */
+ /*
+ * If the record is a write, pointer to the arc_buf_t containing the
+ * payload.
+ */
+ arc_buf_t *write_buf;
+ int payload_size;
+ uint64_t bytes_read; /* bytes read from stream when record created */
+ boolean_t eos_marker; /* Marks the end of the stream */
+ bqueue_node_t node;
+};
+
+struct receive_writer_arg {
+ objset_t *os;
+ boolean_t byteswap;
+ bqueue_t q;
+
+ /*
+ * These three args are used to signal to the main thread that we're
+ * done.
+ */
+ kmutex_t mutex;
+ kcondvar_t cv;
+ boolean_t done;
+
+ int err;
+ /* A map from guid to dataset to help handle dedup'd streams. */
+ avl_tree_t *guid_to_ds_map;
+ boolean_t resumable;
+ uint64_t last_object;
+ uint64_t last_offset;
+ uint64_t max_object; /* highest object ID referenced in stream */
+ uint64_t bytes_read; /* bytes read when current record created */
+};
+
+struct objlist {
+ list_t list; /* List of struct receive_objnode. */
+ /*
+ * Last object looked up. Used to assert that objects are being looked
+ * up in ascending order.
+ */
+ uint64_t last_lookup;
+};
+
+struct receive_objnode {
+ list_node_t node;
+ uint64_t object;
+};
+
+struct receive_arg {
+ objset_t *os;
+ vnode_t *vp; /* The vnode to read the stream from */
+ uint64_t voff; /* The current offset in the stream */
+ uint64_t bytes_read;
+ /*
+ * A record that has had its payload read in, but hasn't yet been handed
+ * off to the worker thread.
+ */
+ struct receive_record_arg *rrd;
+ /* A record that has had its header read in, but not its payload. */
+ struct receive_record_arg *next_rrd;
+ zio_cksum_t cksum;
+ zio_cksum_t prev_cksum;
+ int err;
+ boolean_t byteswap;
+ /* Sorted list of objects not to issue prefetches for. */
+ struct objlist ignore_objlist;
+};
+
+typedef struct guid_map_entry {
+ uint64_t guid;
+ dsl_dataset_t *gme_ds;
+ avl_node_t avlnode;
+} guid_map_entry_t;
+
+static int
+guid_compare(const void *arg1, const void *arg2)
+{
+ const guid_map_entry_t *gmep1 = arg1;
+ const guid_map_entry_t *gmep2 = arg2;
+
+ if (gmep1->guid < gmep2->guid)
+ return (-1);
+ else if (gmep1->guid > gmep2->guid)
+ return (1);
+ return (0);
+}
+
+static void
+free_guid_map_onexit(void *arg)
+{
+ avl_tree_t *ca = arg;
+ void *cookie = NULL;
+ guid_map_entry_t *gmep;
+
+ while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) {
+ dsl_dataset_long_rele(gmep->gme_ds, gmep);
+ dsl_dataset_rele(gmep->gme_ds, gmep);
+ kmem_free(gmep, sizeof (guid_map_entry_t));
+ }
+ avl_destroy(ca);
+ kmem_free(ca, sizeof (avl_tree_t));
+}
+
+static int
+receive_read(struct receive_arg *ra, int len, void *buf)
+{
+ int done = 0;
+
+ /*
+ * The code doesn't rely on this (lengths being multiples of 8). See
+ * comment in dump_bytes.
+ */
+ ASSERT0(len % 8);
+
+ while (done < len) {
+ ssize_t resid;
+
+ ra->err = vn_rdwr(UIO_READ, ra->vp,
+ (char *)buf + done, len - done,
+ ra->voff, UIO_SYSSPACE, FAPPEND,
+ RLIM64_INFINITY, CRED(), &resid);
+
+ if (resid == len - done) {
+ /*
+ * Note: ECKSUM indicates that the receive
+ * was interrupted and can potentially be resumed.
+ */
+ ra->err = SET_ERROR(ECKSUM);
+ }
+ ra->voff += len - done - resid;
+ done = len - resid;
+ if (ra->err != 0)
+ return (ra->err);
+ }
+
+ ra->bytes_read += len;
+
+ ASSERT3U(done, ==, len);
+ return (0);
+}
+
+static void
+byteswap_record(dmu_replay_record_t *drr)
+{
+#define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
+#define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
+ drr->drr_type = BSWAP_32(drr->drr_type);
+ drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen);
+
+ switch (drr->drr_type) {
+ case DRR_BEGIN:
+ DO64(drr_begin.drr_magic);
+ DO64(drr_begin.drr_versioninfo);
+ DO64(drr_begin.drr_creation_time);
+ DO32(drr_begin.drr_type);
+ DO32(drr_begin.drr_flags);
+ DO64(drr_begin.drr_toguid);
+ DO64(drr_begin.drr_fromguid);
+ break;
+ case DRR_OBJECT:
+ DO64(drr_object.drr_object);
+ DO32(drr_object.drr_type);
+ DO32(drr_object.drr_bonustype);
+ DO32(drr_object.drr_blksz);
+ DO32(drr_object.drr_bonuslen);
+ DO64(drr_object.drr_toguid);
+ break;
+ case DRR_FREEOBJECTS:
+ DO64(drr_freeobjects.drr_firstobj);
+ DO64(drr_freeobjects.drr_numobjs);
+ DO64(drr_freeobjects.drr_toguid);
+ break;
+ case DRR_WRITE:
+ DO64(drr_write.drr_object);
+ DO32(drr_write.drr_type);
+ DO64(drr_write.drr_offset);
+ DO64(drr_write.drr_logical_size);
+ DO64(drr_write.drr_toguid);
+ ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_write.drr_key.ddk_cksum);
+ DO64(drr_write.drr_key.ddk_prop);
+ DO64(drr_write.drr_compressed_size);
+ break;
+ case DRR_WRITE_BYREF:
+ DO64(drr_write_byref.drr_object);
+ DO64(drr_write_byref.drr_offset);
+ DO64(drr_write_byref.drr_length);
+ DO64(drr_write_byref.drr_toguid);
+ DO64(drr_write_byref.drr_refguid);
+ DO64(drr_write_byref.drr_refobject);
+ DO64(drr_write_byref.drr_refoffset);
+ ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_write_byref.
+ drr_key.ddk_cksum);
+ DO64(drr_write_byref.drr_key.ddk_prop);
+ break;
+ case DRR_WRITE_EMBEDDED:
+ DO64(drr_write_embedded.drr_object);
+ DO64(drr_write_embedded.drr_offset);
+ DO64(drr_write_embedded.drr_length);
+ DO64(drr_write_embedded.drr_toguid);
+ DO32(drr_write_embedded.drr_lsize);
+ DO32(drr_write_embedded.drr_psize);
+ break;
+ case DRR_FREE:
+ DO64(drr_free.drr_object);
+ DO64(drr_free.drr_offset);
+ DO64(drr_free.drr_length);
+ DO64(drr_free.drr_toguid);
+ break;
+ case DRR_SPILL:
+ DO64(drr_spill.drr_object);
+ DO64(drr_spill.drr_length);
+ DO64(drr_spill.drr_toguid);
+ break;
+ case DRR_END:
+ DO64(drr_end.drr_toguid);
+ ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_end.drr_checksum);
+ break;
+ }
+
+ if (drr->drr_type != DRR_BEGIN) {
+ ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_checksum.drr_checksum);
+ }
+
+#undef DO64
+#undef DO32
+}
+
+static inline uint8_t
+deduce_nblkptr(dmu_object_type_t bonus_type, uint64_t bonus_size)
+{
+ if (bonus_type == DMU_OT_SA) {
+ return (1);
+ } else {
+ return (1 +
+ ((DN_OLD_MAX_BONUSLEN -
+ MIN(DN_OLD_MAX_BONUSLEN, bonus_size)) >> SPA_BLKPTRSHIFT));
+ }
+}
+
+static void
+save_resume_state(struct receive_writer_arg *rwa,
+ uint64_t object, uint64_t offset, dmu_tx_t *tx)
+{
+ int txgoff = dmu_tx_get_txg(tx) & TXG_MASK;
+
+ if (!rwa->resumable)
+ return;
+
+ /*
+ * We use ds_resume_bytes[] != 0 to indicate that we need to
+ * update this on disk, so it must not be 0.
+ */
+ ASSERT(rwa->bytes_read != 0);
+
+ /*
+ * We only resume from write records, which have a valid
+ * (non-meta-dnode) object number.
+ */
+ ASSERT(object != 0);
+
+ /*
+ * For resuming to work correctly, we must receive records in order,
+ * sorted by object,offset. This is checked by the callers, but
+ * assert it here for good measure.
+ */
+ ASSERT3U(object, >=, rwa->os->os_dsl_dataset->ds_resume_object[txgoff]);
+ ASSERT(object != rwa->os->os_dsl_dataset->ds_resume_object[txgoff] ||
+ offset >= rwa->os->os_dsl_dataset->ds_resume_offset[txgoff]);
+ ASSERT3U(rwa->bytes_read, >=,
+ rwa->os->os_dsl_dataset->ds_resume_bytes[txgoff]);
+
+ rwa->os->os_dsl_dataset->ds_resume_object[txgoff] = object;
+ rwa->os->os_dsl_dataset->ds_resume_offset[txgoff] = offset;
+ rwa->os->os_dsl_dataset->ds_resume_bytes[txgoff] = rwa->bytes_read;
+}
+
+static int
+receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
+ void *data)
+{
+ dmu_object_info_t doi;
+ dmu_tx_t *tx;
+ uint64_t object;
+ int err;
+ uint8_t dn_slots = drro->drr_dn_slots != 0 ?
+ drro->drr_dn_slots : DNODE_MIN_SLOTS;
+
+ if (drro->drr_type == DMU_OT_NONE ||
+ !DMU_OT_IS_VALID(drro->drr_type) ||
+ !DMU_OT_IS_VALID(drro->drr_bonustype) ||
+ drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS ||
+ drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS ||
+ P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) ||
+ drro->drr_blksz < SPA_MINBLOCKSIZE ||
+ drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(rwa->os)) ||
+ drro->drr_bonuslen >
+ DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os))) ||
+ dn_slots >
+ (spa_maxdnodesize(dmu_objset_spa(rwa->os)) >> DNODE_SHIFT)) {
+ return (SET_ERROR(EINVAL));
+ }
+
+ err = dmu_object_info(rwa->os, drro->drr_object, &doi);
+
+ if (err != 0 && err != ENOENT && err != EEXIST)
+ return (SET_ERROR(EINVAL));
+
+ if (drro->drr_object > rwa->max_object)
+ rwa->max_object = drro->drr_object;
+
+ /*
+ * If we are losing blkptrs or changing the block size this must
+ * be a new file instance. We must clear out the previous file
+ * contents before we can change this type of metadata in the dnode.
+ */
+ if (err == 0) {
+ int nblkptr;
+
+ object = drro->drr_object;
+
+ nblkptr = deduce_nblkptr(drro->drr_bonustype,
+ drro->drr_bonuslen);
+
+ if (drro->drr_blksz != doi.doi_data_block_size ||
+ nblkptr < doi.doi_nblkptr ||
+ dn_slots != doi.doi_dnodesize >> DNODE_SHIFT) {
+ err = dmu_free_long_range(rwa->os, drro->drr_object,
+ 0, DMU_OBJECT_END);
+ if (err != 0)
+ return (SET_ERROR(EINVAL));
+ }
+ } else if (err == EEXIST) {
+ /*
+ * The object requested is currently an interior slot of a
+ * multi-slot dnode. This will be resolved when the next txg
+ * is synced out, since the send stream will have told us
+ * to free this slot when we freed the associated dnode
+ * earlier in the stream.
+ */
+ txg_wait_synced(dmu_objset_pool(rwa->os), 0);
+ object = drro->drr_object;
+ } else {
+ /* object is free and we are about to allocate a new one */
+ object = DMU_NEW_OBJECT;
+ }
+
+ /*
+ * If this is a multi-slot dnode there is a chance that this
+ * object will expand into a slot that is already used by
+ * another object from the previous snapshot. We must free
+ * these objects before we attempt to allocate the new dnode.
+ */
+ if (dn_slots > 1) {
+ boolean_t need_sync = B_FALSE;
+
+ for (uint64_t slot = drro->drr_object + 1;
+ slot < drro->drr_object + dn_slots;
+ slot++) {
+ dmu_object_info_t slot_doi;
+
+ err = dmu_object_info(rwa->os, slot, &slot_doi);
+ if (err == ENOENT || err == EEXIST)
+ continue;
+ else if (err != 0)
+ return (err);
+
+ err = dmu_free_long_object(rwa->os, slot);
+
+ if (err != 0)
+ return (err);
+
+ need_sync = B_TRUE;
+ }
+
+ if (need_sync)
+ txg_wait_synced(dmu_objset_pool(rwa->os), 0);
+ }
+
+ tx = dmu_tx_create(rwa->os);
+ dmu_tx_hold_bonus(tx, object);
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err != 0) {
+ dmu_tx_abort(tx);
+ return (err);
+ }
+
+ if (object == DMU_NEW_OBJECT) {
+ /* currently free, want to be allocated */
+ err = dmu_object_claim_dnsize(rwa->os, drro->drr_object,
+ drro->drr_type, drro->drr_blksz,
+ drro->drr_bonustype, drro->drr_bonuslen,
+ dn_slots << DNODE_SHIFT, tx);
+ } else if (drro->drr_type != doi.doi_type ||
+ drro->drr_blksz != doi.doi_data_block_size ||
+ drro->drr_bonustype != doi.doi_bonus_type ||
+ drro->drr_bonuslen != doi.doi_bonus_size ||
+ drro->drr_dn_slots != (doi.doi_dnodesize >> DNODE_SHIFT)) {
+ /* currently allocated, but with different properties */
+ err = dmu_object_reclaim_dnsize(rwa->os, drro->drr_object,
+ drro->drr_type, drro->drr_blksz,
+ drro->drr_bonustype, drro->drr_bonuslen,
+ drro->drr_dn_slots << DNODE_SHIFT, tx);
+ }
+ if (err != 0) {
+ dmu_tx_commit(tx);
+ return (SET_ERROR(EINVAL));
+ }
+
+ dmu_object_set_checksum(rwa->os, drro->drr_object,
+ drro->drr_checksumtype, tx);
+ dmu_object_set_compress(rwa->os, drro->drr_object,
+ drro->drr_compress, tx);
+
+ if (data != NULL) {
+ dmu_buf_t *db;
+
+ VERIFY0(dmu_bonus_hold(rwa->os, drro->drr_object, FTAG, &db));
+ dmu_buf_will_dirty(db, tx);
+
+ ASSERT3U(db->db_size, >=, drro->drr_bonuslen);
+ bcopy(data, db->db_data, drro->drr_bonuslen);
+ if (rwa->byteswap) {
+ dmu_object_byteswap_t byteswap =
+ DMU_OT_BYTESWAP(drro->drr_bonustype);
+ dmu_ot_byteswap[byteswap].ob_func(db->db_data,
+ drro->drr_bonuslen);
+ }
+ dmu_buf_rele(db, FTAG);
+ }
+ dmu_tx_commit(tx);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+receive_freeobjects(struct receive_writer_arg *rwa,
+ struct drr_freeobjects *drrfo)
+{
+ uint64_t obj;
+ int next_err = 0;
+
+ if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj)
+ return (SET_ERROR(EINVAL));
+
+ for (obj = drrfo->drr_firstobj == 0 ? 1 : drrfo->drr_firstobj;
+ obj < drrfo->drr_firstobj + drrfo->drr_numobjs && next_err == 0;
+ next_err = dmu_object_next(rwa->os, &obj, FALSE, 0)) {
+ int err;
+
+ err = dmu_object_info(rwa->os, obj, NULL);
+ if (err == ENOENT)
+ continue;
+ else if (err != 0)
+ return (err);
+
+ err = dmu_free_long_object(rwa->os, obj);
+ if (err != 0)
+ return (err);
+
+ if (obj > rwa->max_object)
+ rwa->max_object = obj;
+ }
+ if (next_err != ESRCH)
+ return (next_err);
+ return (0);
+}
+
+static int
+receive_write(struct receive_writer_arg *rwa, struct drr_write *drrw,
+ arc_buf_t *abuf)
+{
+ dmu_tx_t *tx;
+ int err;
+
+ if (drrw->drr_offset + drrw->drr_logical_size < drrw->drr_offset ||
+ !DMU_OT_IS_VALID(drrw->drr_type))
+ return (SET_ERROR(EINVAL));
+
+ /*
+ * For resuming to work, records must be in increasing order
+ * by (object, offset).
+ */
+ if (drrw->drr_object < rwa->last_object ||
+ (drrw->drr_object == rwa->last_object &&
+ drrw->drr_offset < rwa->last_offset)) {
+ return (SET_ERROR(EINVAL));
+ }
+ rwa->last_object = drrw->drr_object;
+ rwa->last_offset = drrw->drr_offset;
+
+ if (rwa->last_object > rwa->max_object)
+ rwa->max_object = rwa->last_object;
+
+ if (dmu_object_info(rwa->os, drrw->drr_object, NULL) != 0)
+ return (SET_ERROR(EINVAL));
+
+ tx = dmu_tx_create(rwa->os);
+
+ dmu_tx_hold_write(tx, drrw->drr_object,
+ drrw->drr_offset, drrw->drr_logical_size);
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err != 0) {
+ dmu_tx_abort(tx);
+ return (err);
+ }
+ if (rwa->byteswap) {
+ dmu_object_byteswap_t byteswap =
+ DMU_OT_BYTESWAP(drrw->drr_type);
+ dmu_ot_byteswap[byteswap].ob_func(abuf->b_data,
+ DRR_WRITE_PAYLOAD_SIZE(drrw));
+ }
+
+ /* use the bonus buf to look up the dnode in dmu_assign_arcbuf */
+ dmu_buf_t *bonus;
+ if (dmu_bonus_hold(rwa->os, drrw->drr_object, FTAG, &bonus) != 0)
+ return (SET_ERROR(EINVAL));
+ dmu_assign_arcbuf(bonus, drrw->drr_offset, abuf, tx);
+
+ /*
+ * Note: If the receive fails, we want the resume stream to start
+ * with the same record that we last successfully received (as opposed
+ * to the next record), so that we can verify that we are
+ * resuming from the correct location.
+ */
+ save_resume_state(rwa, drrw->drr_object, drrw->drr_offset, tx);
+ dmu_tx_commit(tx);
+ dmu_buf_rele(bonus, FTAG);
+
+ return (0);
+}
+
+/*
+ * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed
+ * streams to refer to a copy of the data that is already on the
+ * system because it came in earlier in the stream. This function
+ * finds the earlier copy of the data, and uses that copy instead of
+ * data from the stream to fulfill this write.
+ */
+static int
+receive_write_byref(struct receive_writer_arg *rwa,
+ struct drr_write_byref *drrwbr)
+{
+ dmu_tx_t *tx;
+ int err;
+ guid_map_entry_t gmesrch;
+ guid_map_entry_t *gmep;
+ avl_index_t where;
+ objset_t *ref_os = NULL;
+ dmu_buf_t *dbp;
+
+ if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset)
+ return (SET_ERROR(EINVAL));
+
+ /*
+ * If the GUID of the referenced dataset is different from the
+ * GUID of the target dataset, find the referenced dataset.
+ */
+ if (drrwbr->drr_toguid != drrwbr->drr_refguid) {
+ gmesrch.guid = drrwbr->drr_refguid;
+ if ((gmep = avl_find(rwa->guid_to_ds_map, &gmesrch,
+ &where)) == NULL) {
+ return (SET_ERROR(EINVAL));
+ }
+ if (dmu_objset_from_ds(gmep->gme_ds, &ref_os))
+ return (SET_ERROR(EINVAL));
+ } else {
+ ref_os = rwa->os;
+ }
+
+ if (drrwbr->drr_object > rwa->max_object)
+ rwa->max_object = drrwbr->drr_object;
+
+ err = dmu_buf_hold(ref_os, drrwbr->drr_refobject,
+ drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH);
+ if (err != 0)
+ return (err);
+
+ tx = dmu_tx_create(rwa->os);
+
+ dmu_tx_hold_write(tx, drrwbr->drr_object,
+ drrwbr->drr_offset, drrwbr->drr_length);
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err != 0) {
+ dmu_tx_abort(tx);
+ return (err);
+ }
+ dmu_write(rwa->os, drrwbr->drr_object,
+ drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx);
+ dmu_buf_rele(dbp, FTAG);
+
+ /* See comment in restore_write. */
+ save_resume_state(rwa, drrwbr->drr_object, drrwbr->drr_offset, tx);
+ dmu_tx_commit(tx);
+ return (0);
+}
+
+static int
+receive_write_embedded(struct receive_writer_arg *rwa,
+ struct drr_write_embedded *drrwe, void *data)
+{
+ dmu_tx_t *tx;
+ int err;
+
+ if (drrwe->drr_offset + drrwe->drr_length < drrwe->drr_offset)
+ return (EINVAL);
+
+ if (drrwe->drr_psize > BPE_PAYLOAD_SIZE)
+ return (EINVAL);
+
+ if (drrwe->drr_etype >= NUM_BP_EMBEDDED_TYPES)
+ return (EINVAL);
+ if (drrwe->drr_compression >= ZIO_COMPRESS_FUNCTIONS)
+ return (EINVAL);
+
+ if (drrwe->drr_object > rwa->max_object)
+ rwa->max_object = drrwe->drr_object;
+
+ tx = dmu_tx_create(rwa->os);
+
+ dmu_tx_hold_write(tx, drrwe->drr_object,
+ drrwe->drr_offset, drrwe->drr_length);
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err != 0) {
+ dmu_tx_abort(tx);
+ return (err);
+ }
+
+ dmu_write_embedded(rwa->os, drrwe->drr_object,
+ drrwe->drr_offset, data, drrwe->drr_etype,
+ drrwe->drr_compression, drrwe->drr_lsize, drrwe->drr_psize,
+ rwa->byteswap ^ ZFS_HOST_BYTEORDER, tx);
+
+ /* See comment in restore_write. */
+ save_resume_state(rwa, drrwe->drr_object, drrwe->drr_offset, tx);
+ dmu_tx_commit(tx);
+ return (0);
+}
+
+static int
+receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
+ void *data)
+{
+ dmu_tx_t *tx;
+ dmu_buf_t *db, *db_spill;
+ int err;
+
+ if (drrs->drr_length < SPA_MINBLOCKSIZE ||
+ drrs->drr_length > spa_maxblocksize(dmu_objset_spa(rwa->os)))
+ return (SET_ERROR(EINVAL));
+
+ if (dmu_object_info(rwa->os, drrs->drr_object, NULL) != 0)
+ return (SET_ERROR(EINVAL));
+
+ if (drrs->drr_object > rwa->max_object)
+ rwa->max_object = drrs->drr_object;
+
+ VERIFY0(dmu_bonus_hold(rwa->os, drrs->drr_object, FTAG, &db));
+ if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) {
+ dmu_buf_rele(db, FTAG);
+ return (err);
+ }
+
+ tx = dmu_tx_create(rwa->os);
+
+ dmu_tx_hold_spill(tx, db->db_object);
+
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err != 0) {
+ dmu_buf_rele(db, FTAG);
+ dmu_buf_rele(db_spill, FTAG);
+ dmu_tx_abort(tx);
+ return (err);
+ }
+ dmu_buf_will_dirty(db_spill, tx);
+
+ if (db_spill->db_size < drrs->drr_length)
+ VERIFY(0 == dbuf_spill_set_blksz(db_spill,
+ drrs->drr_length, tx));
+ bcopy(data, db_spill->db_data, drrs->drr_length);
+
+ dmu_buf_rele(db, FTAG);
+ dmu_buf_rele(db_spill, FTAG);
+
+ dmu_tx_commit(tx);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+receive_free(struct receive_writer_arg *rwa, struct drr_free *drrf)
+{
+ int err;
+
+ if (drrf->drr_length != -1ULL &&
+ drrf->drr_offset + drrf->drr_length < drrf->drr_offset)
+ return (SET_ERROR(EINVAL));
+
+ if (dmu_object_info(rwa->os, drrf->drr_object, NULL) != 0)
+ return (SET_ERROR(EINVAL));
+
+ if (drrf->drr_object > rwa->max_object)
+ rwa->max_object = drrf->drr_object;
+
+ err = dmu_free_long_range(rwa->os, drrf->drr_object,
+ drrf->drr_offset, drrf->drr_length);
+
+ return (err);
+}
+
+/* used to destroy the drc_ds on error */
+static void
+dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc)
+{
+ if (drc->drc_resumable) {
+ /* wait for our resume state to be written to disk */
+ txg_wait_synced(drc->drc_ds->ds_dir->dd_pool, 0);
+ dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
+ } else {
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ dsl_dataset_name(drc->drc_ds, name);
+ dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
+ (void) dsl_destroy_head(name);
+ }
+}
+
+static void
+receive_cksum(struct receive_arg *ra, int len, void *buf)
+{
+ if (ra->byteswap) {
+ (void) fletcher_4_incremental_byteswap(buf, len, &ra->cksum);
+ } else {
+ (void) fletcher_4_incremental_native(buf, len, &ra->cksum);
+ }
+}
+
+/*
+ * Read the payload into a buffer of size len, and update the current record's
+ * payload field.
+ * Allocate ra->next_rrd and read the next record's header into
+ * ra->next_rrd->header.
+ * Verify checksum of payload and next record.
+ */
+static int
+receive_read_payload_and_next_header(struct receive_arg *ra, int len, void *buf)
+{
+ int err;
+
+ if (len != 0) {
+ ASSERT3U(len, <=, SPA_MAXBLOCKSIZE);
+ err = receive_read(ra, len, buf);
+ if (err != 0)
+ return (err);
+ receive_cksum(ra, len, buf);
+
+ /* note: rrd is NULL when reading the begin record's payload */
+ if (ra->rrd != NULL) {
+ ra->rrd->payload = buf;
+ ra->rrd->payload_size = len;
+ ra->rrd->bytes_read = ra->bytes_read;
+ }
+ }
+
+ ra->prev_cksum = ra->cksum;
+
+ ra->next_rrd = kmem_zalloc(sizeof (*ra->next_rrd), KM_SLEEP);
+ err = receive_read(ra, sizeof (ra->next_rrd->header),
+ &ra->next_rrd->header);
+ ra->next_rrd->bytes_read = ra->bytes_read;
+ if (err != 0) {
+ kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
+ ra->next_rrd = NULL;
+ return (err);
+ }
+ if (ra->next_rrd->header.drr_type == DRR_BEGIN) {
+ kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
+ ra->next_rrd = NULL;
+ return (SET_ERROR(EINVAL));
+ }
+
+ /*
+ * Note: checksum is of everything up to but not including the
+ * checksum itself.
+ */
+ ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+ ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+ receive_cksum(ra,
+ offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+ &ra->next_rrd->header);
+
+ zio_cksum_t cksum_orig =
+ ra->next_rrd->header.drr_u.drr_checksum.drr_checksum;
+ zio_cksum_t *cksump =
+ &ra->next_rrd->header.drr_u.drr_checksum.drr_checksum;
+
+ if (ra->byteswap)
+ byteswap_record(&ra->next_rrd->header);
+
+ if ((!ZIO_CHECKSUM_IS_ZERO(cksump)) &&
+ !ZIO_CHECKSUM_EQUAL(ra->cksum, *cksump)) {
+ kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
+ ra->next_rrd = NULL;
+ return (SET_ERROR(ECKSUM));
+ }
+
+ receive_cksum(ra, sizeof (cksum_orig), &cksum_orig);
+
+ return (0);
+}
+
+static void
+objlist_create(struct objlist *list)
+{
+ list_create(&list->list, sizeof (struct receive_objnode),
+ offsetof(struct receive_objnode, node));
+ list->last_lookup = 0;
+}
+
+static void
+objlist_destroy(struct objlist *list)
+{
+ for (struct receive_objnode *n = list_remove_head(&list->list);
+ n != NULL; n = list_remove_head(&list->list)) {
+ kmem_free(n, sizeof (*n));
+ }
+ list_destroy(&list->list);
+}
+
+/*
+ * This function looks through the objlist to see if the specified object number
+ * is contained in the objlist. In the process, it will remove all object
+ * numbers in the list that are smaller than the specified object number. Thus,
+ * any lookup of an object number smaller than a previously looked up object
+ * number will always return false; therefore, all lookups should be done in
+ * ascending order.
+ */
+static boolean_t
+objlist_exists(struct objlist *list, uint64_t object)
+{
+ struct receive_objnode *node = list_head(&list->list);
+ ASSERT3U(object, >=, list->last_lookup);
+ list->last_lookup = object;
+ while (node != NULL && node->object < object) {
+ VERIFY3P(node, ==, list_remove_head(&list->list));
+ kmem_free(node, sizeof (*node));
+ node = list_head(&list->list);
+ }
+ return (node != NULL && node->object == object);
+}
+
+/*
+ * The objlist is a list of object numbers stored in ascending order. However,
+ * the insertion of new object numbers does not seek out the correct location to
+ * store a new object number; instead, it appends it to the list for simplicity.
+ * Thus, any users must take care to only insert new object numbers in ascending
+ * order.
+ */
+static void
+objlist_insert(struct objlist *list, uint64_t object)
+{
+ struct receive_objnode *node = kmem_zalloc(sizeof (*node), KM_SLEEP);
+ node->object = object;
+#ifdef ZFS_DEBUG
+ struct receive_objnode *last_object = list_tail(&list->list);
+ uint64_t last_objnum = (last_object != NULL ? last_object->object : 0);
+ ASSERT3U(node->object, >, last_objnum);
+#endif
+ list_insert_tail(&list->list, node);
+}
+
+/*
+ * Issue the prefetch reads for any necessary indirect blocks.
+ *
+ * We use the object ignore list to tell us whether or not to issue prefetches
+ * for a given object. We do this for both correctness (in case the blocksize
+ * of an object has changed) and performance (if the object doesn't exist, don't
+ * needlessly try to issue prefetches). We also trim the list as we go through
+ * the stream to prevent it from growing to an unbounded size.
+ *
+ * The object numbers within will always be in sorted order, and any write
+ * records we see will also be in sorted order, but they're not sorted with
+ * respect to each other (i.e. we can get several object records before
+ * receiving each object's write records). As a result, once we've reached a
+ * given object number, we can safely remove any reference to lower object
+ * numbers in the ignore list. In practice, we receive up to 32 object records
+ * before receiving write records, so the list can have up to 32 nodes in it.
+ */
+/* ARGSUSED */
+static void
+receive_read_prefetch(struct receive_arg *ra,
+ uint64_t object, uint64_t offset, uint64_t length)
+{
+ if (!objlist_exists(&ra->ignore_objlist, object)) {
+ dmu_prefetch(ra->os, object, 1, offset, length,
+ ZIO_PRIORITY_SYNC_READ);
+ }
+}
+
+/*
+ * Read records off the stream, issuing any necessary prefetches.
+ */
+static int
+receive_read_record(struct receive_arg *ra)
+{
+ int err;
+
+ switch (ra->rrd->header.drr_type) {
+ case DRR_OBJECT:
+ {
+ struct drr_object *drro = &ra->rrd->header.drr_u.drr_object;
+ uint32_t size = P2ROUNDUP(drro->drr_bonuslen, 8);
+ void *buf = NULL;
+ dmu_object_info_t doi;
+
+ if (size > 0)
+ buf = kmem_zalloc(size, KM_SLEEP);
+
+ err = receive_read_payload_and_next_header(ra, size, buf);
+ if (err != 0) {
+ kmem_free(buf, size);
+ return (err);
+ }
+ err = dmu_object_info(ra->os, drro->drr_object, &doi);
+ /*
+ * See receive_read_prefetch for an explanation why we're
+ * storing this object in the ignore_obj_list.
+ */
+ if (err == ENOENT ||
+ (err == 0 && doi.doi_data_block_size != drro->drr_blksz)) {
+ objlist_insert(&ra->ignore_objlist, drro->drr_object);
+ err = 0;
+ }
+ return (err);
+ }
+ case DRR_FREEOBJECTS:
+ {
+ err = receive_read_payload_and_next_header(ra, 0, NULL);
+ return (err);
+ }
+ case DRR_WRITE:
+ {
+ struct drr_write *drrw = &ra->rrd->header.drr_u.drr_write;
+ arc_buf_t *abuf;
+ boolean_t is_meta = DMU_OT_IS_METADATA(drrw->drr_type);
+ if (DRR_WRITE_COMPRESSED(drrw)) {
+ ASSERT3U(drrw->drr_compressed_size, >, 0);
+ ASSERT3U(drrw->drr_logical_size, >=,
+ drrw->drr_compressed_size);
+ ASSERT(!is_meta);
+ abuf = arc_loan_compressed_buf(
+ dmu_objset_spa(ra->os),
+ drrw->drr_compressed_size, drrw->drr_logical_size,
+ drrw->drr_compressiontype);
+ } else {
+ abuf = arc_loan_buf(dmu_objset_spa(ra->os),
+ is_meta, drrw->drr_logical_size);
+ }
+
+ err = receive_read_payload_and_next_header(ra,
+ DRR_WRITE_PAYLOAD_SIZE(drrw), abuf->b_data);
+ if (err != 0) {
+ dmu_return_arcbuf(abuf);
+ return (err);
+ }
+ ra->rrd->write_buf = abuf;
+ receive_read_prefetch(ra, drrw->drr_object, drrw->drr_offset,
+ drrw->drr_logical_size);
+ return (err);
+ }
+ case DRR_WRITE_BYREF:
+ {
+ struct drr_write_byref *drrwb =
+ &ra->rrd->header.drr_u.drr_write_byref;
+ err = receive_read_payload_and_next_header(ra, 0, NULL);
+ receive_read_prefetch(ra, drrwb->drr_object, drrwb->drr_offset,
+ drrwb->drr_length);
+ return (err);
+ }
+ case DRR_WRITE_EMBEDDED:
+ {
+ struct drr_write_embedded *drrwe =
+ &ra->rrd->header.drr_u.drr_write_embedded;
+ uint32_t size = P2ROUNDUP(drrwe->drr_psize, 8);
+ void *buf = kmem_zalloc(size, KM_SLEEP);
+
+ err = receive_read_payload_and_next_header(ra, size, buf);
+ if (err != 0) {
+ kmem_free(buf, size);
+ return (err);
+ }
+
+ receive_read_prefetch(ra, drrwe->drr_object, drrwe->drr_offset,
+ drrwe->drr_length);
+ return (err);
+ }
+ case DRR_FREE:
+ {
+ /*
+ * It might be beneficial to prefetch indirect blocks here, but
+ * we don't really have the data to decide for sure.
+ */
+ err = receive_read_payload_and_next_header(ra, 0, NULL);
+ return (err);
+ }
+ case DRR_END:
+ {
+ struct drr_end *drre = &ra->rrd->header.drr_u.drr_end;
+ if (!ZIO_CHECKSUM_EQUAL(ra->prev_cksum, drre->drr_checksum))
+ return (SET_ERROR(ECKSUM));
+ return (0);
+ }
+ case DRR_SPILL:
+ {
+ struct drr_spill *drrs = &ra->rrd->header.drr_u.drr_spill;
+ void *buf = kmem_zalloc(drrs->drr_length, KM_SLEEP);
+ err = receive_read_payload_and_next_header(ra, drrs->drr_length,
+ buf);
+ if (err != 0)
+ kmem_free(buf, drrs->drr_length);
+ return (err);
+ }
+ default:
+ return (SET_ERROR(EINVAL));
+ }
+}
+
+/*
+ * Commit the records to the pool.
+ */
+static int
+receive_process_record(struct receive_writer_arg *rwa,
+ struct receive_record_arg *rrd)
+{
+ int err;
+
+ /* Processing in order, therefore bytes_read should be increasing. */
+ ASSERT3U(rrd->bytes_read, >=, rwa->bytes_read);
+ rwa->bytes_read = rrd->bytes_read;
+
+ switch (rrd->header.drr_type) {
+ case DRR_OBJECT:
+ {
+ struct drr_object *drro = &rrd->header.drr_u.drr_object;
+ err = receive_object(rwa, drro, rrd->payload);
+ kmem_free(rrd->payload, rrd->payload_size);
+ rrd->payload = NULL;
+ return (err);
+ }
+ case DRR_FREEOBJECTS:
+ {
+ struct drr_freeobjects *drrfo =
+ &rrd->header.drr_u.drr_freeobjects;
+ return (receive_freeobjects(rwa, drrfo));
+ }
+ case DRR_WRITE:
+ {
+ struct drr_write *drrw = &rrd->header.drr_u.drr_write;
+ err = receive_write(rwa, drrw, rrd->write_buf);
+ /* if receive_write() is successful, it consumes the arc_buf */
+ if (err != 0)
+ dmu_return_arcbuf(rrd->write_buf);
+ rrd->write_buf = NULL;
+ rrd->payload = NULL;
+ return (err);
+ }
+ case DRR_WRITE_BYREF:
+ {
+ struct drr_write_byref *drrwbr =
+ &rrd->header.drr_u.drr_write_byref;
+ return (receive_write_byref(rwa, drrwbr));
+ }
+ case DRR_WRITE_EMBEDDED:
+ {
+ struct drr_write_embedded *drrwe =
+ &rrd->header.drr_u.drr_write_embedded;
+ err = receive_write_embedded(rwa, drrwe, rrd->payload);
+ kmem_free(rrd->payload, rrd->payload_size);
+ rrd->payload = NULL;
+ return (err);
+ }
+ case DRR_FREE:
+ {
+ struct drr_free *drrf = &rrd->header.drr_u.drr_free;
+ return (receive_free(rwa, drrf));
+ }
+ case DRR_SPILL:
+ {
+ struct drr_spill *drrs = &rrd->header.drr_u.drr_spill;
+ err = receive_spill(rwa, drrs, rrd->payload);
+ kmem_free(rrd->payload, rrd->payload_size);
+ rrd->payload = NULL;
+ return (err);
+ }
+ default:
+ return (SET_ERROR(EINVAL));
+ }
+}
+
+/*
+ * dmu_recv_stream's worker thread; pull records off the queue, and then call
+ * receive_process_record When we're done, signal the main thread and exit.
+ */
+static void
+receive_writer_thread(void *arg)
+{
+ struct receive_writer_arg *rwa = arg;
+ struct receive_record_arg *rrd;
+ for (rrd = bqueue_dequeue(&rwa->q); !rrd->eos_marker;
+ rrd = bqueue_dequeue(&rwa->q)) {
+ /*
+ * If there's an error, the main thread will stop putting things
+ * on the queue, but we need to clear everything in it before we
+ * can exit.
+ */
+ if (rwa->err == 0) {
+ rwa->err = receive_process_record(rwa, rrd);
+ } else if (rrd->write_buf != NULL) {
+ dmu_return_arcbuf(rrd->write_buf);
+ rrd->write_buf = NULL;
+ rrd->payload = NULL;
+ } else if (rrd->payload != NULL) {
+ kmem_free(rrd->payload, rrd->payload_size);
+ rrd->payload = NULL;
+ }
+ kmem_free(rrd, sizeof (*rrd));
+ }
+ kmem_free(rrd, sizeof (*rrd));
+ mutex_enter(&rwa->mutex);
+ rwa->done = B_TRUE;
+ cv_signal(&rwa->cv);
+ mutex_exit(&rwa->mutex);
+ thread_exit();
+}
+
+static int
+resume_check(struct receive_arg *ra, nvlist_t *begin_nvl)
+{
+ uint64_t val;
+ objset_t *mos = dmu_objset_pool(ra->os)->dp_meta_objset;
+ uint64_t dsobj = dmu_objset_id(ra->os);
+ uint64_t resume_obj, resume_off;
+
+ if (nvlist_lookup_uint64(begin_nvl,
+ "resume_object", &resume_obj) != 0 ||
+ nvlist_lookup_uint64(begin_nvl,
+ "resume_offset", &resume_off) != 0) {
+ return (SET_ERROR(EINVAL));
+ }
+ VERIFY0(zap_lookup(mos, dsobj,
+ DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val));
+ if (resume_obj != val)
+ return (SET_ERROR(EINVAL));
+ VERIFY0(zap_lookup(mos, dsobj,
+ DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val));
+ if (resume_off != val)
+ return (SET_ERROR(EINVAL));
+
+ return (0);
+}
+
+/*
+ * Read in the stream's records, one by one, and apply them to the pool. There
+ * are two threads involved; the thread that calls this function will spin up a
+ * worker thread, read the records off the stream one by one, and issue
+ * prefetches for any necessary indirect blocks. It will then push the records
+ * onto an internal blocking queue. The worker thread will pull the records off
+ * the queue, and actually write the data into the DMU. This way, the worker
+ * thread doesn't have to wait for reads to complete, since everything it needs
+ * (the indirect blocks) will be prefetched.
+ *
+ * NB: callers *must* call dmu_recv_end() if this succeeds.
+ */
+int
+dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
+ int cleanup_fd, uint64_t *action_handlep)
+{
+ int err = 0;
+ struct receive_arg ra = { 0 };
+ struct receive_writer_arg rwa = { 0 };
+ int featureflags;
+ nvlist_t *begin_nvl = NULL;
+
+ ra.byteswap = drc->drc_byteswap;
+ ra.cksum = drc->drc_cksum;
+ ra.vp = vp;
+ ra.voff = *voffp;
+
+ if (dsl_dataset_is_zapified(drc->drc_ds)) {
+ (void) zap_lookup(drc->drc_ds->ds_dir->dd_pool->dp_meta_objset,
+ drc->drc_ds->ds_object, DS_FIELD_RESUME_BYTES,
+ sizeof (ra.bytes_read), 1, &ra.bytes_read);
+ }
+
+ objlist_create(&ra.ignore_objlist);
+
+ /* these were verified in dmu_recv_begin */
+ ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==,
+ DMU_SUBSTREAM);
+ ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES);
+
+ /*
+ * Open the objset we are modifying.
+ */
+ VERIFY0(dmu_objset_from_ds(drc->drc_ds, &ra.os));
+
+ ASSERT(dsl_dataset_phys(drc->drc_ds)->ds_flags & DS_FLAG_INCONSISTENT);
+
+ featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo);
+
+ /* if this stream is dedup'ed, set up the avl tree for guid mapping */
+ if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {
+ minor_t minor;
+
+ if (cleanup_fd == -1) {
+ ra.err = SET_ERROR(EBADF);
+ goto out;
+ }
+ ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor);
+ if (ra.err != 0) {
+ cleanup_fd = -1;
+ goto out;
+ }
+
+ if (*action_handlep == 0) {
+ rwa.guid_to_ds_map =
+ kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
+ avl_create(rwa.guid_to_ds_map, guid_compare,
+ sizeof (guid_map_entry_t),
+ offsetof(guid_map_entry_t, avlnode));
+ err = zfs_onexit_add_cb(minor,
+ free_guid_map_onexit, rwa.guid_to_ds_map,
+ action_handlep);
+ if (ra.err != 0)
+ goto out;
+ } else {
+ err = zfs_onexit_cb_data(minor, *action_handlep,
+ (void **)&rwa.guid_to_ds_map);
+ if (ra.err != 0)
+ goto out;
+ }
+
+ drc->drc_guid_to_ds_map = rwa.guid_to_ds_map;
+ }
+
+ uint32_t payloadlen = drc->drc_drr_begin->drr_payloadlen;
+ void *payload = NULL;
+ if (payloadlen != 0)
+ payload = kmem_alloc(payloadlen, KM_SLEEP);
+
+ err = receive_read_payload_and_next_header(&ra, payloadlen, payload);
+ if (err != 0) {
+ if (payloadlen != 0)
+ kmem_free(payload, payloadlen);
+ goto out;
+ }
+ if (payloadlen != 0) {
+ err = nvlist_unpack(payload, payloadlen, &begin_nvl, KM_SLEEP);
+ kmem_free(payload, payloadlen);
+ if (err != 0)
+ goto out;
+ }
+
+ if (featureflags & DMU_BACKUP_FEATURE_RESUMING) {
+ err = resume_check(&ra, begin_nvl);
+ if (err != 0)
+ goto out;
+ }
+
+ (void) bqueue_init(&rwa.q, zfs_recv_queue_length,
+ offsetof(struct receive_record_arg, node));
+ cv_init(&rwa.cv, NULL, CV_DEFAULT, NULL);
+ mutex_init(&rwa.mutex, NULL, MUTEX_DEFAULT, NULL);
+ rwa.os = ra.os;
+ rwa.byteswap = drc->drc_byteswap;
+ rwa.resumable = drc->drc_resumable;
+
+ (void) thread_create(NULL, 0, receive_writer_thread, &rwa, 0, curproc,
+ TS_RUN, minclsyspri);
+ /*
+ * We're reading rwa.err without locks, which is safe since we are the
+ * only reader, and the worker thread is the only writer. It's ok if we
+ * miss a write for an iteration or two of the loop, since the writer
+ * thread will keep freeing records we send it until we send it an eos
+ * marker.
+ *
+ * We can leave this loop in 3 ways: First, if rwa.err is
+ * non-zero. In that case, the writer thread will free the rrd we just
+ * pushed. Second, if we're interrupted; in that case, either it's the
+ * first loop and ra.rrd was never allocated, or it's later, and ra.rrd
+ * has been handed off to the writer thread who will free it. Finally,
+ * if receive_read_record fails or we're at the end of the stream, then
+ * we free ra.rrd and exit.
+ */
+ while (rwa.err == 0) {
+ if (issig(JUSTLOOKING) && issig(FORREAL)) {
+ err = SET_ERROR(EINTR);
+ break;
+ }
+
+ ASSERT3P(ra.rrd, ==, NULL);
+ ra.rrd = ra.next_rrd;
+ ra.next_rrd = NULL;
+ /* Allocates and loads header into ra.next_rrd */
+ err = receive_read_record(&ra);
+
+ if (ra.rrd->header.drr_type == DRR_END || err != 0) {
+ kmem_free(ra.rrd, sizeof (*ra.rrd));
+ ra.rrd = NULL;
+ break;
+ }
+
+ bqueue_enqueue(&rwa.q, ra.rrd,
+ sizeof (struct receive_record_arg) + ra.rrd->payload_size);
+ ra.rrd = NULL;
+ }
+ if (ra.next_rrd == NULL)
+ ra.next_rrd = kmem_zalloc(sizeof (*ra.next_rrd), KM_SLEEP);
+ ra.next_rrd->eos_marker = B_TRUE;
+ bqueue_enqueue(&rwa.q, ra.next_rrd, 1);
+
+ mutex_enter(&rwa.mutex);
+ while (!rwa.done) {
+ cv_wait(&rwa.cv, &rwa.mutex);
+ }
+ mutex_exit(&rwa.mutex);
+
+ /*
+ * If we are receiving a full stream as a clone, all object IDs which
+ * are greater than the maximum ID referenced in the stream are
+ * by definition unused and must be freed. Note that it's possible that
+ * we've resumed this send and the first record we received was the END
+ * record. In that case, max_object would be 0, but we shouldn't start
+ * freeing all objects from there; instead we should start from the
+ * resumeobj.
+ */
+ if (drc->drc_clone && drc->drc_drrb->drr_fromguid == 0) {
+ uint64_t obj;
+ if (nvlist_lookup_uint64(begin_nvl, "resume_object", &obj) != 0)
+ obj = 0;
+ if (rwa.max_object > obj)
+ obj = rwa.max_object;
+ obj++;
+ int free_err = 0;
+ int next_err = 0;
+
+ while (next_err == 0) {
+ free_err = dmu_free_long_object(rwa.os, obj);
+ if (free_err != 0 && free_err != ENOENT)
+ break;
+
+ next_err = dmu_object_next(rwa.os, &obj, FALSE, 0);
+ }
+
+ if (err == 0) {
+ if (free_err != 0 && free_err != ENOENT)
+ err = free_err;
+ else if (next_err != ESRCH)
+ err = next_err;
+ }
+ }
+
+ cv_destroy(&rwa.cv);
+ mutex_destroy(&rwa.mutex);
+ bqueue_destroy(&rwa.q);
+ if (err == 0)
+ err = rwa.err;
+
+out:
+ nvlist_free(begin_nvl);
+ if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1))
+ zfs_onexit_fd_rele(cleanup_fd);
+
+ if (err != 0) {
+ /*
+ * Clean up references. If receive is not resumable,
+ * destroy what we created, so we don't leave it in
+ * the inconsistent state.
+ */
+ dmu_recv_cleanup_ds(drc);
+ }
+
+ *voffp = ra.voff;
+ objlist_destroy(&ra.ignore_objlist);
+ return (err);
+}
+
+static int
+dmu_recv_end_check(void *arg, dmu_tx_t *tx)
+{
+ dmu_recv_cookie_t *drc = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ int error;
+
+ ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag);
+
+ if (!drc->drc_newfs) {
+ dsl_dataset_t *origin_head;
+
+ error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
+ if (error != 0)
+ return (error);
+ if (drc->drc_force) {
+ /*
+ * We will destroy any snapshots in tofs (i.e. before
+ * origin_head) that are after the origin (which is
+ * the snap before drc_ds, because drc_ds can not
+ * have any snaps of its own).
+ */
+ uint64_t obj;
+
+ obj = dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
+ while (obj !=
+ dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj) {
+ dsl_dataset_t *snap;
+ error = dsl_dataset_hold_obj(dp, obj, FTAG,
+ &snap);
+ if (error != 0)
+ break;
+ if (snap->ds_dir != origin_head->ds_dir)
+ error = SET_ERROR(EINVAL);
+ if (error == 0) {
+ error = dsl_destroy_snapshot_check_impl(
+ snap, B_FALSE);
+ }
+ obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
+ dsl_dataset_rele(snap, FTAG);
+ if (error != 0)
+ break;
+ }
+ if (error != 0) {
+ dsl_dataset_rele(origin_head, FTAG);
+ return (error);
+ }
+ }
+ error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
+ origin_head, drc->drc_force, drc->drc_owner, tx);
+ if (error != 0) {
+ dsl_dataset_rele(origin_head, FTAG);
+ return (error);
+ }
+ error = dsl_dataset_snapshot_check_impl(origin_head,
+ drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+ dsl_dataset_rele(origin_head, FTAG);
+ if (error != 0)
+ return (error);
+
+ error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
+ } else {
+ error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
+ drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+ }
+ return (error);
+}
+
+static void
+dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
+{
+ dmu_recv_cookie_t *drc = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+
+ spa_history_log_internal_ds(drc->drc_ds, "finish receiving",
+ tx, "snap=%s", drc->drc_tosnap);
+
+ if (!drc->drc_newfs) {
+ dsl_dataset_t *origin_head;
+
+ VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
+ &origin_head));
+
+ if (drc->drc_force) {
+ /*
+ * Destroy any snapshots of drc_tofs (origin_head)
+ * after the origin (the snap before drc_ds).
+ */
+ uint64_t obj;
+
+ obj = dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
+ while (obj !=
+ dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj) {
+ dsl_dataset_t *snap;
+ VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG,
+ &snap));
+ ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir);
+ obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
+ dsl_destroy_snapshot_sync_impl(snap,
+ B_FALSE, tx);
+ dsl_dataset_rele(snap, FTAG);
+ }
+ }
+ VERIFY3P(drc->drc_ds->ds_prev, ==,
+ origin_head->ds_prev);
+
+ dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
+ origin_head, tx);
+ dsl_dataset_snapshot_sync_impl(origin_head,
+ drc->drc_tosnap, tx);
+
+ /* set snapshot's creation time and guid */
+ dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx);
+ dsl_dataset_phys(origin_head->ds_prev)->ds_creation_time =
+ drc->drc_drrb->drr_creation_time;
+ dsl_dataset_phys(origin_head->ds_prev)->ds_guid =
+ drc->drc_drrb->drr_toguid;
+ dsl_dataset_phys(origin_head->ds_prev)->ds_flags &=
+ ~DS_FLAG_INCONSISTENT;
+
+ dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
+ dsl_dataset_phys(origin_head)->ds_flags &=
+ ~DS_FLAG_INCONSISTENT;
+
+ drc->drc_newsnapobj =
+ dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
+
+ dsl_dataset_rele(origin_head, FTAG);
+ dsl_destroy_head_sync_impl(drc->drc_ds, tx);
+
+ if (drc->drc_owner != NULL)
+ VERIFY3P(origin_head->ds_owner, ==, drc->drc_owner);
+ } else {
+ dsl_dataset_t *ds = drc->drc_ds;
+
+ dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx);
+
+ /* set snapshot's creation time and guid */
+ dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
+ dsl_dataset_phys(ds->ds_prev)->ds_creation_time =
+ drc->drc_drrb->drr_creation_time;
+ dsl_dataset_phys(ds->ds_prev)->ds_guid =
+ drc->drc_drrb->drr_toguid;
+ dsl_dataset_phys(ds->ds_prev)->ds_flags &=
+ ~DS_FLAG_INCONSISTENT;
+
+ dmu_buf_will_dirty(ds->ds_dbuf, tx);
+ dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
+ if (dsl_dataset_has_resume_receive_state(ds)) {
+ (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_FROMGUID, tx);
+ (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_OBJECT, tx);
+ (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_OFFSET, tx);
+ (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_BYTES, tx);
+ (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_TOGUID, tx);
+ (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+ DS_FIELD_RESUME_TONAME, tx);
+ }
+ drc->drc_newsnapobj =
+ dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
+ }
+ /*
+ * Release the hold from dmu_recv_begin. This must be done before
+ * we return to open context, so that when we free the dataset's dnode,
+ * we can evict its bonus buffer.
+ */
+ dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
+ drc->drc_ds = NULL;
+}
+
+static int
+add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj)
+{
+ dsl_pool_t *dp;
+ dsl_dataset_t *snapds;
+ guid_map_entry_t *gmep;
+ int err;
+
+ ASSERT(guid_map != NULL);
+
+ err = dsl_pool_hold(name, FTAG, &dp);
+ if (err != 0)
+ return (err);
+ gmep = kmem_alloc(sizeof (*gmep), KM_SLEEP);
+ err = dsl_dataset_hold_obj(dp, snapobj, gmep, &snapds);
+ if (err == 0) {
+ gmep->guid = dsl_dataset_phys(snapds)->ds_guid;
+ gmep->gme_ds = snapds;
+ avl_add(guid_map, gmep);
+ dsl_dataset_long_hold(snapds, gmep);
+ } else {
+ kmem_free(gmep, sizeof (*gmep));
+ }
+
+ dsl_pool_rele(dp, FTAG);
+ return (err);
+}
+
+static int dmu_recv_end_modified_blocks = 3;
+
+static int
+dmu_recv_existing_end(dmu_recv_cookie_t *drc)
+{
+#ifdef _KERNEL
+ /*
+ * We will be destroying the ds; make sure its origin is unmounted if
+ * necessary.
+ */
+ char name[ZFS_MAX_DATASET_NAME_LEN];
+ dsl_dataset_name(drc->drc_ds, name);
+ zfs_destroy_unmount_origin(name);
+#endif
+
+ return (dsl_sync_task(drc->drc_tofs,
+ dmu_recv_end_check, dmu_recv_end_sync, drc,
+ dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
+}
+
+static int
+dmu_recv_new_end(dmu_recv_cookie_t *drc)
+{
+ return (dsl_sync_task(drc->drc_tofs,
+ dmu_recv_end_check, dmu_recv_end_sync, drc,
+ dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
+}
+
+int
+dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
+{
+ int error;
+
+ drc->drc_owner = owner;
+
+ if (drc->drc_newfs)
+ error = dmu_recv_new_end(drc);
+ else
+ error = dmu_recv_existing_end(drc);
+
+ if (error != 0) {
+ dmu_recv_cleanup_ds(drc);
+ } else if (drc->drc_guid_to_ds_map != NULL) {
+ (void) add_ds_to_guidmap(drc->drc_tofs,
+ drc->drc_guid_to_ds_map,
+ drc->drc_newsnapobj);
+ }
+ return (error);
+}
+
+/*
+ * Return TRUE if this objset is currently being received into.
+ */
+boolean_t
+dmu_objset_is_receiving(objset_t *os)
+{
+ return (os->os_dsl_dataset != NULL &&
+ os->os_dsl_dataset->ds_owner == dmu_recv_tag);
+}
diff --git a/usr/src/uts/common/fs/zfs/dmu_send.c b/usr/src/uts/common/fs/zfs/dmu_send.c
index 81de2970b2..d42a7c66de 100644
--- a/usr/src/uts/common/fs/zfs/dmu_send.c
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c
@@ -59,13 +59,9 @@
/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
int zfs_send_corrupt_data = B_FALSE;
int zfs_send_queue_length = 16 * 1024 * 1024;
-int zfs_recv_queue_length = 16 * 1024 * 1024;
/* Set this tunable to FALSE to disable setting of DRR_FLAG_FREERECORDS */
int zfs_send_set_freerecords_bit = B_TRUE;
-static char *dmu_recv_tag = "dmu_recv_tag";
-const char *recv_clone_name = "%recv";
-
/*
* Use this to override the recordsize calculation for fast zfs send estimates.
*/
@@ -75,8 +71,6 @@ uint64_t zfs_override_estimate_recordsize = 0;
(((uint64_t)datablkszsec) << (SPA_MINBLOCKSHIFT + \
(level) * (indblkshift - SPA_BLKPTRSHIFT)))
-static void byteswap_record(dmu_replay_record_t *drr);
-
struct send_thread_arg {
bqueue_t q;
dsl_dataset_t *ds; /* Dataset to traverse */
@@ -1257,2203 +1251,3 @@ dmu_send_estimate_from_txg(dsl_dataset_t *ds, uint64_t from_txg,
size.compressed, stream_compressed, sizep);
return (err);
}
-
-typedef struct dmu_recv_begin_arg {
- const char *drba_origin;
- dmu_recv_cookie_t *drba_cookie;
- cred_t *drba_cred;
- uint64_t drba_snapobj;
-} dmu_recv_begin_arg_t;
-
-static int
-recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
- uint64_t fromguid)
-{
- uint64_t val;
- int error;
- dsl_pool_t *dp = ds->ds_dir->dd_pool;
-
- /* temporary clone name must not exist */
- error = zap_lookup(dp->dp_meta_objset,
- dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, recv_clone_name,
- 8, 1, &val);
- if (error != ENOENT)
- return (error == 0 ? EBUSY : error);
-
- /* new snapshot name must not exist */
- error = zap_lookup(dp->dp_meta_objset,
- dsl_dataset_phys(ds)->ds_snapnames_zapobj,
- drba->drba_cookie->drc_tosnap, 8, 1, &val);
- if (error != ENOENT)
- return (error == 0 ? EEXIST : error);
-
- /*
- * Check snapshot limit before receiving. We'll recheck again at the
- * end, but might as well abort before receiving if we're already over
- * the limit.
- *
- * Note that we do not check the file system limit with
- * dsl_dir_fscount_check because the temporary %clones don't count
- * against that limit.
- */
- error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT,
- NULL, drba->drba_cred);
- if (error != 0)
- return (error);
-
- if (fromguid != 0) {
- dsl_dataset_t *snap;
- uint64_t obj = dsl_dataset_phys(ds)->ds_prev_snap_obj;
-
- /* Find snapshot in this dir that matches fromguid. */
- while (obj != 0) {
- error = dsl_dataset_hold_obj(dp, obj, FTAG,
- &snap);
- if (error != 0)
- return (SET_ERROR(ENODEV));
- if (snap->ds_dir != ds->ds_dir) {
- dsl_dataset_rele(snap, FTAG);
- return (SET_ERROR(ENODEV));
- }
- if (dsl_dataset_phys(snap)->ds_guid == fromguid)
- break;
- obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
- dsl_dataset_rele(snap, FTAG);
- }
- if (obj == 0)
- return (SET_ERROR(ENODEV));
-
- if (drba->drba_cookie->drc_force) {
- drba->drba_snapobj = obj;
- } else {
- /*
- * If we are not forcing, there must be no
- * changes since fromsnap.
- */
- if (dsl_dataset_modified_since_snap(ds, snap)) {
- dsl_dataset_rele(snap, FTAG);
- return (SET_ERROR(ETXTBSY));
- }
- drba->drba_snapobj = ds->ds_prev->ds_object;
- }
-
- dsl_dataset_rele(snap, FTAG);
- } else {
- /* if full, then must be forced */
- if (!drba->drba_cookie->drc_force)
- return (SET_ERROR(EEXIST));
- /* start from $ORIGIN@$ORIGIN, if supported */
- drba->drba_snapobj = dp->dp_origin_snap != NULL ?
- dp->dp_origin_snap->ds_object : 0;
- }
-
- return (0);
-
-}
-
-static int
-dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
-{
- dmu_recv_begin_arg_t *drba = arg;
- dsl_pool_t *dp = dmu_tx_pool(tx);
- struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
- uint64_t fromguid = drrb->drr_fromguid;
- int flags = drrb->drr_flags;
- int error;
- uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
- dsl_dataset_t *ds;
- const char *tofs = drba->drba_cookie->drc_tofs;
-
- /* already checked */
- ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
- ASSERT(!(featureflags & DMU_BACKUP_FEATURE_RESUMING));
-
- if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
- DMU_COMPOUNDSTREAM ||
- drrb->drr_type >= DMU_OST_NUMTYPES ||
- ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL))
- return (SET_ERROR(EINVAL));
-
- /* Verify pool version supports SA if SA_SPILL feature set */
- if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) &&
- spa_version(dp->dp_spa) < SPA_VERSION_SA)
- return (SET_ERROR(ENOTSUP));
-
- if (drba->drba_cookie->drc_resumable &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EXTENSIBLE_DATASET))
- return (SET_ERROR(ENOTSUP));
-
- /*
- * The receiving code doesn't know how to translate a WRITE_EMBEDDED
- * record to a plain WRITE record, so the pool must have the
- * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED
- * records. Same with WRITE_EMBEDDED records that use LZ4 compression.
- */
- if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA))
- return (SET_ERROR(ENOTSUP));
- if ((featureflags & DMU_BACKUP_FEATURE_LZ4) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
- return (SET_ERROR(ENOTSUP));
-
- /*
- * The receiving code doesn't know how to translate large blocks
- * to smaller ones, so the pool must have the LARGE_BLOCKS
- * feature enabled if the stream has LARGE_BLOCKS. Same with
- * large dnodes.
- */
- if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
- return (SET_ERROR(ENOTSUP));
- if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE))
- return (SET_ERROR(ENOTSUP));
-
- error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
- if (error == 0) {
- /* target fs already exists; recv into temp clone */
-
- /* Can't recv a clone into an existing fs */
- if (flags & DRR_FLAG_CLONE || drba->drba_origin) {
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EINVAL));
- }
-
- error = recv_begin_check_existing_impl(drba, ds, fromguid);
- dsl_dataset_rele(ds, FTAG);
- } else if (error == ENOENT) {
- /* target fs does not exist; must be a full backup or clone */
- char buf[ZFS_MAX_DATASET_NAME_LEN];
-
- /*
- * If it's a non-clone incremental, we are missing the
- * target fs, so fail the recv.
- */
- if (fromguid != 0 && !(flags & DRR_FLAG_CLONE ||
- drba->drba_origin))
- return (SET_ERROR(ENOENT));
-
- /*
- * If we're receiving a full send as a clone, and it doesn't
- * contain all the necessary free records and freeobject
- * records, reject it.
- */
- if (fromguid == 0 && drba->drba_origin &&
- !(flags & DRR_FLAG_FREERECORDS))
- return (SET_ERROR(EINVAL));
-
- /* Open the parent of tofs */
- ASSERT3U(strlen(tofs), <, sizeof (buf));
- (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1);
- error = dsl_dataset_hold(dp, buf, FTAG, &ds);
- if (error != 0)
- return (error);
-
- /*
- * Check filesystem and snapshot limits before receiving. We'll
- * recheck snapshot limits again at the end (we create the
- * filesystems and increment those counts during begin_sync).
- */
- error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
- ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred);
- if (error != 0) {
- dsl_dataset_rele(ds, FTAG);
- return (error);
- }
-
- error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
- ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred);
- if (error != 0) {
- dsl_dataset_rele(ds, FTAG);
- return (error);
- }
-
- if (drba->drba_origin != NULL) {
- dsl_dataset_t *origin;
- error = dsl_dataset_hold(dp, drba->drba_origin,
- FTAG, &origin);
- if (error != 0) {
- dsl_dataset_rele(ds, FTAG);
- return (error);
- }
- if (!origin->ds_is_snapshot) {
- dsl_dataset_rele(origin, FTAG);
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EINVAL));
- }
- if (dsl_dataset_phys(origin)->ds_guid != fromguid &&
- fromguid != 0) {
- dsl_dataset_rele(origin, FTAG);
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(ENODEV));
- }
- dsl_dataset_rele(origin, FTAG);
- }
- dsl_dataset_rele(ds, FTAG);
- error = 0;
- }
- return (error);
-}
-
-static void
-dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
-{
- dmu_recv_begin_arg_t *drba = arg;
- dsl_pool_t *dp = dmu_tx_pool(tx);
- objset_t *mos = dp->dp_meta_objset;
- struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
- const char *tofs = drba->drba_cookie->drc_tofs;
- dsl_dataset_t *ds, *newds;
- uint64_t dsobj;
- int error;
- uint64_t crflags = 0;
-
- if (drrb->drr_flags & DRR_FLAG_CI_DATA)
- crflags |= DS_FLAG_CI_DATASET;
-
- error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
- if (error == 0) {
- /* create temporary clone */
- dsl_dataset_t *snap = NULL;
- if (drba->drba_snapobj != 0) {
- VERIFY0(dsl_dataset_hold_obj(dp,
- drba->drba_snapobj, FTAG, &snap));
- }
- dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
- snap, crflags, drba->drba_cred, tx);
- if (drba->drba_snapobj != 0)
- dsl_dataset_rele(snap, FTAG);
- dsl_dataset_rele(ds, FTAG);
- } else {
- dsl_dir_t *dd;
- const char *tail;
- dsl_dataset_t *origin = NULL;
-
- VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail));
-
- if (drba->drba_origin != NULL) {
- VERIFY0(dsl_dataset_hold(dp, drba->drba_origin,
- FTAG, &origin));
- }
-
- /* Create new dataset. */
- dsobj = dsl_dataset_create_sync(dd,
- strrchr(tofs, '/') + 1,
- origin, crflags, drba->drba_cred, tx);
- if (origin != NULL)
- dsl_dataset_rele(origin, FTAG);
- dsl_dir_rele(dd, FTAG);
- drba->drba_cookie->drc_newfs = B_TRUE;
- }
- VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds));
-
- if (drba->drba_cookie->drc_resumable) {
- dsl_dataset_zapify(newds, tx);
- if (drrb->drr_fromguid != 0) {
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_FROMGUID,
- 8, 1, &drrb->drr_fromguid, tx));
- }
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_TOGUID,
- 8, 1, &drrb->drr_toguid, tx));
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_TONAME,
- 1, strlen(drrb->drr_toname) + 1, drrb->drr_toname, tx));
- uint64_t one = 1;
- uint64_t zero = 0;
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_OBJECT,
- 8, 1, &one, tx));
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_OFFSET,
- 8, 1, &zero, tx));
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_BYTES,
- 8, 1, &zero, tx));
- if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
- DMU_BACKUP_FEATURE_LARGE_BLOCKS) {
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_LARGEBLOCK,
- 8, 1, &one, tx));
- }
- if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
- DMU_BACKUP_FEATURE_EMBED_DATA) {
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_EMBEDOK,
- 8, 1, &one, tx));
- }
- if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
- DMU_BACKUP_FEATURE_COMPRESSED) {
- VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_COMPRESSOK,
- 8, 1, &one, tx));
- }
- }
-
- dmu_buf_will_dirty(newds->ds_dbuf, tx);
- dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
-
- /*
- * If we actually created a non-clone, we need to create the
- * objset in our new dataset.
- */
- rrw_enter(&newds->ds_bp_rwlock, RW_READER, FTAG);
- if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) {
- (void) dmu_objset_create_impl(dp->dp_spa,
- newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx);
- }
- rrw_exit(&newds->ds_bp_rwlock, FTAG);
-
- drba->drba_cookie->drc_ds = newds;
-
- spa_history_log_internal_ds(newds, "receive", tx, "");
-}
-
-static int
-dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx)
-{
- dmu_recv_begin_arg_t *drba = arg;
- dsl_pool_t *dp = dmu_tx_pool(tx);
- struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
- int error;
- uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
- dsl_dataset_t *ds;
- const char *tofs = drba->drba_cookie->drc_tofs;
-
- /* 6 extra bytes for /%recv */
- char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
-
- /* already checked */
- ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
- ASSERT(featureflags & DMU_BACKUP_FEATURE_RESUMING);
-
- if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
- DMU_COMPOUNDSTREAM ||
- drrb->drr_type >= DMU_OST_NUMTYPES)
- return (SET_ERROR(EINVAL));
-
- /* Verify pool version supports SA if SA_SPILL feature set */
- if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) &&
- spa_version(dp->dp_spa) < SPA_VERSION_SA)
- return (SET_ERROR(ENOTSUP));
-
- /*
- * The receiving code doesn't know how to translate a WRITE_EMBEDDED
- * record to a plain WRITE record, so the pool must have the
- * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED
- * records. Same with WRITE_EMBEDDED records that use LZ4 compression.
- */
- if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA))
- return (SET_ERROR(ENOTSUP));
- if ((featureflags & DMU_BACKUP_FEATURE_LZ4) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
- return (SET_ERROR(ENOTSUP));
-
- /*
- * The receiving code doesn't know how to translate large blocks
- * to smaller ones, so the pool must have the LARGE_BLOCKS
- * feature enabled if the stream has LARGE_BLOCKS. Same with
- * large dnodes.
- */
- if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
- return (SET_ERROR(ENOTSUP));
- if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
- !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE))
- return (SET_ERROR(ENOTSUP));
-
- (void) snprintf(recvname, sizeof (recvname), "%s/%s",
- tofs, recv_clone_name);
-
- if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) {
- /* %recv does not exist; continue in tofs */
- error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
- if (error != 0)
- return (error);
- }
-
- /* check that ds is marked inconsistent */
- if (!DS_IS_INCONSISTENT(ds)) {
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EINVAL));
- }
-
- /* check that there is resuming data, and that the toguid matches */
- if (!dsl_dataset_is_zapified(ds)) {
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EINVAL));
- }
- uint64_t val;
- error = zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val);
- if (error != 0 || drrb->drr_toguid != val) {
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EINVAL));
- }
-
- /*
- * Check if the receive is still running. If so, it will be owned.
- * Note that nothing else can own the dataset (e.g. after the receive
- * fails) because it will be marked inconsistent.
- */
- if (dsl_dataset_has_owner(ds)) {
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EBUSY));
- }
-
- /* There should not be any snapshots of this fs yet. */
- if (ds->ds_prev != NULL && ds->ds_prev->ds_dir == ds->ds_dir) {
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EINVAL));
- }
-
- /*
- * Note: resume point will be checked when we process the first WRITE
- * record.
- */
-
- /* check that the origin matches */
- val = 0;
- (void) zap_lookup(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val);
- if (drrb->drr_fromguid != val) {
- dsl_dataset_rele(ds, FTAG);
- return (SET_ERROR(EINVAL));
- }
-
- dsl_dataset_rele(ds, FTAG);
- return (0);
-}
-
-static void
-dmu_recv_resume_begin_sync(void *arg, dmu_tx_t *tx)
-{
- dmu_recv_begin_arg_t *drba = arg;
- dsl_pool_t *dp = dmu_tx_pool(tx);
- const char *tofs = drba->drba_cookie->drc_tofs;
- dsl_dataset_t *ds;
- uint64_t dsobj;
- /* 6 extra bytes for /%recv */
- char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
-
- (void) snprintf(recvname, sizeof (recvname), "%s/%s",
- tofs, recv_clone_name);
-
- if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) {
- /* %recv does not exist; continue in tofs */
- VERIFY0(dsl_dataset_hold(dp, tofs, FTAG, &ds));
- drba->drba_cookie->drc_newfs = B_TRUE;
- }
-
- /* clear the inconsistent flag so that we can own it */
- ASSERT(DS_IS_INCONSISTENT(ds));
- dmu_buf_will_dirty(ds->ds_dbuf, tx);
- dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
- dsobj = ds->ds_object;
- dsl_dataset_rele(ds, FTAG);
-
- VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &ds));
-
- dmu_buf_will_dirty(ds->ds_dbuf, tx);
- dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT;
-
- rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG);
- ASSERT(!BP_IS_HOLE(dsl_dataset_get_blkptr(ds)));
- rrw_exit(&ds->ds_bp_rwlock, FTAG);
-
- drba->drba_cookie->drc_ds = ds;
-
- spa_history_log_internal_ds(ds, "resume receive", tx, "");
-}
-
-/*
- * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
- * succeeds; otherwise we will leak the holds on the datasets.
- */
-int
-dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin,
- boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc)
-{
- dmu_recv_begin_arg_t drba = { 0 };
-
- bzero(drc, sizeof (dmu_recv_cookie_t));
- drc->drc_drr_begin = drr_begin;
- drc->drc_drrb = &drr_begin->drr_u.drr_begin;
- drc->drc_tosnap = tosnap;
- drc->drc_tofs = tofs;
- drc->drc_force = force;
- drc->drc_resumable = resumable;
- drc->drc_cred = CRED();
- drc->drc_clone = (origin != NULL);
-
- if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
- drc->drc_byteswap = B_TRUE;
- (void) fletcher_4_incremental_byteswap(drr_begin,
- sizeof (dmu_replay_record_t), &drc->drc_cksum);
- byteswap_record(drr_begin);
- } else if (drc->drc_drrb->drr_magic == DMU_BACKUP_MAGIC) {
- (void) fletcher_4_incremental_native(drr_begin,
- sizeof (dmu_replay_record_t), &drc->drc_cksum);
- } else {
- return (SET_ERROR(EINVAL));
- }
-
- drba.drba_origin = origin;
- drba.drba_cookie = drc;
- drba.drba_cred = CRED();
-
- if (DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo) &
- DMU_BACKUP_FEATURE_RESUMING) {
- return (dsl_sync_task(tofs,
- dmu_recv_resume_begin_check, dmu_recv_resume_begin_sync,
- &drba, 5, ZFS_SPACE_CHECK_NORMAL));
- } else {
- return (dsl_sync_task(tofs,
- dmu_recv_begin_check, dmu_recv_begin_sync,
- &drba, 5, ZFS_SPACE_CHECK_NORMAL));
- }
-}
-
-struct receive_record_arg {
- dmu_replay_record_t header;
- void *payload; /* Pointer to a buffer containing the payload */
- /*
- * If the record is a write, pointer to the arc_buf_t containing the
- * payload.
- */
- arc_buf_t *write_buf;
- int payload_size;
- uint64_t bytes_read; /* bytes read from stream when record created */
- boolean_t eos_marker; /* Marks the end of the stream */
- bqueue_node_t node;
-};
-
-struct receive_writer_arg {
- objset_t *os;
- boolean_t byteswap;
- bqueue_t q;
-
- /*
- * These three args are used to signal to the main thread that we're
- * done.
- */
- kmutex_t mutex;
- kcondvar_t cv;
- boolean_t done;
-
- int err;
- /* A map from guid to dataset to help handle dedup'd streams. */
- avl_tree_t *guid_to_ds_map;
- boolean_t resumable;
- uint64_t last_object;
- uint64_t last_offset;
- uint64_t max_object; /* highest object ID referenced in stream */
- uint64_t bytes_read; /* bytes read when current record created */
-};
-
-struct objlist {
- list_t list; /* List of struct receive_objnode. */
- /*
- * Last object looked up. Used to assert that objects are being looked
- * up in ascending order.
- */
- uint64_t last_lookup;
-};
-
-struct receive_objnode {
- list_node_t node;
- uint64_t object;
-};
-
-struct receive_arg {
- objset_t *os;
- vnode_t *vp; /* The vnode to read the stream from */
- uint64_t voff; /* The current offset in the stream */
- uint64_t bytes_read;
- /*
- * A record that has had its payload read in, but hasn't yet been handed
- * off to the worker thread.
- */
- struct receive_record_arg *rrd;
- /* A record that has had its header read in, but not its payload. */
- struct receive_record_arg *next_rrd;
- zio_cksum_t cksum;
- zio_cksum_t prev_cksum;
- int err;
- boolean_t byteswap;
- /* Sorted list of objects not to issue prefetches for. */
- struct objlist ignore_objlist;
-};
-
-typedef struct guid_map_entry {
- uint64_t guid;
- dsl_dataset_t *gme_ds;
- avl_node_t avlnode;
-} guid_map_entry_t;
-
-static int
-guid_compare(const void *arg1, const void *arg2)
-{
- const guid_map_entry_t *gmep1 = arg1;
- const guid_map_entry_t *gmep2 = arg2;
-
- if (gmep1->guid < gmep2->guid)
- return (-1);
- else if (gmep1->guid > gmep2->guid)
- return (1);
- return (0);
-}
-
-static void
-free_guid_map_onexit(void *arg)
-{
- avl_tree_t *ca = arg;
- void *cookie = NULL;
- guid_map_entry_t *gmep;
-
- while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) {
- dsl_dataset_long_rele(gmep->gme_ds, gmep);
- dsl_dataset_rele(gmep->gme_ds, gmep);
- kmem_free(gmep, sizeof (guid_map_entry_t));
- }
- avl_destroy(ca);
- kmem_free(ca, sizeof (avl_tree_t));
-}
-
-static int
-receive_read(struct receive_arg *ra, int len, void *buf)
-{
- int done = 0;
-
- /*
- * The code doesn't rely on this (lengths being multiples of 8). See
- * comment in dump_bytes.
- */
- ASSERT0(len % 8);
-
- while (done < len) {
- ssize_t resid;
-
- ra->err = vn_rdwr(UIO_READ, ra->vp,
- (char *)buf + done, len - done,
- ra->voff, UIO_SYSSPACE, FAPPEND,
- RLIM64_INFINITY, CRED(), &resid);
-
- if (resid == len - done) {
- /*
- * Note: ECKSUM indicates that the receive
- * was interrupted and can potentially be resumed.
- */
- ra->err = SET_ERROR(ECKSUM);
- }
- ra->voff += len - done - resid;
- done = len - resid;
- if (ra->err != 0)
- return (ra->err);
- }
-
- ra->bytes_read += len;
-
- ASSERT3U(done, ==, len);
- return (0);
-}
-
-static void
-byteswap_record(dmu_replay_record_t *drr)
-{
-#define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
-#define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
- drr->drr_type = BSWAP_32(drr->drr_type);
- drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen);
-
- switch (drr->drr_type) {
- case DRR_BEGIN:
- DO64(drr_begin.drr_magic);
- DO64(drr_begin.drr_versioninfo);
- DO64(drr_begin.drr_creation_time);
- DO32(drr_begin.drr_type);
- DO32(drr_begin.drr_flags);
- DO64(drr_begin.drr_toguid);
- DO64(drr_begin.drr_fromguid);
- break;
- case DRR_OBJECT:
- DO64(drr_object.drr_object);
- DO32(drr_object.drr_type);
- DO32(drr_object.drr_bonustype);
- DO32(drr_object.drr_blksz);
- DO32(drr_object.drr_bonuslen);
- DO64(drr_object.drr_toguid);
- break;
- case DRR_FREEOBJECTS:
- DO64(drr_freeobjects.drr_firstobj);
- DO64(drr_freeobjects.drr_numobjs);
- DO64(drr_freeobjects.drr_toguid);
- break;
- case DRR_WRITE:
- DO64(drr_write.drr_object);
- DO32(drr_write.drr_type);
- DO64(drr_write.drr_offset);
- DO64(drr_write.drr_logical_size);
- DO64(drr_write.drr_toguid);
- ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_write.drr_key.ddk_cksum);
- DO64(drr_write.drr_key.ddk_prop);
- DO64(drr_write.drr_compressed_size);
- break;
- case DRR_WRITE_BYREF:
- DO64(drr_write_byref.drr_object);
- DO64(drr_write_byref.drr_offset);
- DO64(drr_write_byref.drr_length);
- DO64(drr_write_byref.drr_toguid);
- DO64(drr_write_byref.drr_refguid);
- DO64(drr_write_byref.drr_refobject);
- DO64(drr_write_byref.drr_refoffset);
- ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_write_byref.
- drr_key.ddk_cksum);
- DO64(drr_write_byref.drr_key.ddk_prop);
- break;
- case DRR_WRITE_EMBEDDED:
- DO64(drr_write_embedded.drr_object);
- DO64(drr_write_embedded.drr_offset);
- DO64(drr_write_embedded.drr_length);
- DO64(drr_write_embedded.drr_toguid);
- DO32(drr_write_embedded.drr_lsize);
- DO32(drr_write_embedded.drr_psize);
- break;
- case DRR_FREE:
- DO64(drr_free.drr_object);
- DO64(drr_free.drr_offset);
- DO64(drr_free.drr_length);
- DO64(drr_free.drr_toguid);
- break;
- case DRR_SPILL:
- DO64(drr_spill.drr_object);
- DO64(drr_spill.drr_length);
- DO64(drr_spill.drr_toguid);
- break;
- case DRR_END:
- DO64(drr_end.drr_toguid);
- ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_end.drr_checksum);
- break;
- }
-
- if (drr->drr_type != DRR_BEGIN) {
- ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_checksum.drr_checksum);
- }
-
-#undef DO64
-#undef DO32
-}
-
-static inline uint8_t
-deduce_nblkptr(dmu_object_type_t bonus_type, uint64_t bonus_size)
-{
- if (bonus_type == DMU_OT_SA) {
- return (1);
- } else {
- return (1 +
- ((DN_OLD_MAX_BONUSLEN -
- MIN(DN_OLD_MAX_BONUSLEN, bonus_size)) >> SPA_BLKPTRSHIFT));
- }
-}
-
-static void
-save_resume_state(struct receive_writer_arg *rwa,
- uint64_t object, uint64_t offset, dmu_tx_t *tx)
-{
- int txgoff = dmu_tx_get_txg(tx) & TXG_MASK;
-
- if (!rwa->resumable)
- return;
-
- /*
- * We use ds_resume_bytes[] != 0 to indicate that we need to
- * update this on disk, so it must not be 0.
- */
- ASSERT(rwa->bytes_read != 0);
-
- /*
- * We only resume from write records, which have a valid
- * (non-meta-dnode) object number.
- */
- ASSERT(object != 0);
-
- /*
- * For resuming to work correctly, we must receive records in order,
- * sorted by object,offset. This is checked by the callers, but
- * assert it here for good measure.
- */
- ASSERT3U(object, >=, rwa->os->os_dsl_dataset->ds_resume_object[txgoff]);
- ASSERT(object != rwa->os->os_dsl_dataset->ds_resume_object[txgoff] ||
- offset >= rwa->os->os_dsl_dataset->ds_resume_offset[txgoff]);
- ASSERT3U(rwa->bytes_read, >=,
- rwa->os->os_dsl_dataset->ds_resume_bytes[txgoff]);
-
- rwa->os->os_dsl_dataset->ds_resume_object[txgoff] = object;
- rwa->os->os_dsl_dataset->ds_resume_offset[txgoff] = offset;
- rwa->os->os_dsl_dataset->ds_resume_bytes[txgoff] = rwa->bytes_read;
-}
-
-static int
-receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
- void *data)
-{
- dmu_object_info_t doi;
- dmu_tx_t *tx;
- uint64_t object;
- int err;
- uint8_t dn_slots = drro->drr_dn_slots != 0 ?
- drro->drr_dn_slots : DNODE_MIN_SLOTS;
-
- if (drro->drr_type == DMU_OT_NONE ||
- !DMU_OT_IS_VALID(drro->drr_type) ||
- !DMU_OT_IS_VALID(drro->drr_bonustype) ||
- drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS ||
- drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS ||
- P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) ||
- drro->drr_blksz < SPA_MINBLOCKSIZE ||
- drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(rwa->os)) ||
- drro->drr_bonuslen >
- DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os))) ||
- dn_slots >
- (spa_maxdnodesize(dmu_objset_spa(rwa->os)) >> DNODE_SHIFT)) {
- return (SET_ERROR(EINVAL));
- }
-
- err = dmu_object_info(rwa->os, drro->drr_object, &doi);
-
- if (err != 0 && err != ENOENT && err != EEXIST)
- return (SET_ERROR(EINVAL));
-
- if (drro->drr_object > rwa->max_object)
- rwa->max_object = drro->drr_object;
-
- /*
- * If we are losing blkptrs or changing the block size this must
- * be a new file instance. We must clear out the previous file
- * contents before we can change this type of metadata in the dnode.
- */
- if (err == 0) {
- int nblkptr;
-
- object = drro->drr_object;
-
- nblkptr = deduce_nblkptr(drro->drr_bonustype,
- drro->drr_bonuslen);
-
- if (drro->drr_blksz != doi.doi_data_block_size ||
- nblkptr < doi.doi_nblkptr ||
- dn_slots != doi.doi_dnodesize >> DNODE_SHIFT) {
- err = dmu_free_long_range(rwa->os, drro->drr_object,
- 0, DMU_OBJECT_END);
- if (err != 0)
- return (SET_ERROR(EINVAL));
- }
- } else if (err == EEXIST) {
- /*
- * The object requested is currently an interior slot of a
- * multi-slot dnode. This will be resolved when the next txg
- * is synced out, since the send stream will have told us
- * to free this slot when we freed the associated dnode
- * earlier in the stream.
- */
- txg_wait_synced(dmu_objset_pool(rwa->os), 0);
- object = drro->drr_object;
- } else {
- /* object is free and we are about to allocate a new one */
- object = DMU_NEW_OBJECT;
- }
-
- /*
- * If this is a multi-slot dnode there is a chance that this
- * object will expand into a slot that is already used by
- * another object from the previous snapshot. We must free
- * these objects before we attempt to allocate the new dnode.
- */
- if (dn_slots > 1) {
- boolean_t need_sync = B_FALSE;
-
- for (uint64_t slot = drro->drr_object + 1;
- slot < drro->drr_object + dn_slots;
- slot++) {
- dmu_object_info_t slot_doi;
-
- err = dmu_object_info(rwa->os, slot, &slot_doi);
- if (err == ENOENT || err == EEXIST)
- continue;
- else if (err != 0)
- return (err);
-
- err = dmu_free_long_object(rwa->os, slot);
-
- if (err != 0)
- return (err);
-
- need_sync = B_TRUE;
- }
-
- if (need_sync)
- txg_wait_synced(dmu_objset_pool(rwa->os), 0);
- }
-
- tx = dmu_tx_create(rwa->os);
- dmu_tx_hold_bonus(tx, object);
- err = dmu_tx_assign(tx, TXG_WAIT);
- if (err != 0) {
- dmu_tx_abort(tx);
- return (err);
- }
-
- if (object == DMU_NEW_OBJECT) {
- /* currently free, want to be allocated */
- err = dmu_object_claim_dnsize(rwa->os, drro->drr_object,
- drro->drr_type, drro->drr_blksz,
- drro->drr_bonustype, drro->drr_bonuslen,
- dn_slots << DNODE_SHIFT, tx);
- } else if (drro->drr_type != doi.doi_type ||
- drro->drr_blksz != doi.doi_data_block_size ||
- drro->drr_bonustype != doi.doi_bonus_type ||
- drro->drr_bonuslen != doi.doi_bonus_size) {
- /* currently allocated, but with different properties */
- err = dmu_object_reclaim(rwa->os, drro->drr_object,
- drro->drr_type, drro->drr_blksz,
- drro->drr_bonustype, drro->drr_bonuslen, tx);
- }
- if (err != 0) {
- dmu_tx_commit(tx);
- return (SET_ERROR(EINVAL));
- }
-
- dmu_object_set_checksum(rwa->os, drro->drr_object,
- drro->drr_checksumtype, tx);
- dmu_object_set_compress(rwa->os, drro->drr_object,
- drro->drr_compress, tx);
-
- if (data != NULL) {
- dmu_buf_t *db;
-
- VERIFY0(dmu_bonus_hold(rwa->os, drro->drr_object, FTAG, &db));
- dmu_buf_will_dirty(db, tx);
-
- ASSERT3U(db->db_size, >=, drro->drr_bonuslen);
- bcopy(data, db->db_data, drro->drr_bonuslen);
- if (rwa->byteswap) {
- dmu_object_byteswap_t byteswap =
- DMU_OT_BYTESWAP(drro->drr_bonustype);
- dmu_ot_byteswap[byteswap].ob_func(db->db_data,
- drro->drr_bonuslen);
- }
- dmu_buf_rele(db, FTAG);
- }
- dmu_tx_commit(tx);
-
- return (0);
-}
-
-/* ARGSUSED */
-static int
-receive_freeobjects(struct receive_writer_arg *rwa,
- struct drr_freeobjects *drrfo)
-{
- uint64_t obj;
- int next_err = 0;
-
- if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj)
- return (SET_ERROR(EINVAL));
-
- for (obj = drrfo->drr_firstobj == 0 ? 1 : drrfo->drr_firstobj;
- obj < drrfo->drr_firstobj + drrfo->drr_numobjs && next_err == 0;
- next_err = dmu_object_next(rwa->os, &obj, FALSE, 0)) {
- int err;
-
- err = dmu_object_info(rwa->os, obj, NULL);
- if (err == ENOENT) {
- obj++;
- continue;
- } else if (err != 0) {
- return (err);
- }
-
- err = dmu_free_long_object(rwa->os, obj);
- if (err != 0)
- return (err);
-
- if (obj > rwa->max_object)
- rwa->max_object = obj;
- }
- if (next_err != ESRCH)
- return (next_err);
- return (0);
-}
-
-static int
-receive_write(struct receive_writer_arg *rwa, struct drr_write *drrw,
- arc_buf_t *abuf)
-{
- dmu_tx_t *tx;
- int err;
-
- if (drrw->drr_offset + drrw->drr_logical_size < drrw->drr_offset ||
- !DMU_OT_IS_VALID(drrw->drr_type))
- return (SET_ERROR(EINVAL));
-
- /*
- * For resuming to work, records must be in increasing order
- * by (object, offset).
- */
- if (drrw->drr_object < rwa->last_object ||
- (drrw->drr_object == rwa->last_object &&
- drrw->drr_offset < rwa->last_offset)) {
- return (SET_ERROR(EINVAL));
- }
- rwa->last_object = drrw->drr_object;
- rwa->last_offset = drrw->drr_offset;
-
- if (rwa->last_object > rwa->max_object)
- rwa->max_object = rwa->last_object;
-
- if (dmu_object_info(rwa->os, drrw->drr_object, NULL) != 0)
- return (SET_ERROR(EINVAL));
-
- tx = dmu_tx_create(rwa->os);
-
- dmu_tx_hold_write(tx, drrw->drr_object,
- drrw->drr_offset, drrw->drr_logical_size);
- err = dmu_tx_assign(tx, TXG_WAIT);
- if (err != 0) {
- dmu_tx_abort(tx);
- return (err);
- }
- if (rwa->byteswap) {
- dmu_object_byteswap_t byteswap =
- DMU_OT_BYTESWAP(drrw->drr_type);
- dmu_ot_byteswap[byteswap].ob_func(abuf->b_data,
- DRR_WRITE_PAYLOAD_SIZE(drrw));
- }
-
- /* use the bonus buf to look up the dnode in dmu_assign_arcbuf */
- dmu_buf_t *bonus;
- if (dmu_bonus_hold(rwa->os, drrw->drr_object, FTAG, &bonus) != 0)
- return (SET_ERROR(EINVAL));
- dmu_assign_arcbuf(bonus, drrw->drr_offset, abuf, tx);
-
- /*
- * Note: If the receive fails, we want the resume stream to start
- * with the same record that we last successfully received (as opposed
- * to the next record), so that we can verify that we are
- * resuming from the correct location.
- */
- save_resume_state(rwa, drrw->drr_object, drrw->drr_offset, tx);
- dmu_tx_commit(tx);
- dmu_buf_rele(bonus, FTAG);
-
- return (0);
-}
-
-/*
- * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed
- * streams to refer to a copy of the data that is already on the
- * system because it came in earlier in the stream. This function
- * finds the earlier copy of the data, and uses that copy instead of
- * data from the stream to fulfill this write.
- */
-static int
-receive_write_byref(struct receive_writer_arg *rwa,
- struct drr_write_byref *drrwbr)
-{
- dmu_tx_t *tx;
- int err;
- guid_map_entry_t gmesrch;
- guid_map_entry_t *gmep;
- avl_index_t where;
- objset_t *ref_os = NULL;
- dmu_buf_t *dbp;
-
- if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset)
- return (SET_ERROR(EINVAL));
-
- /*
- * If the GUID of the referenced dataset is different from the
- * GUID of the target dataset, find the referenced dataset.
- */
- if (drrwbr->drr_toguid != drrwbr->drr_refguid) {
- gmesrch.guid = drrwbr->drr_refguid;
- if ((gmep = avl_find(rwa->guid_to_ds_map, &gmesrch,
- &where)) == NULL) {
- return (SET_ERROR(EINVAL));
- }
- if (dmu_objset_from_ds(gmep->gme_ds, &ref_os))
- return (SET_ERROR(EINVAL));
- } else {
- ref_os = rwa->os;
- }
-
- if (drrwbr->drr_object > rwa->max_object)
- rwa->max_object = drrwbr->drr_object;
-
- err = dmu_buf_hold(ref_os, drrwbr->drr_refobject,
- drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH);
- if (err != 0)
- return (err);
-
- tx = dmu_tx_create(rwa->os);
-
- dmu_tx_hold_write(tx, drrwbr->drr_object,
- drrwbr->drr_offset, drrwbr->drr_length);
- err = dmu_tx_assign(tx, TXG_WAIT);
- if (err != 0) {
- dmu_tx_abort(tx);
- return (err);
- }
- dmu_write(rwa->os, drrwbr->drr_object,
- drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx);
- dmu_buf_rele(dbp, FTAG);
-
- /* See comment in restore_write. */
- save_resume_state(rwa, drrwbr->drr_object, drrwbr->drr_offset, tx);
- dmu_tx_commit(tx);
- return (0);
-}
-
-static int
-receive_write_embedded(struct receive_writer_arg *rwa,
- struct drr_write_embedded *drrwe, void *data)
-{
- dmu_tx_t *tx;
- int err;
-
- if (drrwe->drr_offset + drrwe->drr_length < drrwe->drr_offset)
- return (EINVAL);
-
- if (drrwe->drr_psize > BPE_PAYLOAD_SIZE)
- return (EINVAL);
-
- if (drrwe->drr_etype >= NUM_BP_EMBEDDED_TYPES)
- return (EINVAL);
- if (drrwe->drr_compression >= ZIO_COMPRESS_FUNCTIONS)
- return (EINVAL);
-
- if (drrwe->drr_object > rwa->max_object)
- rwa->max_object = drrwe->drr_object;
-
- tx = dmu_tx_create(rwa->os);
-
- dmu_tx_hold_write(tx, drrwe->drr_object,
- drrwe->drr_offset, drrwe->drr_length);
- err = dmu_tx_assign(tx, TXG_WAIT);
- if (err != 0) {
- dmu_tx_abort(tx);
- return (err);
- }
-
- dmu_write_embedded(rwa->os, drrwe->drr_object,
- drrwe->drr_offset, data, drrwe->drr_etype,
- drrwe->drr_compression, drrwe->drr_lsize, drrwe->drr_psize,
- rwa->byteswap ^ ZFS_HOST_BYTEORDER, tx);
-
- /* See comment in restore_write. */
- save_resume_state(rwa, drrwe->drr_object, drrwe->drr_offset, tx);
- dmu_tx_commit(tx);
- return (0);
-}
-
-static int
-receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
- void *data)
-{
- dmu_tx_t *tx;
- dmu_buf_t *db, *db_spill;
- int err;
-
- if (drrs->drr_length < SPA_MINBLOCKSIZE ||
- drrs->drr_length > spa_maxblocksize(dmu_objset_spa(rwa->os)))
- return (SET_ERROR(EINVAL));
-
- if (dmu_object_info(rwa->os, drrs->drr_object, NULL) != 0)
- return (SET_ERROR(EINVAL));
-
- if (drrs->drr_object > rwa->max_object)
- rwa->max_object = drrs->drr_object;
-
- VERIFY0(dmu_bonus_hold(rwa->os, drrs->drr_object, FTAG, &db));
- if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) {
- dmu_buf_rele(db, FTAG);
- return (err);
- }
-
- tx = dmu_tx_create(rwa->os);
-
- dmu_tx_hold_spill(tx, db->db_object);
-
- err = dmu_tx_assign(tx, TXG_WAIT);
- if (err != 0) {
- dmu_buf_rele(db, FTAG);
- dmu_buf_rele(db_spill, FTAG);
- dmu_tx_abort(tx);
- return (err);
- }
- dmu_buf_will_dirty(db_spill, tx);
-
- if (db_spill->db_size < drrs->drr_length)
- VERIFY(0 == dbuf_spill_set_blksz(db_spill,
- drrs->drr_length, tx));
- bcopy(data, db_spill->db_data, drrs->drr_length);
-
- dmu_buf_rele(db, FTAG);
- dmu_buf_rele(db_spill, FTAG);
-
- dmu_tx_commit(tx);
- return (0);
-}
-
-/* ARGSUSED */
-static int
-receive_free(struct receive_writer_arg *rwa, struct drr_free *drrf)
-{
- int err;
-
- if (drrf->drr_length != -1ULL &&
- drrf->drr_offset + drrf->drr_length < drrf->drr_offset)
- return (SET_ERROR(EINVAL));
-
- if (dmu_object_info(rwa->os, drrf->drr_object, NULL) != 0)
- return (SET_ERROR(EINVAL));
-
- if (drrf->drr_object > rwa->max_object)
- rwa->max_object = drrf->drr_object;
-
- err = dmu_free_long_range(rwa->os, drrf->drr_object,
- drrf->drr_offset, drrf->drr_length);
-
- return (err);
-}
-
-/* used to destroy the drc_ds on error */
-static void
-dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc)
-{
- if (drc->drc_resumable) {
- /* wait for our resume state to be written to disk */
- txg_wait_synced(drc->drc_ds->ds_dir->dd_pool, 0);
- dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
- } else {
- char name[ZFS_MAX_DATASET_NAME_LEN];
- dsl_dataset_name(drc->drc_ds, name);
- dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
- (void) dsl_destroy_head(name);
- }
-}
-
-static void
-receive_cksum(struct receive_arg *ra, int len, void *buf)
-{
- if (ra->byteswap) {
- (void) fletcher_4_incremental_byteswap(buf, len, &ra->cksum);
- } else {
- (void) fletcher_4_incremental_native(buf, len, &ra->cksum);
- }
-}
-
-/*
- * Read the payload into a buffer of size len, and update the current record's
- * payload field.
- * Allocate ra->next_rrd and read the next record's header into
- * ra->next_rrd->header.
- * Verify checksum of payload and next record.
- */
-static int
-receive_read_payload_and_next_header(struct receive_arg *ra, int len, void *buf)
-{
- int err;
-
- if (len != 0) {
- ASSERT3U(len, <=, SPA_MAXBLOCKSIZE);
- err = receive_read(ra, len, buf);
- if (err != 0)
- return (err);
- receive_cksum(ra, len, buf);
-
- /* note: rrd is NULL when reading the begin record's payload */
- if (ra->rrd != NULL) {
- ra->rrd->payload = buf;
- ra->rrd->payload_size = len;
- ra->rrd->bytes_read = ra->bytes_read;
- }
- }
-
- ra->prev_cksum = ra->cksum;
-
- ra->next_rrd = kmem_zalloc(sizeof (*ra->next_rrd), KM_SLEEP);
- err = receive_read(ra, sizeof (ra->next_rrd->header),
- &ra->next_rrd->header);
- ra->next_rrd->bytes_read = ra->bytes_read;
- if (err != 0) {
- kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
- ra->next_rrd = NULL;
- return (err);
- }
- if (ra->next_rrd->header.drr_type == DRR_BEGIN) {
- kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
- ra->next_rrd = NULL;
- return (SET_ERROR(EINVAL));
- }
-
- /*
- * Note: checksum is of everything up to but not including the
- * checksum itself.
- */
- ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
- ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
- receive_cksum(ra,
- offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
- &ra->next_rrd->header);
-
- zio_cksum_t cksum_orig =
- ra->next_rrd->header.drr_u.drr_checksum.drr_checksum;
- zio_cksum_t *cksump =
- &ra->next_rrd->header.drr_u.drr_checksum.drr_checksum;
-
- if (ra->byteswap)
- byteswap_record(&ra->next_rrd->header);
-
- if ((!ZIO_CHECKSUM_IS_ZERO(cksump)) &&
- !ZIO_CHECKSUM_EQUAL(ra->cksum, *cksump)) {
- kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
- ra->next_rrd = NULL;
- return (SET_ERROR(ECKSUM));
- }
-
- receive_cksum(ra, sizeof (cksum_orig), &cksum_orig);
-
- return (0);
-}
-
-static void
-objlist_create(struct objlist *list)
-{
- list_create(&list->list, sizeof (struct receive_objnode),
- offsetof(struct receive_objnode, node));
- list->last_lookup = 0;
-}
-
-static void
-objlist_destroy(struct objlist *list)
-{
- for (struct receive_objnode *n = list_remove_head(&list->list);
- n != NULL; n = list_remove_head(&list->list)) {
- kmem_free(n, sizeof (*n));
- }
- list_destroy(&list->list);
-}
-
-/*
- * This function looks through the objlist to see if the specified object number
- * is contained in the objlist. In the process, it will remove all object
- * numbers in the list that are smaller than the specified object number. Thus,
- * any lookup of an object number smaller than a previously looked up object
- * number will always return false; therefore, all lookups should be done in
- * ascending order.
- */
-static boolean_t
-objlist_exists(struct objlist *list, uint64_t object)
-{
- struct receive_objnode *node = list_head(&list->list);
- ASSERT3U(object, >=, list->last_lookup);
- list->last_lookup = object;
- while (node != NULL && node->object < object) {
- VERIFY3P(node, ==, list_remove_head(&list->list));
- kmem_free(node, sizeof (*node));
- node = list_head(&list->list);
- }
- return (node != NULL && node->object == object);
-}
-
-/*
- * The objlist is a list of object numbers stored in ascending order. However,
- * the insertion of new object numbers does not seek out the correct location to
- * store a new object number; instead, it appends it to the list for simplicity.
- * Thus, any users must take care to only insert new object numbers in ascending
- * order.
- */
-static void
-objlist_insert(struct objlist *list, uint64_t object)
-{
- struct receive_objnode *node = kmem_zalloc(sizeof (*node), KM_SLEEP);
- node->object = object;
-#ifdef ZFS_DEBUG
- struct receive_objnode *last_object = list_tail(&list->list);
- uint64_t last_objnum = (last_object != NULL ? last_object->object : 0);
- ASSERT3U(node->object, >, last_objnum);
-#endif
- list_insert_tail(&list->list, node);
-}
-
-/*
- * Issue the prefetch reads for any necessary indirect blocks.
- *
- * We use the object ignore list to tell us whether or not to issue prefetches
- * for a given object. We do this for both correctness (in case the blocksize
- * of an object has changed) and performance (if the object doesn't exist, don't
- * needlessly try to issue prefetches). We also trim the list as we go through
- * the stream to prevent it from growing to an unbounded size.
- *
- * The object numbers within will always be in sorted order, and any write
- * records we see will also be in sorted order, but they're not sorted with
- * respect to each other (i.e. we can get several object records before
- * receiving each object's write records). As a result, once we've reached a
- * given object number, we can safely remove any reference to lower object
- * numbers in the ignore list. In practice, we receive up to 32 object records
- * before receiving write records, so the list can have up to 32 nodes in it.
- */
-/* ARGSUSED */
-static void
-receive_read_prefetch(struct receive_arg *ra,
- uint64_t object, uint64_t offset, uint64_t length)
-{
- if (!objlist_exists(&ra->ignore_objlist, object)) {
- dmu_prefetch(ra->os, object, 1, offset, length,
- ZIO_PRIORITY_SYNC_READ);
- }
-}
-
-/*
- * Read records off the stream, issuing any necessary prefetches.
- */
-static int
-receive_read_record(struct receive_arg *ra)
-{
- int err;
-
- switch (ra->rrd->header.drr_type) {
- case DRR_OBJECT:
- {
- struct drr_object *drro = &ra->rrd->header.drr_u.drr_object;
- uint32_t size = P2ROUNDUP(drro->drr_bonuslen, 8);
- void *buf = NULL;
- dmu_object_info_t doi;
-
- if (size > 0)
- buf = kmem_zalloc(size, KM_SLEEP);
-
- err = receive_read_payload_and_next_header(ra, size, buf);
- if (err != 0) {
- kmem_free(buf, size);
- return (err);
- }
- err = dmu_object_info(ra->os, drro->drr_object, &doi);
- /*
- * See receive_read_prefetch for an explanation why we're
- * storing this object in the ignore_obj_list.
- */
- if (err == ENOENT ||
- (err == 0 && doi.doi_data_block_size != drro->drr_blksz)) {
- objlist_insert(&ra->ignore_objlist, drro->drr_object);
- err = 0;
- }
- return (err);
- }
- case DRR_FREEOBJECTS:
- {
- err = receive_read_payload_and_next_header(ra, 0, NULL);
- return (err);
- }
- case DRR_WRITE:
- {
- struct drr_write *drrw = &ra->rrd->header.drr_u.drr_write;
- arc_buf_t *abuf;
- boolean_t is_meta = DMU_OT_IS_METADATA(drrw->drr_type);
- if (DRR_WRITE_COMPRESSED(drrw)) {
- ASSERT3U(drrw->drr_compressed_size, >, 0);
- ASSERT3U(drrw->drr_logical_size, >=,
- drrw->drr_compressed_size);
- ASSERT(!is_meta);
- abuf = arc_loan_compressed_buf(
- dmu_objset_spa(ra->os),
- drrw->drr_compressed_size, drrw->drr_logical_size,
- drrw->drr_compressiontype);
- } else {
- abuf = arc_loan_buf(dmu_objset_spa(ra->os),
- is_meta, drrw->drr_logical_size);
- }
-
- err = receive_read_payload_and_next_header(ra,
- DRR_WRITE_PAYLOAD_SIZE(drrw), abuf->b_data);
- if (err != 0) {
- dmu_return_arcbuf(abuf);
- return (err);
- }
- ra->rrd->write_buf = abuf;
- receive_read_prefetch(ra, drrw->drr_object, drrw->drr_offset,
- drrw->drr_logical_size);
- return (err);
- }
- case DRR_WRITE_BYREF:
- {
- struct drr_write_byref *drrwb =
- &ra->rrd->header.drr_u.drr_write_byref;
- err = receive_read_payload_and_next_header(ra, 0, NULL);
- receive_read_prefetch(ra, drrwb->drr_object, drrwb->drr_offset,
- drrwb->drr_length);
- return (err);
- }
- case DRR_WRITE_EMBEDDED:
- {
- struct drr_write_embedded *drrwe =
- &ra->rrd->header.drr_u.drr_write_embedded;
- uint32_t size = P2ROUNDUP(drrwe->drr_psize, 8);
- void *buf = kmem_zalloc(size, KM_SLEEP);
-
- err = receive_read_payload_and_next_header(ra, size, buf);
- if (err != 0) {
- kmem_free(buf, size);
- return (err);
- }
-
- receive_read_prefetch(ra, drrwe->drr_object, drrwe->drr_offset,
- drrwe->drr_length);
- return (err);
- }
- case DRR_FREE:
- {
- /*
- * It might be beneficial to prefetch indirect blocks here, but
- * we don't really have the data to decide for sure.
- */
- err = receive_read_payload_and_next_header(ra, 0, NULL);
- return (err);
- }
- case DRR_END:
- {
- struct drr_end *drre = &ra->rrd->header.drr_u.drr_end;
- if (!ZIO_CHECKSUM_EQUAL(ra->prev_cksum, drre->drr_checksum))
- return (SET_ERROR(ECKSUM));
- return (0);
- }
- case DRR_SPILL:
- {
- struct drr_spill *drrs = &ra->rrd->header.drr_u.drr_spill;
- void *buf = kmem_zalloc(drrs->drr_length, KM_SLEEP);
- err = receive_read_payload_and_next_header(ra, drrs->drr_length,
- buf);
- if (err != 0)
- kmem_free(buf, drrs->drr_length);
- return (err);
- }
- default:
- return (SET_ERROR(EINVAL));
- }
-}
-
-/*
- * Commit the records to the pool.
- */
-static int
-receive_process_record(struct receive_writer_arg *rwa,
- struct receive_record_arg *rrd)
-{
- int err;
-
- /* Processing in order, therefore bytes_read should be increasing. */
- ASSERT3U(rrd->bytes_read, >=, rwa->bytes_read);
- rwa->bytes_read = rrd->bytes_read;
-
- switch (rrd->header.drr_type) {
- case DRR_OBJECT:
- {
- struct drr_object *drro = &rrd->header.drr_u.drr_object;
- err = receive_object(rwa, drro, rrd->payload);
- kmem_free(rrd->payload, rrd->payload_size);
- rrd->payload = NULL;
- return (err);
- }
- case DRR_FREEOBJECTS:
- {
- struct drr_freeobjects *drrfo =
- &rrd->header.drr_u.drr_freeobjects;
- return (receive_freeobjects(rwa, drrfo));
- }
- case DRR_WRITE:
- {
- struct drr_write *drrw = &rrd->header.drr_u.drr_write;
- err = receive_write(rwa, drrw, rrd->write_buf);
- /* if receive_write() is successful, it consumes the arc_buf */
- if (err != 0)
- dmu_return_arcbuf(rrd->write_buf);
- rrd->write_buf = NULL;
- rrd->payload = NULL;
- return (err);
- }
- case DRR_WRITE_BYREF:
- {
- struct drr_write_byref *drrwbr =
- &rrd->header.drr_u.drr_write_byref;
- return (receive_write_byref(rwa, drrwbr));
- }
- case DRR_WRITE_EMBEDDED:
- {
- struct drr_write_embedded *drrwe =
- &rrd->header.drr_u.drr_write_embedded;
- err = receive_write_embedded(rwa, drrwe, rrd->payload);
- kmem_free(rrd->payload, rrd->payload_size);
- rrd->payload = NULL;
- return (err);
- }
- case DRR_FREE:
- {
- struct drr_free *drrf = &rrd->header.drr_u.drr_free;
- return (receive_free(rwa, drrf));
- }
- case DRR_SPILL:
- {
- struct drr_spill *drrs = &rrd->header.drr_u.drr_spill;
- err = receive_spill(rwa, drrs, rrd->payload);
- kmem_free(rrd->payload, rrd->payload_size);
- rrd->payload = NULL;
- return (err);
- }
- default:
- return (SET_ERROR(EINVAL));
- }
-}
-
-/*
- * dmu_recv_stream's worker thread; pull records off the queue, and then call
- * receive_process_record When we're done, signal the main thread and exit.
- */
-static void
-receive_writer_thread(void *arg)
-{
- struct receive_writer_arg *rwa = arg;
- struct receive_record_arg *rrd;
- for (rrd = bqueue_dequeue(&rwa->q); !rrd->eos_marker;
- rrd = bqueue_dequeue(&rwa->q)) {
- /*
- * If there's an error, the main thread will stop putting things
- * on the queue, but we need to clear everything in it before we
- * can exit.
- */
- if (rwa->err == 0) {
- rwa->err = receive_process_record(rwa, rrd);
- } else if (rrd->write_buf != NULL) {
- dmu_return_arcbuf(rrd->write_buf);
- rrd->write_buf = NULL;
- rrd->payload = NULL;
- } else if (rrd->payload != NULL) {
- kmem_free(rrd->payload, rrd->payload_size);
- rrd->payload = NULL;
- }
- kmem_free(rrd, sizeof (*rrd));
- }
- kmem_free(rrd, sizeof (*rrd));
- mutex_enter(&rwa->mutex);
- rwa->done = B_TRUE;
- cv_signal(&rwa->cv);
- mutex_exit(&rwa->mutex);
- thread_exit();
-}
-
-static int
-resume_check(struct receive_arg *ra, nvlist_t *begin_nvl)
-{
- uint64_t val;
- objset_t *mos = dmu_objset_pool(ra->os)->dp_meta_objset;
- uint64_t dsobj = dmu_objset_id(ra->os);
- uint64_t resume_obj, resume_off;
-
- if (nvlist_lookup_uint64(begin_nvl,
- "resume_object", &resume_obj) != 0 ||
- nvlist_lookup_uint64(begin_nvl,
- "resume_offset", &resume_off) != 0) {
- return (SET_ERROR(EINVAL));
- }
- VERIFY0(zap_lookup(mos, dsobj,
- DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val));
- if (resume_obj != val)
- return (SET_ERROR(EINVAL));
- VERIFY0(zap_lookup(mos, dsobj,
- DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val));
- if (resume_off != val)
- return (SET_ERROR(EINVAL));
-
- return (0);
-}
-
-/*
- * Read in the stream's records, one by one, and apply them to the pool. There
- * are two threads involved; the thread that calls this function will spin up a
- * worker thread, read the records off the stream one by one, and issue
- * prefetches for any necessary indirect blocks. It will then push the records
- * onto an internal blocking queue. The worker thread will pull the records off
- * the queue, and actually write the data into the DMU. This way, the worker
- * thread doesn't have to wait for reads to complete, since everything it needs
- * (the indirect blocks) will be prefetched.
- *
- * NB: callers *must* call dmu_recv_end() if this succeeds.
- */
-int
-dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
- int cleanup_fd, uint64_t *action_handlep)
-{
- int err = 0;
- struct receive_arg ra = { 0 };
- struct receive_writer_arg rwa = { 0 };
- int featureflags;
- nvlist_t *begin_nvl = NULL;
-
- ra.byteswap = drc->drc_byteswap;
- ra.cksum = drc->drc_cksum;
- ra.vp = vp;
- ra.voff = *voffp;
-
- if (dsl_dataset_is_zapified(drc->drc_ds)) {
- (void) zap_lookup(drc->drc_ds->ds_dir->dd_pool->dp_meta_objset,
- drc->drc_ds->ds_object, DS_FIELD_RESUME_BYTES,
- sizeof (ra.bytes_read), 1, &ra.bytes_read);
- }
-
- objlist_create(&ra.ignore_objlist);
-
- /* these were verified in dmu_recv_begin */
- ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==,
- DMU_SUBSTREAM);
- ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES);
-
- /*
- * Open the objset we are modifying.
- */
- VERIFY0(dmu_objset_from_ds(drc->drc_ds, &ra.os));
-
- ASSERT(dsl_dataset_phys(drc->drc_ds)->ds_flags & DS_FLAG_INCONSISTENT);
-
- featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo);
-
- /* if this stream is dedup'ed, set up the avl tree for guid mapping */
- if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {
- minor_t minor;
-
- if (cleanup_fd == -1) {
- ra.err = SET_ERROR(EBADF);
- goto out;
- }
- ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor);
- if (ra.err != 0) {
- cleanup_fd = -1;
- goto out;
- }
-
- if (*action_handlep == 0) {
- rwa.guid_to_ds_map =
- kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
- avl_create(rwa.guid_to_ds_map, guid_compare,
- sizeof (guid_map_entry_t),
- offsetof(guid_map_entry_t, avlnode));
- err = zfs_onexit_add_cb(minor,
- free_guid_map_onexit, rwa.guid_to_ds_map,
- action_handlep);
- if (ra.err != 0)
- goto out;
- } else {
- err = zfs_onexit_cb_data(minor, *action_handlep,
- (void **)&rwa.guid_to_ds_map);
- if (ra.err != 0)
- goto out;
- }
-
- drc->drc_guid_to_ds_map = rwa.guid_to_ds_map;
- }
-
- uint32_t payloadlen = drc->drc_drr_begin->drr_payloadlen;
- void *payload = NULL;
- if (payloadlen != 0)
- payload = kmem_alloc(payloadlen, KM_SLEEP);
-
- err = receive_read_payload_and_next_header(&ra, payloadlen, payload);
- if (err != 0) {
- if (payloadlen != 0)
- kmem_free(payload, payloadlen);
- goto out;
- }
- if (payloadlen != 0) {
- err = nvlist_unpack(payload, payloadlen, &begin_nvl, KM_SLEEP);
- kmem_free(payload, payloadlen);
- if (err != 0)
- goto out;
- }
-
- if (featureflags & DMU_BACKUP_FEATURE_RESUMING) {
- err = resume_check(&ra, begin_nvl);
- if (err != 0)
- goto out;
- }
-
- (void) bqueue_init(&rwa.q, zfs_recv_queue_length,
- offsetof(struct receive_record_arg, node));
- cv_init(&rwa.cv, NULL, CV_DEFAULT, NULL);
- mutex_init(&rwa.mutex, NULL, MUTEX_DEFAULT, NULL);
- rwa.os = ra.os;
- rwa.byteswap = drc->drc_byteswap;
- rwa.resumable = drc->drc_resumable;
-
- (void) thread_create(NULL, 0, receive_writer_thread, &rwa, 0, curproc,
- TS_RUN, minclsyspri);
- /*
- * We're reading rwa.err without locks, which is safe since we are the
- * only reader, and the worker thread is the only writer. It's ok if we
- * miss a write for an iteration or two of the loop, since the writer
- * thread will keep freeing records we send it until we send it an eos
- * marker.
- *
- * We can leave this loop in 3 ways: First, if rwa.err is
- * non-zero. In that case, the writer thread will free the rrd we just
- * pushed. Second, if we're interrupted; in that case, either it's the
- * first loop and ra.rrd was never allocated, or it's later, and ra.rrd
- * has been handed off to the writer thread who will free it. Finally,
- * if receive_read_record fails or we're at the end of the stream, then
- * we free ra.rrd and exit.
- */
- while (rwa.err == 0) {
- if (issig(JUSTLOOKING) && issig(FORREAL)) {
- err = SET_ERROR(EINTR);
- break;
- }
-
- ASSERT3P(ra.rrd, ==, NULL);
- ra.rrd = ra.next_rrd;
- ra.next_rrd = NULL;
- /* Allocates and loads header into ra.next_rrd */
- err = receive_read_record(&ra);
-
- if (ra.rrd->header.drr_type == DRR_END || err != 0) {
- kmem_free(ra.rrd, sizeof (*ra.rrd));
- ra.rrd = NULL;
- break;
- }
-
- bqueue_enqueue(&rwa.q, ra.rrd,
- sizeof (struct receive_record_arg) + ra.rrd->payload_size);
- ra.rrd = NULL;
- }
- if (ra.next_rrd == NULL)
- ra.next_rrd = kmem_zalloc(sizeof (*ra.next_rrd), KM_SLEEP);
- ra.next_rrd->eos_marker = B_TRUE;
- bqueue_enqueue(&rwa.q, ra.next_rrd, 1);
-
- mutex_enter(&rwa.mutex);
- while (!rwa.done) {
- cv_wait(&rwa.cv, &rwa.mutex);
- }
- mutex_exit(&rwa.mutex);
-
- /*
- * If we are receiving a full stream as a clone, all object IDs which
- * are greater than the maximum ID referenced in the stream are
- * by definition unused and must be freed. Note that it's possible that
- * we've resumed this send and the first record we received was the END
- * record. In that case, max_object would be 0, but we shouldn't start
- * freeing all objects from there; instead we should start from the
- * resumeobj.
- */
- if (drc->drc_clone && drc->drc_drrb->drr_fromguid == 0) {
- uint64_t obj;
- if (nvlist_lookup_uint64(begin_nvl, "resume_object", &obj) != 0)
- obj = 0;
- if (rwa.max_object > obj)
- obj = rwa.max_object;
- obj++;
- int free_err = 0;
- int next_err = 0;
-
- while (next_err == 0) {
- free_err = dmu_free_long_object(rwa.os, obj);
- if (free_err != 0 && free_err != ENOENT)
- break;
-
- next_err = dmu_object_next(rwa.os, &obj, FALSE, 0);
- }
-
- if (err == 0) {
- if (free_err != 0 && free_err != ENOENT)
- err = free_err;
- else if (next_err != ESRCH)
- err = next_err;
- }
- }
-
- cv_destroy(&rwa.cv);
- mutex_destroy(&rwa.mutex);
- bqueue_destroy(&rwa.q);
- if (err == 0)
- err = rwa.err;
-
-out:
- nvlist_free(begin_nvl);
- if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1))
- zfs_onexit_fd_rele(cleanup_fd);
-
- if (err != 0) {
- /*
- * Clean up references. If receive is not resumable,
- * destroy what we created, so we don't leave it in
- * the inconsistent state.
- */
- dmu_recv_cleanup_ds(drc);
- }
-
- *voffp = ra.voff;
- objlist_destroy(&ra.ignore_objlist);
- return (err);
-}
-
-static int
-dmu_recv_end_check(void *arg, dmu_tx_t *tx)
-{
- dmu_recv_cookie_t *drc = arg;
- dsl_pool_t *dp = dmu_tx_pool(tx);
- int error;
-
- ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag);
-
- if (!drc->drc_newfs) {
- dsl_dataset_t *origin_head;
-
- error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
- if (error != 0)
- return (error);
- if (drc->drc_force) {
- /*
- * We will destroy any snapshots in tofs (i.e. before
- * origin_head) that are after the origin (which is
- * the snap before drc_ds, because drc_ds can not
- * have any snaps of its own).
- */
- uint64_t obj;
-
- obj = dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
- while (obj !=
- dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj) {
- dsl_dataset_t *snap;
- error = dsl_dataset_hold_obj(dp, obj, FTAG,
- &snap);
- if (error != 0)
- break;
- if (snap->ds_dir != origin_head->ds_dir)
- error = SET_ERROR(EINVAL);
- if (error == 0) {
- error = dsl_destroy_snapshot_check_impl(
- snap, B_FALSE);
- }
- obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
- dsl_dataset_rele(snap, FTAG);
- if (error != 0)
- break;
- }
- if (error != 0) {
- dsl_dataset_rele(origin_head, FTAG);
- return (error);
- }
- }
- error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
- origin_head, drc->drc_force, drc->drc_owner, tx);
- if (error != 0) {
- dsl_dataset_rele(origin_head, FTAG);
- return (error);
- }
- error = dsl_dataset_snapshot_check_impl(origin_head,
- drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
- dsl_dataset_rele(origin_head, FTAG);
- if (error != 0)
- return (error);
-
- error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
- } else {
- error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
- drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
- }
- return (error);
-}
-
-static void
-dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
-{
- dmu_recv_cookie_t *drc = arg;
- dsl_pool_t *dp = dmu_tx_pool(tx);
-
- spa_history_log_internal_ds(drc->drc_ds, "finish receiving",
- tx, "snap=%s", drc->drc_tosnap);
-
- if (!drc->drc_newfs) {
- dsl_dataset_t *origin_head;
-
- VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
- &origin_head));
-
- if (drc->drc_force) {
- /*
- * Destroy any snapshots of drc_tofs (origin_head)
- * after the origin (the snap before drc_ds).
- */
- uint64_t obj;
-
- obj = dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
- while (obj !=
- dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj) {
- dsl_dataset_t *snap;
- VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG,
- &snap));
- ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir);
- obj = dsl_dataset_phys(snap)->ds_prev_snap_obj;
- dsl_destroy_snapshot_sync_impl(snap,
- B_FALSE, tx);
- dsl_dataset_rele(snap, FTAG);
- }
- }
- VERIFY3P(drc->drc_ds->ds_prev, ==,
- origin_head->ds_prev);
-
- dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
- origin_head, tx);
- dsl_dataset_snapshot_sync_impl(origin_head,
- drc->drc_tosnap, tx);
-
- /* set snapshot's creation time and guid */
- dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx);
- dsl_dataset_phys(origin_head->ds_prev)->ds_creation_time =
- drc->drc_drrb->drr_creation_time;
- dsl_dataset_phys(origin_head->ds_prev)->ds_guid =
- drc->drc_drrb->drr_toguid;
- dsl_dataset_phys(origin_head->ds_prev)->ds_flags &=
- ~DS_FLAG_INCONSISTENT;
-
- dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
- dsl_dataset_phys(origin_head)->ds_flags &=
- ~DS_FLAG_INCONSISTENT;
-
- drc->drc_newsnapobj =
- dsl_dataset_phys(origin_head)->ds_prev_snap_obj;
-
- dsl_dataset_rele(origin_head, FTAG);
- dsl_destroy_head_sync_impl(drc->drc_ds, tx);
-
- if (drc->drc_owner != NULL)
- VERIFY3P(origin_head->ds_owner, ==, drc->drc_owner);
- } else {
- dsl_dataset_t *ds = drc->drc_ds;
-
- dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx);
-
- /* set snapshot's creation time and guid */
- dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
- dsl_dataset_phys(ds->ds_prev)->ds_creation_time =
- drc->drc_drrb->drr_creation_time;
- dsl_dataset_phys(ds->ds_prev)->ds_guid =
- drc->drc_drrb->drr_toguid;
- dsl_dataset_phys(ds->ds_prev)->ds_flags &=
- ~DS_FLAG_INCONSISTENT;
-
- dmu_buf_will_dirty(ds->ds_dbuf, tx);
- dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
- if (dsl_dataset_has_resume_receive_state(ds)) {
- (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_FROMGUID, tx);
- (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_OBJECT, tx);
- (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_OFFSET, tx);
- (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_BYTES, tx);
- (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_TOGUID, tx);
- (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
- DS_FIELD_RESUME_TONAME, tx);
- }
- drc->drc_newsnapobj =
- dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
- }
- /*
- * Release the hold from dmu_recv_begin. This must be done before
- * we return to open context, so that when we free the dataset's dnode,
- * we can evict its bonus buffer.
- */
- dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
- drc->drc_ds = NULL;
-}
-
-static int
-add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj)
-{
- dsl_pool_t *dp;
- dsl_dataset_t *snapds;
- guid_map_entry_t *gmep;
- int err;
-
- ASSERT(guid_map != NULL);
-
- err = dsl_pool_hold(name, FTAG, &dp);
- if (err != 0)
- return (err);
- gmep = kmem_alloc(sizeof (*gmep), KM_SLEEP);
- err = dsl_dataset_hold_obj(dp, snapobj, gmep, &snapds);
- if (err == 0) {
- gmep->guid = dsl_dataset_phys(snapds)->ds_guid;
- gmep->gme_ds = snapds;
- avl_add(guid_map, gmep);
- dsl_dataset_long_hold(snapds, gmep);
- } else {
- kmem_free(gmep, sizeof (*gmep));
- }
-
- dsl_pool_rele(dp, FTAG);
- return (err);
-}
-
-static int dmu_recv_end_modified_blocks = 3;
-
-static int
-dmu_recv_existing_end(dmu_recv_cookie_t *drc)
-{
-#ifdef _KERNEL
- /*
- * We will be destroying the ds; make sure its origin is unmounted if
- * necessary.
- */
- char name[ZFS_MAX_DATASET_NAME_LEN];
- dsl_dataset_name(drc->drc_ds, name);
- zfs_destroy_unmount_origin(name);
-#endif
-
- return (dsl_sync_task(drc->drc_tofs,
- dmu_recv_end_check, dmu_recv_end_sync, drc,
- dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
-}
-
-static int
-dmu_recv_new_end(dmu_recv_cookie_t *drc)
-{
- return (dsl_sync_task(drc->drc_tofs,
- dmu_recv_end_check, dmu_recv_end_sync, drc,
- dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL));
-}
-
-int
-dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
-{
- int error;
-
- drc->drc_owner = owner;
-
- if (drc->drc_newfs)
- error = dmu_recv_new_end(drc);
- else
- error = dmu_recv_existing_end(drc);
-
- if (error != 0) {
- dmu_recv_cleanup_ds(drc);
- } else if (drc->drc_guid_to_ds_map != NULL) {
- (void) add_ds_to_guidmap(drc->drc_tofs,
- drc->drc_guid_to_ds_map,
- drc->drc_newsnapobj);
- }
- return (error);
-}
-
-/*
- * Return TRUE if this objset is currently being received into.
- */
-boolean_t
-dmu_objset_is_receiving(objset_t *os)
-{
- return (os->os_dsl_dataset != NULL &&
- os->os_dsl_dataset->ds_owner == dmu_recv_tag);
-}
diff --git a/usr/src/uts/common/fs/zfs/dnode.c b/usr/src/uts/common/fs/zfs/dnode.c
index 972aebf45c..2f9e188454 100644
--- a/usr/src/uts/common/fs/zfs/dnode.c
+++ b/usr/src/uts/common/fs/zfs/dnode.c
@@ -150,7 +150,7 @@ dnode_cons(void *arg, void *unused, int kmflag)
bzero(&dn->dn_next_blksz[0], sizeof (dn->dn_next_blksz));
for (i = 0; i < TXG_SIZE; i++) {
- list_link_init(&dn->dn_dirty_link[i]);
+ multilist_link_init(&dn->dn_dirty_link[i]);
dn->dn_free_ranges[i] = NULL;
list_create(&dn->dn_dirty_records[i],
sizeof (dbuf_dirty_record_t),
@@ -160,6 +160,7 @@ dnode_cons(void *arg, void *unused, int kmflag)
dn->dn_allocated_txg = 0;
dn->dn_free_txg = 0;
dn->dn_assigned_txg = 0;
+ dn->dn_dirty_txg = 0;
dn->dn_dirtyctx = 0;
dn->dn_dirtyctx_firstset = NULL;
dn->dn_bonus = NULL;
@@ -197,7 +198,7 @@ dnode_dest(void *arg, void *unused)
ASSERT(!list_link_active(&dn->dn_link));
for (i = 0; i < TXG_SIZE; i++) {
- ASSERT(!list_link_active(&dn->dn_dirty_link[i]));
+ ASSERT(!multilist_link_active(&dn->dn_dirty_link[i]));
ASSERT3P(dn->dn_free_ranges[i], ==, NULL);
list_destroy(&dn->dn_dirty_records[i]);
ASSERT0(dn->dn_next_nblkptr[i]);
@@ -212,6 +213,7 @@ dnode_dest(void *arg, void *unused)
ASSERT0(dn->dn_allocated_txg);
ASSERT0(dn->dn_free_txg);
ASSERT0(dn->dn_assigned_txg);
+ ASSERT0(dn->dn_dirty_txg);
ASSERT0(dn->dn_dirtyctx);
ASSERT3P(dn->dn_dirtyctx_firstset, ==, NULL);
ASSERT3P(dn->dn_bonus, ==, NULL);
@@ -543,6 +545,7 @@ dnode_destroy(dnode_t *dn)
dn->dn_allocated_txg = 0;
dn->dn_free_txg = 0;
dn->dn_assigned_txg = 0;
+ dn->dn_dirty_txg = 0;
dn->dn_dirtyctx = 0;
if (dn->dn_dirtyctx_firstset != NULL) {
@@ -612,6 +615,7 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
ASSERT(dn->dn_type == DMU_OT_NONE);
ASSERT0(dn->dn_maxblkid);
ASSERT0(dn->dn_allocated_txg);
+ ASSERT0(dn->dn_dirty_txg);
ASSERT0(dn->dn_assigned_txg);
ASSERT(zfs_refcount_is_zero(&dn->dn_tx_holds));
ASSERT3U(zfs_refcount_count(&dn->dn_holds), <=, 1);
@@ -625,7 +629,7 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
ASSERT0(dn->dn_next_bonustype[i]);
ASSERT0(dn->dn_rm_spillblk[i]);
ASSERT0(dn->dn_next_blksz[i]);
- ASSERT(!list_link_active(&dn->dn_dirty_link[i]));
+ ASSERT(!multilist_link_active(&dn->dn_dirty_link[i]));
ASSERT3P(list_head(&dn->dn_dirty_records[i]), ==, NULL);
ASSERT3P(dn->dn_free_ranges[i], ==, NULL);
}
@@ -683,8 +687,7 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
ASSERT(DMU_OT_IS_VALID(bonustype));
ASSERT3U(bonuslen, <=,
DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(dn->dn_objset))));
-
- dn_slots = dn_slots > 0 ? dn_slots : DNODE_MIN_SLOTS;
+ ASSERT3U(bonuslen, <=, DN_BONUS_SIZE(dn_slots << DNODE_SHIFT));
dnode_free_interior_slots(dn);
DNODE_STAT_BUMP(dnode_reallocate);
@@ -803,6 +806,7 @@ dnode_move_impl(dnode_t *odn, dnode_t *ndn)
ndn->dn_allocated_txg = odn->dn_allocated_txg;
ndn->dn_free_txg = odn->dn_free_txg;
ndn->dn_assigned_txg = odn->dn_assigned_txg;
+ ndn->dn_dirty_txg = odn->dn_dirty_txg;
ndn->dn_dirtyctx = odn->dn_dirtyctx;
ndn->dn_dirtyctx_firstset = odn->dn_dirtyctx_firstset;
ASSERT(zfs_refcount_count(&odn->dn_tx_holds) == 0);
@@ -869,6 +873,7 @@ dnode_move_impl(dnode_t *odn, dnode_t *ndn)
odn->dn_allocated_txg = 0;
odn->dn_free_txg = 0;
odn->dn_assigned_txg = 0;
+ odn->dn_dirty_txg = 0;
odn->dn_dirtyctx = 0;
odn->dn_dirtyctx_firstset = NULL;
odn->dn_have_spill = B_FALSE;
@@ -1093,6 +1098,10 @@ dnode_check_slots_free(dnode_children_t *children, int idx, int slots)
{
ASSERT3S(idx + slots, <=, DNODES_PER_BLOCK);
+ /*
+ * If all dnode slots are either already free or
+ * evictable return B_TRUE.
+ */
for (int i = idx; i < idx + slots; i++) {
dnode_handle_t *dnh = &children->dnc_children[i];
dnode_t *dn = dnh->dnh_dnode;
@@ -1101,18 +1110,18 @@ dnode_check_slots_free(dnode_children_t *children, int idx, int slots)
continue;
} else if (DN_SLOT_IS_PTR(dn)) {
mutex_enter(&dn->dn_mtx);
- dmu_object_type_t type = dn->dn_type;
+ boolean_t can_free = (dn->dn_type == DMU_OT_NONE &&
+ zfs_refcount_is_zero(&dn->dn_holds) &&
+ !DNODE_IS_DIRTY(dn));
mutex_exit(&dn->dn_mtx);
- if (type != DMU_OT_NONE)
+ if (!can_free)
return (B_FALSE);
-
- continue;
+ else
+ continue;
} else {
return (B_FALSE);
}
-
- return (B_FALSE);
}
return (B_TRUE);
@@ -1635,7 +1644,7 @@ dnode_setdirty(dnode_t *dn, dmu_tx_t *tx)
/*
* If we are already marked dirty, we're done.
*/
- if (list_link_active(&dn->dn_dirty_link[txg & TXG_MASK])) {
+ if (multilist_link_active(&dn->dn_dirty_link[txg & TXG_MASK])) {
multilist_sublist_unlock(mls);
return;
}
diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c
index 27873c0d45..caa6855034 100644
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c
@@ -56,7 +56,7 @@
#include <sys/dsl_destroy.h>
#include <sys/dsl_userhold.h>
#include <sys/dsl_bookmark.h>
-#include <sys/dmu_send.h>
+#include <sys/dmu_recv.h>
#include <sys/zio_checksum.h>
#include <sys/zio_compress.h>
#include <zfs_fletcher.h>
diff --git a/usr/src/uts/common/fs/zfs/metaslab.c b/usr/src/uts/common/fs/zfs/metaslab.c
index f652a3ef1a..04e44b8feb 100644
--- a/usr/src/uts/common/fs/zfs/metaslab.c
+++ b/usr/src/uts/common/fs/zfs/metaslab.c
@@ -720,6 +720,7 @@ metaslab_group_activate(metaslab_group_t *mg)
{
metaslab_class_t *mc = mg->mg_class;
metaslab_group_t *mgprev, *mgnext;
+ char kstat_name[KSTAT_STRLEN];
ASSERT3U(spa_config_held(mc->mc_spa, SCL_ALLOC, RW_WRITER), !=, 0);
@@ -744,6 +745,33 @@ metaslab_group_activate(metaslab_group_t *mg)
mgprev->mg_next = mg;
mgnext->mg_prev = mg;
}
+
+ /* Create a kstat to monitor the loading and unloading of metaslabs. */
+ (void) snprintf(kstat_name, sizeof (kstat_name), "%llx",
+ (unsigned long long) mg->mg_vd->vdev_guid);
+
+ mutex_init(&mg->mg_kstat_lock, NULL, MUTEX_DEFAULT, NULL);
+ if ((mg->mg_kstat = kstat_create("zfs_metaslab_group", 0,
+ kstat_name, "misc", KSTAT_TYPE_NAMED,
+ sizeof (metaslab_group_kstat_t) / sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL)) != NULL) {
+
+ metaslab_group_kstat_t *mg_kstat = kmem_zalloc(
+ sizeof (metaslab_group_kstat_t), KM_SLEEP);
+ kstat_named_init(&mg_kstat->mg_loads, "loads",
+ KSTAT_DATA_UINT64);
+ kstat_named_init(&mg_kstat->mg_unloads, "unloads",
+ KSTAT_DATA_UINT64);
+ kstat_named_init(&mg_kstat->mg_spa_name, "spa_name",
+ KSTAT_DATA_STRING);
+ kstat_named_setstr(&mg_kstat->mg_spa_name,
+ mg->mg_vd->vdev_spa->spa_name);
+
+ mg->mg_kstat->ks_data = mg_kstat;
+ mg->mg_kstat->ks_lock = &mg->mg_kstat_lock;
+ kstat_install(mg->mg_kstat);
+ }
+
mc->mc_rotor = mg;
}
@@ -820,6 +848,11 @@ metaslab_group_passivate(metaslab_group_t *mg)
mg->mg_prev = NULL;
mg->mg_next = NULL;
+
+ if (mg->mg_kstat != NULL) {
+ kstat_delete(mg->mg_kstat);
+ }
+ mutex_destroy(&mg->mg_kstat_lock);
}
boolean_t
@@ -1538,6 +1571,7 @@ metaslab_load_impl(metaslab_t *msp)
int
metaslab_load(metaslab_t *msp, uint64_t txg)
{
+ kstat_t *ksp;
ASSERT(MUTEX_HELD(&msp->ms_lock));
/*
@@ -1549,6 +1583,12 @@ metaslab_load(metaslab_t *msp, uint64_t txg)
return (0);
VERIFY(!msp->ms_loading);
+ ksp = msp->ms_group->mg_kstat;
+ if (ksp != NULL) {
+ metaslab_group_kstat_t *mg_ksp = ksp->ks_data;
+ atomic_inc_64(&mg_ksp->mg_loads.value.ui64);
+ }
+
msp->ms_loading = B_TRUE;
int error = metaslab_load_impl(msp);
msp->ms_loading = B_FALSE;
@@ -1562,6 +1602,14 @@ void
metaslab_unload(metaslab_t *msp)
{
ASSERT(MUTEX_HELD(&msp->ms_lock));
+
+ if (msp->ms_group != NULL) {
+ kstat_t *ksp = msp->ms_group->mg_kstat;
+ if (ksp != NULL) {
+ metaslab_group_kstat_t *mg_ksp = ksp->ks_data;
+ atomic_inc_64(&mg_ksp->mg_unloads.value.ui64);
+ }
+ }
range_tree_vacate(msp->ms_allocatable, NULL, NULL);
msp->ms_loaded = B_FALSE;
msp->ms_loaded_txg = 0;
diff --git a/usr/src/uts/common/fs/zfs/sys/arc.h b/usr/src/uts/common/fs/zfs/sys/arc.h
index 641ae93e9c..87d2d1d329 100644
--- a/usr/src/uts/common/fs/zfs/sys/arc.h
+++ b/usr/src/uts/common/fs/zfs/sys/arc.h
@@ -170,6 +170,7 @@ void arc_loan_inuse_buf(arc_buf_t *buf, void *tag);
void arc_buf_destroy(arc_buf_t *buf, void *tag);
int arc_buf_size(arc_buf_t *buf);
int arc_buf_lsize(arc_buf_t *buf);
+void arc_buf_access(arc_buf_t *buf);
void arc_release(arc_buf_t *buf, void *tag);
int arc_released(arc_buf_t *buf);
void arc_buf_freeze(arc_buf_t *buf);
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu_impl.h b/usr/src/uts/common/fs/zfs/sys/dmu_impl.h
index 0930be6a85..e820fe57ec 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu_impl.h
@@ -162,7 +162,7 @@ extern "C" {
* dn_allocated_txg
* dn_free_txg
* dn_assigned_txg
- * dd_assigned_tx
+ * dn_dirty_txg
* dn_notxholds
* dn_dirtyctx
* dn_dirtyctx_firstset
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu_recv.h b/usr/src/uts/common/fs/zfs/sys/dmu_recv.h
new file mode 100644
index 0000000000..56b69e61b1
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/dmu_recv.h
@@ -0,0 +1,64 @@
+/*
+ * 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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ */
+
+#ifndef _DMU_RECV_H
+#define _DMU_RECV_H
+
+#include <sys/inttypes.h>
+#include <sys/spa.h>
+
+extern const char *recv_clone_name;
+
+typedef struct dmu_recv_cookie {
+ struct dsl_dataset *drc_ds;
+ struct dmu_replay_record *drc_drr_begin;
+ struct drr_begin *drc_drrb;
+ const char *drc_tofs;
+ const char *drc_tosnap;
+ boolean_t drc_newfs;
+ boolean_t drc_byteswap;
+ boolean_t drc_force;
+ boolean_t drc_resumable;
+ boolean_t drc_clone;
+ struct avl_tree *drc_guid_to_ds_map;
+ zio_cksum_t drc_cksum;
+ uint64_t drc_newsnapobj;
+ void *drc_owner;
+ cred_t *drc_cred;
+} dmu_recv_cookie_t;
+
+int dmu_recv_begin(char *tofs, char *tosnap,
+ struct dmu_replay_record *drr_begin,
+ boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc);
+int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp,
+ int cleanup_fd, uint64_t *action_handlep);
+int dmu_recv_end(dmu_recv_cookie_t *drc, void *owner);
+boolean_t dmu_objset_is_receiving(objset_t *os);
+
+#endif /* _DMU_RECV_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu_send.h b/usr/src/uts/common/fs/zfs/sys/dmu_send.h
index b8403313e9..65d8e99db6 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu_send.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu_send.h
@@ -39,8 +39,6 @@ struct drr_begin;
struct avl_tree;
struct dmu_replay_record;
-extern const char *recv_clone_name;
-
int dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
boolean_t large_block_ok, boolean_t compressok, int outfd,
uint64_t resumeobj, uint64_t resumeoff,
@@ -53,30 +51,4 @@ int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
boolean_t embedok, boolean_t large_block_ok, boolean_t compressok,
int outfd, struct vnode *vp, offset_t *off);
-typedef struct dmu_recv_cookie {
- struct dsl_dataset *drc_ds;
- struct dmu_replay_record *drc_drr_begin;
- struct drr_begin *drc_drrb;
- const char *drc_tofs;
- const char *drc_tosnap;
- boolean_t drc_newfs;
- boolean_t drc_byteswap;
- boolean_t drc_force;
- boolean_t drc_resumable;
- boolean_t drc_clone;
- struct avl_tree *drc_guid_to_ds_map;
- zio_cksum_t drc_cksum;
- uint64_t drc_newsnapobj;
- void *drc_owner;
- cred_t *drc_cred;
-} dmu_recv_cookie_t;
-
-int dmu_recv_begin(char *tofs, char *tosnap,
- struct dmu_replay_record *drr_begin,
- boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc);
-int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp,
- int cleanup_fd, uint64_t *action_handlep);
-int dmu_recv_end(dmu_recv_cookie_t *drc, void *owner);
-boolean_t dmu_objset_is_receiving(objset_t *os);
-
#endif /* _DMU_SEND_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/dnode.h b/usr/src/uts/common/fs/zfs/sys/dnode.h
index 167ae789b6..3b7d619172 100644
--- a/usr/src/uts/common/fs/zfs/sys/dnode.h
+++ b/usr/src/uts/common/fs/zfs/sys/dnode.h
@@ -296,6 +296,7 @@ struct dnode {
uint64_t dn_allocated_txg;
uint64_t dn_free_txg;
uint64_t dn_assigned_txg;
+ uint64_t dn_dirty_txg; /* txg dnode was last dirtied */
kcondvar_t dn_notxholds;
enum dnode_dirtycontext dn_dirtyctx;
uint8_t *dn_dirtyctx_firstset; /* dbg: contents meaningless */
@@ -399,6 +400,9 @@ void dnode_evict_bonus(dnode_t *dn);
void dnode_free_interior_slots(dnode_t *dn);
boolean_t dnode_needs_remap(const dnode_t *dn);
+#define DNODE_IS_DIRTY(_dn) \
+ ((_dn)->dn_dirty_txg >= spa_syncing_txg((_dn)->dn_objset->os_spa))
+
#define DNODE_IS_CACHEABLE(_dn) \
((_dn)->dn_objset->os_primary_cache == ZFS_CACHE_ALL || \
(DMU_OT_IS_METADATA((_dn)->dn_type) && \
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_bookmark.h b/usr/src/uts/common/fs/zfs/sys/dsl_bookmark.h
index 3591986d7b..e477bb231c 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_bookmark.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_bookmark.h
@@ -20,6 +20,7 @@
#define _SYS_DSL_BOOKMARK_H
#include <sys/zfs_context.h>
+#include <sys/dsl_dataset.h>
#ifdef __cplusplus
extern "C" {
diff --git a/usr/src/uts/common/fs/zfs/sys/metaslab_impl.h b/usr/src/uts/common/fs/zfs/sys/metaslab_impl.h
index a04264a23f..33da2a0c00 100644
--- a/usr/src/uts/common/fs/zfs/sys/metaslab_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/metaslab_impl.h
@@ -276,8 +276,17 @@ struct metaslab_group {
boolean_t mg_initialize_updating;
kmutex_t mg_ms_initialize_lock;
kcondvar_t mg_ms_initialize_cv;
+
+ kstat_t *mg_kstat;
+ kmutex_t mg_kstat_lock;
};
+typedef struct metaslab_group_kstat {
+ kstat_named_t mg_loads;
+ kstat_named_t mg_unloads;
+ kstat_named_t mg_spa_name;
+} metaslab_group_kstat_t;
+
/*
* This value defines the number of elements in the ms_lbas array. The value
* of 64 was chosen as it covers all power of 2 buckets up to UINT64_MAX.
diff --git a/usr/src/uts/common/fs/zfs/sys/zap.h b/usr/src/uts/common/fs/zfs/sys/zap.h
index e7f5358140..15e912d1c3 100644
--- a/usr/src/uts/common/fs/zfs/sys/zap.h
+++ b/usr/src/uts/common/fs/zfs/sys/zap.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright 2017 Nexenta Systems, Inc.
*/
@@ -347,6 +347,7 @@ typedef struct zap_cursor {
uint64_t zc_serialized;
uint64_t zc_hash;
uint32_t zc_cd;
+ boolean_t zc_prefetch;
} zap_cursor_t;
typedef struct {
@@ -373,6 +374,8 @@ typedef struct {
* zapobj. You must _fini the cursor when you are done with it.
*/
void zap_cursor_init(zap_cursor_t *zc, objset_t *ds, uint64_t zapobj);
+void zap_cursor_init_noprefetch(zap_cursor_t *zc, objset_t *os,
+ uint64_t zapobj);
void zap_cursor_fini(zap_cursor_t *zc);
/*
diff --git a/usr/src/uts/common/fs/zfs/zap.c b/usr/src/uts/common/fs/zfs/zap.c
index 7a1994f603..de8e212077 100644
--- a/usr/src/uts/common/fs/zfs/zap.c
+++ b/usr/src/uts/common/fs/zfs/zap.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
*/
@@ -49,6 +49,36 @@
#include <sys/zap_impl.h>
#include <sys/zap_leaf.h>
+/*
+ * If zap_iterate_prefetch is set, we will prefetch the entire ZAP object
+ * (all leaf blocks) when we start iterating over it.
+ *
+ * For zap_cursor_init(), the callers all intend to iterate through all the
+ * entries. There are a few cases where an error (typically i/o error) could
+ * cause it to bail out early.
+ *
+ * For zap_cursor_init_serialized(), there are callers that do the iteration
+ * outside of ZFS. Typically they would iterate over everything, but we
+ * don't have control of that. E.g. zfs_ioc_snapshot_list_next(),
+ * zcp_snapshots_iter(), and other iterators over things in the MOS - these
+ * are called by /sbin/zfs and channel programs. The other example is
+ * zfs_readdir() which iterates over directory entries for the getdents()
+ * syscall. /sbin/ls iterates to the end (unless it receives a signal), but
+ * userland doesn't have to.
+ *
+ * Given that the ZAP entries aren't returned in a specific order, the only
+ * legitimate use cases for partial iteration would be:
+ *
+ * 1. Pagination: e.g. you only want to display 100 entries at a time, so you
+ * get the first 100 and then wait for the user to hit "next page", which
+ * they may never do).
+ *
+ * 2. You want to know if there are more than X entries, without relying on
+ * the zfs-specific implementation of the directory's st_size (which is
+ * the number of entries).
+ */
+boolean_t zap_iterate_prefetch = B_TRUE;
+
int fzap_default_block_shift = 14; /* 16k blocksize */
extern inline zap_phys_t *zap_f_phys(zap_t *zap);
@@ -1169,6 +1199,20 @@ fzap_cursor_retrieve(zap_t *zap, zap_cursor_t *zc, zap_attribute_t *za)
/* retrieve the next entry at or after zc_hash/zc_cd */
/* if no entry, return ENOENT */
+ /*
+ * If we are reading from the beginning, we're almost
+ * certain to iterate over the entire ZAP object. If there are
+ * multiple leaf blocks (freeblk > 2), prefetch the whole
+ * object, so that we read the leaf blocks concurrently.
+ * (Unless noprefetch was requested via zap_cursor_init_noprefetch()).
+ */
+ if (zc->zc_hash == 0 && zap_iterate_prefetch &&
+ zc->zc_prefetch && zap_f_phys(zap)->zap_freeblk > 2) {
+ dmu_prefetch(zc->zc_objset, zc->zc_zapobj, 0, 0,
+ zap_f_phys(zap)->zap_freeblk << FZAP_BLOCK_SHIFT(zap),
+ ZIO_PRIORITY_ASYNC_READ);
+ }
+
if (zc->zc_leaf &&
(ZAP_HASH_IDX(zc->zc_hash,
zap_leaf_phys(zc->zc_leaf)->l_hdr.lh_prefix_len) !=
diff --git a/usr/src/uts/common/fs/zfs/zap_micro.c b/usr/src/uts/common/fs/zfs/zap_micro.c
index d093fe1e73..bb5da13ba1 100644
--- a/usr/src/uts/common/fs/zfs/zap_micro.c
+++ b/usr/src/uts/common/fs/zfs/zap_micro.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 Nexenta Systems, Inc.
@@ -1386,9 +1386,9 @@ zap_remove_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
* Routines for iterating over the attributes.
*/
-void
-zap_cursor_init_serialized(zap_cursor_t *zc, objset_t *os, uint64_t zapobj,
- uint64_t serialized)
+static void
+zap_cursor_init_impl(zap_cursor_t *zc, objset_t *os, uint64_t zapobj,
+ uint64_t serialized, boolean_t prefetch)
{
zc->zc_objset = os;
zc->zc_zap = NULL;
@@ -1397,12 +1397,33 @@ zap_cursor_init_serialized(zap_cursor_t *zc, objset_t *os, uint64_t zapobj,
zc->zc_serialized = serialized;
zc->zc_hash = 0;
zc->zc_cd = 0;
+ zc->zc_prefetch = prefetch;
+}
+void
+zap_cursor_init_serialized(zap_cursor_t *zc, objset_t *os, uint64_t zapobj,
+ uint64_t serialized)
+{
+ zap_cursor_init_impl(zc, os, zapobj, serialized, B_TRUE);
}
+/*
+ * Initialize a cursor at the beginning of the ZAP object. The entire
+ * ZAP object will be prefetched.
+ */
void
zap_cursor_init(zap_cursor_t *zc, objset_t *os, uint64_t zapobj)
{
- zap_cursor_init_serialized(zc, os, zapobj, 0);
+ zap_cursor_init_impl(zc, os, zapobj, 0, B_TRUE);
+}
+
+/*
+ * Initialize a cursor at the beginning, but request that we not prefetch
+ * the entire ZAP object.
+ */
+void
+zap_cursor_init_noprefetch(zap_cursor_t *zc, objset_t *os, uint64_t zapobj)
+{
+ zap_cursor_init_impl(zc, os, zapobj, 0, B_FALSE);
}
void
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 486b7398a4..22ed061953 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -181,6 +181,7 @@
#include <sys/dsl_scan.h>
#include <sharefs/share.h>
#include <sys/dmu_objset.h>
+#include <sys/dmu_recv.h>
#include <sys/dmu_send.h>
#include <sys/dsl_destroy.h>
#include <sys/dsl_bookmark.h>
@@ -5560,6 +5561,7 @@ zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
static int
zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
{
+ ASSERT3P(args, ==, NULL);
return (dsl_dataset_get_holds(snapname, outnvl));
}
@@ -5828,6 +5830,44 @@ out:
return (error);
}
+/*
+ * Sync the currently open TXG to disk for the specified pool.
+ * This is somewhat similar to 'zfs_sync()'.
+ * For cases that do not result in error this ioctl will wait for
+ * the currently open TXG to commit before returning back to the caller.
+ *
+ * innvl: {
+ * "force" -> when true, force uberblock update even if there is no dirty data.
+ * In addition this will cause the vdev configuration to be written
+ * out including updating the zpool cache file. (boolean_t)
+ * }
+ *
+ * onvl is unused
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl)
+{
+ int err;
+ boolean_t force;
+ spa_t *spa;
+
+ if ((err = spa_open(pool, &spa, FTAG)) != 0)
+ return (err);
+
+ force = fnvlist_lookup_boolean_value(innvl, "force");
+ if (force) {
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_WRITER);
+ vdev_config_dirty(spa->spa_root_vdev);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+ }
+ txg_wait_synced(spa_get_dsl(spa), 0);
+
+ spa_close(spa, FTAG);
+
+ return (err);
+}
+
static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST];
static void
@@ -6021,6 +6061,10 @@ zfs_ioctl_init(void)
zfs_ioc_pool_initialize, zfs_secpolicy_config, POOL_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ zfs_ioctl_register("sync", ZFS_IOC_POOL_SYNC,
+ zfs_ioc_pool_sync, zfs_secpolicy_none, POOL_NAME,
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE);
+
/* IOCTLS that use the legacy function signature */
zfs_ioctl_register_legacy("pool_freeze", ZFS_IOC_POOL_FREEZE,
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index a0ae38d4dd..e9a3fcdeeb 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -22,9 +22,9 @@
/*
* Copyright (c) 1990 Mentat Inc.
* Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017, Joyent, Inc. All rights reserved.
* Copyright 2017 Nexenta Systems, Inc.
* Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright 2019, Joyent, Inc.
*/
#ifndef _INET_IP_H
@@ -1709,7 +1709,8 @@ typedef struct ill_s {
ill_manual_dst_linklocal : 1, /* same for pt-pt dst linklocal */
- ill_pad_bit_31 : 27;
+ ill_mcast_ncec_cleanup : 1, /* Reaping mcast ncecs. */
+ ill_pad_bit_31 : 26;
/*
* Used in SIOCSIFMUXID and SIOCGIFMUXID for 'ifconfig unplumb'.
@@ -1777,6 +1778,7 @@ typedef struct ill_s {
*/
uint_t ill_dl_bind_err;
avl_node_t ill_avl_byppa; /* avl node based on ppa */
+ uint_t ill_mcast_nces; /* Number of NCEs that are multicast. */
list_t ill_nce; /* pointer to nce_s list */
uint_t ill_refcnt; /* active refcnt by threads */
uint_t ill_ire_cnt; /* ires associated with this ill */
@@ -1948,6 +1950,7 @@ typedef struct ill_s {
* ill_refcnt ill_lock ill_lock
* ill_ire_cnt ill_lock ill_lock
* ill_cv ill_lock ill_lock
+ * ill_mcast_nces ill_lock ill_lock
* ill_ncec_cnt ill_lock ill_lock
* ill_nce_cnt ill_lock ill_lock
* ill_ilm_cnt ill_lock ill_lock
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index f21f3f4d73..6054ad7e43 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -24,7 +24,7 @@
* Copyright (c) 1990 Mentat Inc.
* Copyright (c) 2017 OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
- * Copyright (c) 2018 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2019 Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -13887,6 +13887,9 @@ ip_kstat2_init(netstackid_t stackid, ip_stat_t *ip_statisticsp)
{ "ip_ire_reclaim_deleted", KSTAT_DATA_UINT64 },
{ "ip_nce_reclaim_calls", KSTAT_DATA_UINT64 },
{ "ip_nce_reclaim_deleted", KSTAT_DATA_UINT64 },
+ { "ip_nce_mcast_reclaim_calls", KSTAT_DATA_UINT64 },
+ { "ip_nce_mcast_reclaim_deleted", KSTAT_DATA_UINT64 },
+ { "ip_nce_mcast_reclaim_tqfail", KSTAT_DATA_UINT64 },
{ "ip_dce_reclaim_calls", KSTAT_DATA_UINT64 },
{ "ip_dce_reclaim_deleted", KSTAT_DATA_UINT64 },
{ "ip_tcp_in_full_hw_cksum_err", KSTAT_DATA_UINT64 },
diff --git a/usr/src/uts/common/inet/ip/ip_ndp.c b/usr/src/uts/common/inet/ip/ip_ndp.c
index 211e56633f..3e5d2087a6 100644
--- a/usr/src/uts/common/inet/ip/ip_ndp.c
+++ b/usr/src/uts/common/inet/ip/ip_ndp.c
@@ -23,7 +23,7 @@
*/
/*
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <sys/types.h>
@@ -127,8 +127,8 @@ static boolean_t ill_defend_rate_limit(ill_t *, ncec_t *);
static void nce_queue_mp_common(ncec_t *, mblk_t *, boolean_t);
static int nce_add_common(ill_t *, uchar_t *, uint_t, const in6_addr_t *,
uint16_t, uint16_t, nce_t **);
-static nce_t *nce_add_impl(ill_t *, ncec_t *, nce_t *, mblk_t *);
-static nce_t *nce_add(ill_t *, ncec_t *);
+static nce_t *nce_add_impl(ill_t *, ncec_t *, nce_t *, mblk_t *, list_t *);
+static nce_t *nce_add(ill_t *, ncec_t *, list_t *);
static void nce_inactive(nce_t *);
extern nce_t *nce_lookup(ill_t *, const in6_addr_t *);
static nce_t *nce_ill_lookup_then_add(ill_t *, ncec_t *);
@@ -1005,6 +1005,236 @@ ncec_walk(ill_t *ill, ncec_walk_cb_t cbf, void *arg1, ip_stack_t *ipst)
}
/*
+ * Cheesy globals (i.e. all netstacks) for both a limit on per-ill multicast
+ * NCEs, and the number to reclaim if we hit the limit. Used by
+ * nce_set_multicast_v[46]() to limit the linked-list length of ill_nce. Until
+ * we solve the multicast-mappings-shouldn't-be-NCEs problem, use this.
+ */
+
+/* Maximum number of multicast NCEs on an ill. */
+uint_t ip_max_ill_mcast_nces = 16384;
+/*
+ * Number of NCEs to delete if we hit the maximum above. 0 means *don't* and
+ * return an error. Non-zero means delete so many, and if the number is >=
+ * the max above, that means delete them all.
+ */
+uint_t ip_ill_mcast_reclaim = 256;
+
+/*
+ * Encapsulate multicast ill capping in a function, for easier DTrace
+ * detections. Return a list of refheld NCEs to destroy-via-refrele. That
+ * list can be NULL, but can only be non-NULL if we successfully reclaimed.
+ *
+ * NOTE: This function must be called while holding the ill_lock AND
+ * JUST PRIOR to making the insertion into the ill_nce list.
+ *
+ * We can't release the ones we delete ourselves because the ill_lock is held
+ * by the caller. They are, instead, passed back in a list_t for deletion
+ * outside of the ill_lock hold. nce_graveyard_free() actually frees them.
+ *
+ * While this covers nce_t, ncec_t gets done even further down the road. See
+ * nce_graveyard_free() for why.
+ */
+static boolean_t
+nce_too_many_mcast(ill_t *ill, list_t *graveyard)
+{
+ uint_t reclaim_count, max_count, reclaimed = 0;
+ boolean_t too_many;
+ nce_t *nce, *deadman;
+
+ ASSERT(graveyard != NULL);
+ ASSERT(list_is_empty(graveyard));
+ ASSERT(MUTEX_HELD(&ill->ill_lock));
+
+ /*
+ * NOTE: Some grinning weirdo may have lowered the global max beyond
+ * what this ill currently has. The behavior in this case will be
+ * trim-back just by the reclaim amount for any new ones.
+ */
+ max_count = ip_max_ill_mcast_nces;
+ reclaim_count = min(ip_ill_mcast_reclaim, max_count);
+
+ /* All good? */
+ if (ill->ill_mcast_nces < max_count)
+ return (B_FALSE); /* Yes, all good. */
+
+ if (reclaim_count == 0)
+ return (B_TRUE); /* Don't bother - we're stuck. */
+
+ /* We need to reclaim now. Exploit our held ill_lock. */
+
+ /*
+ * Start at the tail and work backwards, new nces are head-inserted,
+ * so we'll be reaping the oldest entries.
+ */
+ nce = list_tail(&ill->ill_nce);
+ while (reclaimed < reclaim_count) {
+ /* Skip ahead to a multicast NCE. */
+ while (nce != NULL &&
+ (nce->nce_common->ncec_flags & NCE_F_MCAST) == 0) {
+ nce = list_prev(&ill->ill_nce, nce);
+ }
+ if (nce == NULL)
+ break;
+
+ /*
+ * NOTE: For now, we just delete the first one(s) we find.
+ * This is not optimal, and may require some inspection of nce
+ * & its ncec to be better.
+ */
+ deadman = nce;
+ nce = list_prev(&ill->ill_nce, nce);
+
+ /* nce_delete() requires caller holds... */
+ nce_refhold(deadman);
+ nce_delete(deadman); /* Bumps down ill_mcast_nces. */
+
+ /* Link the dead ones singly, still refheld... */
+ list_insert_tail(graveyard, deadman);
+ reclaimed++;
+ }
+
+ if (reclaimed != reclaim_count) {
+ /* We didn't have enough to reach reclaim_count. Why?!? */
+ DTRACE_PROBE3(ill__mcast__nce__reclaim__mismatch, ill_t *, ill,
+ uint_t, reclaimed, uint_t, reclaim_count);
+
+ /* In case for some REALLY weird reason we found none! */
+ too_many = (reclaimed == 0);
+ } else {
+ too_many = B_FALSE;
+ }
+
+ return (too_many);
+}
+
+static void
+ncec_mcast_reap_one(ncec_t *ncec, void *arg)
+{
+ boolean_t reapit;
+ ill_t *ill = (ill_t *)arg;
+
+ /* Obvious no-lock-needed checks... */
+ if (ncec == NULL || ncec->ncec_ill != ill ||
+ (ncec->ncec_flags & NCE_F_MCAST) == 0)
+ return;
+
+ mutex_enter(&ncec->ncec_lock);
+ /*
+ * It's refheld by the walk infrastructure. It has one reference for
+ * being in the ndp_g_hash, and if an nce_t exists, that's one more.
+ * We want ones without an nce_t, so 2 is the magic number. If it's
+ * LESS than 2, we have much bigger problems anyway.
+ */
+ ASSERT(ncec->ncec_refcnt >= 2);
+ reapit = (ncec->ncec_refcnt == 2);
+ mutex_exit(&ncec->ncec_lock);
+
+ if (reapit) {
+ IP_STAT(ill->ill_ipst, ip_nce_mcast_reclaim_deleted);
+ ncec_delete(ncec);
+ }
+}
+
+/*
+ * Attempt to reap stray multicast ncec_t structures left in the wake of
+ * nce_graveyard_free(). This is a taskq servicing routine, as it's well
+ * outside any netstack-global locks being held - ndp_g_lock in this case. We
+ * have a reference hold on the ill, which will prevent any unplumbing races.
+ */
+static void
+ncec_mcast_reap(void *arg)
+{
+ ill_t *ill = (ill_t *)arg;
+
+ IP_STAT(ill->ill_ipst, ip_nce_mcast_reclaim_calls);
+ ncec_walk(ill, ncec_mcast_reap_one, ill, ill->ill_ipst);
+ mutex_enter(&ill->ill_lock);
+ ill->ill_mcast_ncec_cleanup = B_FALSE;
+ /*
+ * Inline a _notr() version of ill_refrele. See nce_graveyard_free()
+ * below for why.
+ */
+ ill->ill_refcnt--;
+ if (ill->ill_refcnt == 0)
+ ipif_ill_refrele_tail(ill); /* Drops ill_lock. */
+ else
+ mutex_exit(&ill->ill_lock);
+}
+
+/*
+ * Free a list (including handling an empty list or NULL list) of
+ * reference-held NCEs that were reaped from a nce_too_many_mcast()
+ * call. Separate because the caller must have dropped ndp_g_lock first.
+ *
+ * This also schedules a taskq task to unlink underlying NCECs from the
+ * ndp_g_hash, which are protected by ndp_g_lock.
+ */
+static void
+nce_graveyard_free(list_t *graveyard)
+{
+ nce_t *deadman, *current;
+ ill_t *ill;
+ boolean_t doit;
+
+ if (graveyard == NULL)
+ return;
+
+ current = list_head(graveyard);
+ if (current == NULL) {
+ list_destroy(graveyard);
+ return;
+ }
+
+ ill = current->nce_ill;
+ /*
+ * Normally one should ill_refhold(ill) here. There's no _notr()
+ * variant like there is for ire_t, dce_t, or even ncec_t, but this is
+ * the ONLY case that'll break the mh_trace that IP debugging uses for
+ * reference counts (i.e. they assume same thread releases as
+ * holds). Instead, we inline ill_refhold() here. We must do the same
+ * in the release done by the ncec_mcast_reap() above.
+ */
+ mutex_enter(&ill->ill_lock);
+ ill->ill_refcnt++;
+ mutex_exit(&ill->ill_lock);
+
+ while (current != NULL) {
+ ASSERT3P(ill, ==, current->nce_ill);
+ deadman = current;
+ current = list_next(graveyard, deadman);
+ list_remove(graveyard, deadman);
+ ASSERT3U((deadman->nce_common->ncec_flags & NCE_F_MCAST), !=,
+ 0);
+ nce_refrele(deadman);
+ }
+ list_destroy(graveyard);
+
+ mutex_enter(&ill->ill_lock);
+ if (ill->ill_mcast_ncec_cleanup)
+ doit = B_FALSE;
+ else {
+ ill->ill_mcast_ncec_cleanup = B_TRUE;
+ doit = B_TRUE;
+ }
+ mutex_exit(&ill->ill_lock);
+ if (!doit || taskq_dispatch(system_taskq, ncec_mcast_reap,
+ ill, TQ_NOSLEEP) == (taskqid_t)NULL) {
+ mutex_enter(&ill->ill_lock);
+ if (doit) {
+ IP_STAT(ill->ill_ipst, ip_nce_mcast_reclaim_tqfail);
+ ill->ill_mcast_ncec_cleanup = B_FALSE;
+ }
+ /* There's no _notr() for ill_refrele(), so inline it here. */
+ ill->ill_refcnt--;
+ if (ill->ill_refcnt == 0)
+ ipif_ill_refrele_tail(ill); /* Drops ill_lock */
+ else
+ mutex_exit(&ill->ill_lock);
+ }
+}
+
+/*
* For each interface an entry is added for the unspecified multicast group.
* Here that mapping is used to form the multicast cache entry for a particular
* multicast destination.
@@ -1050,7 +1280,7 @@ nce_set_multicast_v6(ill_t *ill, const in6_addr_t *dst,
ND_UNCHANGED, &nce);
mutex_exit(&ipst->ips_ndp6->ndp_g_lock);
if (err == 0)
- err = nce_add_v6_postprocess(nce);
+ err = (nce != NULL) ? nce_add_v6_postprocess(nce) : ENOMEM;
if (hw_addr != NULL)
kmem_free(hw_addr, ill->ill_nd_lla_len);
if (err != 0) {
@@ -3100,7 +3330,7 @@ nce_fastpath_create(ill_t *ill, ncec_t *ncec)
* method. All other callers (that pass in NULL ncec_nce) will have to do a
* nce_refrele of the returned nce (when it is non-null).
*/
-nce_t *
+static nce_t *
nce_fastpath(ncec_t *ncec, boolean_t trigger_fp_req, nce_t *ncec_nce)
{
nce_t *nce;
@@ -3158,7 +3388,7 @@ nce_fastpath_trigger(nce_t *nce)
* Add ncec to the nce fastpath list on ill.
*/
static nce_t *
-nce_ill_lookup_then_add_locked(ill_t *ill, ncec_t *ncec)
+nce_ill_lookup_then_add_locked(ill_t *ill, ncec_t *ncec, list_t *graveyard)
{
nce_t *nce = NULL;
@@ -3178,21 +3408,24 @@ nce_ill_lookup_then_add_locked(ill_t *ill, ncec_t *ncec)
nce = nce_lookup(ill, &ncec->ncec_addr);
if (nce != NULL)
goto done;
- nce = nce_add(ill, ncec);
+ nce = nce_add(ill, ncec, graveyard);
}
done:
mutex_exit(&ncec->ncec_lock);
return (nce);
}
-nce_t *
+static nce_t *
nce_ill_lookup_then_add(ill_t *ill, ncec_t *ncec)
{
nce_t *nce;
+ list_t graveyard;
+ list_create(&graveyard, sizeof (nce_t), offsetof(nce_t, nce_node));
mutex_enter(&ill->ill_lock);
- nce = nce_ill_lookup_then_add_locked(ill, ncec);
+ nce = nce_ill_lookup_then_add_locked(ill, ncec, &graveyard);
mutex_exit(&ill->ill_lock);
+ nce_graveyard_free(&graveyard);
return (nce);
}
@@ -3243,7 +3476,9 @@ nce_delete_then_add(nce_t *nce)
{
ill_t *ill = nce->nce_ill;
nce_t *newnce = NULL;
+ list_t graveyard;
+ list_create(&graveyard, sizeof (nce_t), offsetof(nce_t, nce_node));
ip0dbg(("nce_delete_then_add nce %p ill %s\n",
(void *)nce, ill->ill_name));
mutex_enter(&ill->ill_lock);
@@ -3255,9 +3490,10 @@ nce_delete_then_add(nce_t *nce)
* ipmp_ncec_delete_nce()
*/
if (!NCE_ISCONDEMNED(nce->nce_common))
- newnce = nce_add(ill, nce->nce_common);
+ newnce = nce_add(ill, nce->nce_common, &graveyard);
mutex_exit(&nce->nce_common->ncec_lock);
mutex_exit(&ill->ill_lock);
+ nce_graveyard_free(&graveyard);
nce_refrele(nce);
return (newnce); /* could be null if nomem */
}
@@ -3972,7 +4208,7 @@ nce_set_multicast_v4(ill_t *ill, const in_addr_t *dst,
ND_UNCHANGED, &nce);
mutex_exit(&ipst->ips_ndp4->ndp_g_lock);
if (err == 0)
- err = nce_add_v4_postprocess(nce);
+ err = (nce != NULL) ? nce_add_v4_postprocess(nce) : ENOMEM;
if (hw_addr != NULL)
kmem_free(hw_addr, ill->ill_phys_addr_length);
if (err != 0) {
@@ -4396,6 +4632,7 @@ nce_add_common(ill_t *ill, uchar_t *hw_addr, uint_t hw_addr_len,
boolean_t fastprobe = B_FALSE;
struct ndp_g_s *ndp;
nce_t *nce = NULL;
+ list_t graveyard;
mblk_t *dlur_mp = NULL;
if (ill->ill_isv6)
@@ -4686,9 +4923,11 @@ nce_add_common(ill_t *ill, uchar_t *hw_addr, uint_t hw_addr_len,
* Since we hold the ncec_lock at this time, the ncec cannot be
* condemned, and we can safely add the nce.
*/
- *retnce = nce_add_impl(ill, ncec, nce, dlur_mp);
+ list_create(&graveyard, sizeof (nce_t), offsetof(nce_t, nce_node));
+ *retnce = nce_add_impl(ill, ncec, nce, dlur_mp, &graveyard);
mutex_exit(&ncec->ncec_lock);
mutex_exit(&ill->ill_lock);
+ nce_graveyard_free(&graveyard);
/* caller must trigger fastpath on *retnce */
return (0);
@@ -4774,10 +5013,25 @@ nce_inactive(nce_t *nce)
/*
* Add an nce to the ill_nce list.
+ *
+ * Adding multicast NCEs is subject to a per-ill limit. This function returns
+ * NULL if that's the case, and it may reap a number of multicast nces.
+ * Callers (and upstack) must be able to cope with NULL returns.
*/
static nce_t *
-nce_add_impl(ill_t *ill, ncec_t *ncec, nce_t *nce, mblk_t *dlur_mp)
+nce_add_impl(ill_t *ill, ncec_t *ncec, nce_t *nce, mblk_t *dlur_mp,
+ list_t *graveyard)
{
+ ASSERT(MUTEX_HELD(&ill->ill_lock));
+
+ if ((ncec->ncec_flags & NCE_F_MCAST) != 0) {
+ if (nce_too_many_mcast(ill, graveyard)) {
+ kmem_cache_free(nce_cache, nce);
+ return (NULL);
+ }
+ ill->ill_mcast_nces++;
+ }
+
bzero(nce, sizeof (*nce));
mutex_init(&nce->nce_lock, NULL, MUTEX_DEFAULT, NULL);
nce->nce_common = ncec;
@@ -4798,7 +5052,7 @@ nce_add_impl(ill_t *ill, ncec_t *ncec, nce_t *nce, mblk_t *dlur_mp)
}
static nce_t *
-nce_add(ill_t *ill, ncec_t *ncec)
+nce_add(ill_t *ill, ncec_t *ncec, list_t *graveyard)
{
nce_t *nce;
mblk_t *dlur_mp = NULL;
@@ -4819,7 +5073,11 @@ nce_add(ill_t *ill, ncec_t *ncec)
return (NULL);
}
}
- return (nce_add_impl(ill, ncec, nce, dlur_mp));
+ /*
+ * If nce_add_impl() returns NULL due to on multicast limiting, caller
+ * will (correctly) assume ENOMEM.
+ */
+ return (nce_add_impl(ill, ncec, nce, dlur_mp, graveyard));
}
/*
@@ -4843,6 +5101,10 @@ nce_delete(nce_t *nce)
nce->nce_is_condemned = B_TRUE;
mutex_exit(&nce->nce_lock);
+ /* Update the count of multicast NCEs. */
+ if ((nce->nce_common->ncec_flags & NCE_F_MCAST) == NCE_F_MCAST)
+ ill->ill_mcast_nces--;
+
list_remove(&ill->ill_nce, nce);
/*
* even though we are holding the ill_lock, it is ok to
diff --git a/usr/src/uts/common/inet/ip/ipsecah.c b/usr/src/uts/common/inet/ip/ipsecah.c
index 05e92c4fa4..455b9af72f 100644
--- a/usr/src/uts/common/inet/ip/ipsecah.c
+++ b/usr/src/uts/common/inet/ip/ipsecah.c
@@ -135,7 +135,8 @@ static void ah_outbound_finish(mblk_t *, ip_xmit_attr_t *);
static int ipsecah_open(queue_t *, dev_t *, int, int, cred_t *);
static int ipsecah_close(queue_t *, int, cred_t *);
-static void ipsecah_wput(queue_t *, mblk_t *);
+static int ipsecah_rput(queue_t *, mblk_t *);
+static int ipsecah_wput(queue_t *, mblk_t *);
static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *,
cred_t *);
static void *ipsecah_stack_init(netstackid_t stackid, netstack_t *ns);
@@ -151,12 +152,12 @@ static struct module_info info = {
};
static struct qinit rinit = {
- (pfi_t)putnext, NULL, ipsecah_open, ipsecah_close, NULL, &info,
+ ipsecah_rput, NULL, ipsecah_open, ipsecah_close, NULL, &info,
NULL
};
static struct qinit winit = {
- (pfi_t)ipsecah_wput, NULL, ipsecah_open, ipsecah_close, NULL, &info,
+ ipsecah_wput, NULL, ipsecah_open, ipsecah_close, NULL, &info,
NULL
};
@@ -1446,9 +1447,19 @@ ah_keysock_no_socket(mblk_t *mp, ipsecah_stack_t *ahstack)
}
/*
+ * AH module read put routine.
+ */
+static int
+ipsecah_rput(queue_t *q, mblk_t *mp)
+{
+ putnext(q, mp);
+ return (0);
+}
+
+/*
* AH module write put routine.
*/
-static void
+static int
ipsecah_wput(queue_t *q, mblk_t *mp)
{
ipsec_info_t *ii;
@@ -1498,7 +1509,7 @@ ipsecah_wput(queue_t *q, mblk_t *mp)
case ND_GET:
if (nd_getset(q, ahstack->ipsecah_g_nd, mp)) {
qreply(q, mp);
- return;
+ return (0);
} else {
iocp->ioc_error = ENOENT;
}
@@ -1512,7 +1523,7 @@ ipsecah_wput(queue_t *q, mblk_t *mp)
iocp->ioc_count = 0;
mp->b_datap->db_type = M_IOCACK;
qreply(q, mp);
- return;
+ return (0);
}
default:
ah3dbg(ahstack,
@@ -1520,6 +1531,7 @@ ipsecah_wput(queue_t *q, mblk_t *mp)
mp->b_datap->db_type));
putnext(q, mp);
}
+ return (0);
}
/* Refactor me */
@@ -2885,7 +2897,7 @@ ah_process_ip_options_v6(mblk_t *mp, ipsa_t *assoc, int *length_to_skip,
{
ip6_t *ip6h;
ip6_t *oip6h;
- mblk_t *phdr_mp;
+ mblk_t *phdr_mp;
int option_length;
uint_t ah_align_sz;
uint_t ah_offset;
@@ -3003,7 +3015,7 @@ ah_process_ip_options_v4(mblk_t *mp, ipsa_t *assoc, int *length_to_skip,
uint32_t option_length;
ipha_t *ipha;
ipha_t *oipha;
- mblk_t *phdr_mp;
+ mblk_t *phdr_mp;
int size;
uchar_t *optptr;
uint8_t optval;
diff --git a/usr/src/uts/common/inet/ip/ipsecesp.c b/usr/src/uts/common/inet/ip/ipsecesp.c
index ce7a4d0f4f..8f6fa27487 100644
--- a/usr/src/uts/common/inet/ip/ipsecesp.c
+++ b/usr/src/uts/common/inet/ip/ipsecesp.c
@@ -107,7 +107,8 @@ static ipsecespparam_t lcl_param_arr[] = {
static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *);
static int ipsecesp_close(queue_t *, int, cred_t *);
-static void ipsecesp_wput(queue_t *, mblk_t *);
+static int ipsecesp_rput(queue_t *, mblk_t *);
+static int ipsecesp_wput(queue_t *, mblk_t *);
static void *ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns);
static void ipsecesp_stack_fini(netstackid_t stackid, void *arg);
@@ -132,12 +133,12 @@ static struct module_info info = {
};
static struct qinit rinit = {
- (pfi_t)putnext, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
+ ipsecesp_rput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
NULL
};
static struct qinit winit = {
- (pfi_t)ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
+ ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
NULL
};
@@ -1801,7 +1802,7 @@ esp_crypto_failed(mblk_t *data_mp, boolean_t is_inbound, int kef_rc,
(data)->cd_offset = off; \
} else { \
(data)->cd_format = CRYPTO_DATA_MBLK; \
- (data)->cd_mp = mp; \
+ (data)->cd_mp = mp; \
(data)->cd_offset = off; \
} \
(data)->cd_length = len; \
@@ -3839,9 +3840,19 @@ esp_keysock_no_socket(mblk_t *mp, ipsecesp_stack_t *espstack)
}
/*
+ * ESP module read put routine.
+ */
+static int
+ipsecesp_rput(queue_t *q, mblk_t *mp)
+{
+ putnext(q, mp);
+ return (0);
+}
+
+/*
* ESP module write put routine.
*/
-static void
+static int
ipsecesp_wput(queue_t *q, mblk_t *mp)
{
ipsec_info_t *ii;
@@ -3891,7 +3902,7 @@ ipsecesp_wput(queue_t *q, mblk_t *mp)
case ND_GET:
if (nd_getset(q, espstack->ipsecesp_g_nd, mp)) {
qreply(q, mp);
- return;
+ return (0);
} else {
iocp->ioc_error = ENOENT;
}
@@ -3905,7 +3916,7 @@ ipsecesp_wput(queue_t *q, mblk_t *mp)
iocp->ioc_count = 0;
mp->b_datap->db_type = M_IOCACK;
qreply(q, mp);
- return;
+ return (0);
}
default:
esp3dbg(espstack,
@@ -3913,6 +3924,7 @@ ipsecesp_wput(queue_t *q, mblk_t *mp)
mp->b_datap->db_type));
putnext(q, mp);
}
+ return (0);
}
/*
diff --git a/usr/src/uts/common/inet/ip/keysock.c b/usr/src/uts/common/inet/ip/keysock.c
index a01eeaa3c8..47435bb727 100644
--- a/usr/src/uts/common/inet/ip/keysock.c
+++ b/usr/src/uts/common/inet/ip/keysock.c
@@ -146,9 +146,9 @@ static keysockparam_t lcl_param_arr[] = {
static int keysock_close(queue_t *, int, cred_t *);
static int keysock_open(queue_t *, dev_t *, int, int, cred_t *);
-static void keysock_wput(queue_t *, mblk_t *);
-static void keysock_rput(queue_t *, mblk_t *);
-static void keysock_rsrv(queue_t *);
+static int keysock_wput(queue_t *, mblk_t *);
+static int keysock_rput(queue_t *, mblk_t *);
+static int keysock_rsrv(queue_t *);
static void keysock_passup(mblk_t *, sadb_msg_t *, minor_t,
keysock_consumer_t *, boolean_t, keysock_stack_t *);
static void *keysock_stack_init(netstackid_t stackid, netstack_t *ns);
@@ -159,12 +159,12 @@ static struct module_info info = {
};
static struct qinit rinit = {
- (pfi_t)keysock_rput, (pfi_t)keysock_rsrv, keysock_open, keysock_close,
+ keysock_rput, keysock_rsrv, keysock_open, keysock_close,
NULL, &info
};
static struct qinit winit = {
- (pfi_t)keysock_wput, NULL, NULL, NULL, NULL, &info
+ keysock_wput, NULL, NULL, NULL, NULL, &info
};
struct streamtab keysockinfo = {
@@ -1916,7 +1916,7 @@ keysock_parse(queue_t *q, mblk_t *mp)
* as PF_KEY sockets are concerned. I do some conversion, but not as much
* as IP/rts does.
*/
-static void
+static int
keysock_wput(queue_t *q, mblk_t *mp)
{
uchar_t *rptr = mp->b_rptr;
@@ -1937,7 +1937,7 @@ keysock_wput(queue_t *q, mblk_t *mp)
ks1dbg(keystack, ("Huh? wput for an consumer instance (%d)?\n",
kc->kc_sa_type));
putnext(q, mp);
- return;
+ return (0);
}
ks = (keysock_t *)q->q_ptr;
keystack = ks->keysock_keystack;
@@ -1951,7 +1951,7 @@ keysock_wput(queue_t *q, mblk_t *mp)
*/
ks2dbg(keystack, ("raw M_DATA in keysock.\n"));
freemsg(mp);
- return;
+ return (0);
case M_PROTO:
case M_PCPROTO:
if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) {
@@ -1961,7 +1961,7 @@ keysock_wput(queue_t *q, mblk_t *mp)
ks2dbg(keystack,
("No data after DATA_REQ.\n"));
freemsg(mp);
- return;
+ return (0);
}
freeb(mp);
mp = mp1;
@@ -1974,11 +1974,12 @@ keysock_wput(queue_t *q, mblk_t *mp)
ks3dbg(keystack, ("In default wput case (%d %d).\n",
mp->b_datap->db_type, ((union T_primitives *)rptr)->type));
keysock_wput_other(q, mp);
- return;
+ return (0);
}
/* I now have a PF_KEY message in an M_DATA block, pointed to by mp. */
keysock_parse(q, mp);
+ return (0);
}
/* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_rput(). */
@@ -2329,7 +2330,7 @@ error:
* Keysock's read service procedure is there only for PF_KEY reply
* messages that really need to reach the top.
*/
-static void
+static int
keysock_rsrv(queue_t *q)
{
mblk_t *mp;
@@ -2339,9 +2340,10 @@ keysock_rsrv(queue_t *q)
putnext(q, mp);
} else {
(void) putbq(q, mp);
- return;
+ return (0);
}
}
+ return (0);
}
/*
@@ -2349,7 +2351,7 @@ keysock_rsrv(queue_t *q)
* ESP, AH, etc. I should only see KEYSOCK_OUT and KEYSOCK_HELLO_ACK
* messages on my read queues.
*/
-static void
+static int
keysock_rput(queue_t *q, mblk_t *mp)
{
keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr;
@@ -2374,7 +2376,7 @@ keysock_rput(queue_t *q, mblk_t *mp)
("Hmmm, a non M_CTL (%d, 0x%x) on keysock_rput.\n",
mp->b_datap->db_type, mp->b_datap->db_type));
putnext(q, mp);
- return;
+ return (0);
}
ii = (ipsec_info_t *)mp->b_rptr;
@@ -2418,7 +2420,7 @@ keysock_rput(queue_t *q, mblk_t *mp)
("One flush/dump message back from %d,"
" more to go.\n", samsg->sadb_msg_satype));
freemsg(mp1);
- return;
+ return (0);
}
samsg->sadb_msg_errno =
@@ -2429,18 +2431,19 @@ keysock_rput(queue_t *q, mblk_t *mp)
}
keysock_passup(mp1, samsg, serial, kc,
(samsg->sadb_msg_type == SADB_DUMP), keystack);
- return;
+ return (0);
case KEYSOCK_HELLO_ACK:
/* Aha, now we can link in the consumer! */
ksa = (keysock_hello_ack_t *)ii;
keysock_link_consumer(ksa->ks_hello_satype, kc);
freemsg(mp);
- return;
+ return (0);
default:
ks1dbg(keystack, ("Hmmm, an IPsec info I'm not used to, 0x%x\n",
ii->ipsec_info_type));
putnext(q, mp);
}
+ return (0);
}
/*
diff --git a/usr/src/uts/common/inet/ip/spdsock.c b/usr/src/uts/common/inet/ip/spdsock.c
index 267bad10ba..5911b45770 100644
--- a/usr/src/uts/common/inet/ip/spdsock.c
+++ b/usr/src/uts/common/inet/ip/spdsock.c
@@ -154,9 +154,9 @@ static spdsockparam_t lcl_param_arr[] = {
static int spdsock_close(queue_t *, int, cred_t *);
static int spdsock_open(queue_t *, dev_t *, int, int, cred_t *);
-static void spdsock_wput(queue_t *, mblk_t *);
-static void spdsock_wsrv(queue_t *);
-static void spdsock_rsrv(queue_t *);
+static int spdsock_wput(queue_t *, mblk_t *);
+static int spdsock_wsrv(queue_t *);
+static int spdsock_rsrv(queue_t *);
static void *spdsock_stack_init(netstackid_t stackid, netstack_t *ns);
static void spdsock_stack_shutdown(netstackid_t stackid, void *arg);
static void spdsock_stack_fini(netstackid_t stackid, void *arg);
@@ -171,12 +171,12 @@ static struct module_info info = {
};
static struct qinit rinit = {
- NULL, (pfi_t)spdsock_rsrv, spdsock_open, spdsock_close,
+ NULL, spdsock_rsrv, spdsock_open, spdsock_close,
NULL, &info
};
static struct qinit winit = {
- (pfi_t)spdsock_wput, (pfi_t)spdsock_wsrv, NULL, NULL, NULL, &info
+ spdsock_wput, spdsock_wsrv, NULL, NULL, NULL, &info
};
struct streamtab spdsockinfo = {
@@ -696,23 +696,23 @@ spdsock_ext_to_sel(spd_ext_t **extv, ipsec_selkey_t *sel, int *diag)
tc->spd_typecode_code_end;
}
}
-#define ADDR2SEL(sel, extv, field, pfield, extn, bit) \
- if ((extv)[(extn)] != NULL) { \
- uint_t addrlen; \
- struct spd_address *ap = \
- (struct spd_address *)((extv)[(extn)]); \
- addrlen = (ap->spd_address_af == AF_INET6) ? \
- IPV6_ADDR_LEN : IP_ADDR_LEN; \
- if (SPD_64TO8(ap->spd_address_len) < \
- (addrlen + sizeof (*ap))) { \
- *diag = SPD_DIAGNOSTIC_BAD_ADDR_LEN; \
- return (B_FALSE); \
- } \
- bcopy((ap+1), &((sel)->field), addrlen); \
- (sel)->pfield = ap->spd_address_prefixlen; \
- (sel)->ipsl_valid |= (bit); \
- (sel)->ipsl_valid |= (ap->spd_address_af == AF_INET6) ? \
- IPSL_IPV6 : IPSL_IPV4; \
+#define ADDR2SEL(sel, extv, field, pfield, extn, bit) \
+ if ((extv)[(extn)] != NULL) { \
+ uint_t addrlen; \
+ struct spd_address *ap = \
+ (struct spd_address *)((extv)[(extn)]); \
+ addrlen = (ap->spd_address_af == AF_INET6) ? \
+ IPV6_ADDR_LEN : IP_ADDR_LEN; \
+ if (SPD_64TO8(ap->spd_address_len) < \
+ (addrlen + sizeof (*ap))) { \
+ *diag = SPD_DIAGNOSTIC_BAD_ADDR_LEN; \
+ return (B_FALSE); \
+ } \
+ bcopy((ap+1), &((sel)->field), addrlen); \
+ (sel)->pfield = ap->spd_address_prefixlen; \
+ (sel)->ipsl_valid |= (bit); \
+ (sel)->ipsl_valid |= (ap->spd_address_af == AF_INET6) ? \
+ IPSL_IPV6 : IPSL_IPV4; \
}
ADDR2SEL(sel, extv, ipsl_local, ipsl_local_pfxlen,
@@ -2327,9 +2327,9 @@ spdsock_alglist(queue_t *q, mblk_t *mp)
attr = (struct spd_attribute *)cur;
#define EMIT(tag, value) { \
- attr->spd_attr_tag = (tag); \
- attr->spd_attr_value = (value); \
- attr++; \
+ attr->spd_attr_tag = (tag); \
+ attr->spd_attr_value = (value); \
+ attr++; \
}
/*
@@ -2337,7 +2337,7 @@ spdsock_alglist(queue_t *q, mblk_t *mp)
* ATTRPERALG above to match
*/
#define EMITALGATTRS(_type) { \
- EMIT(algattr[_type], algid); /* 1 */ \
+ EMIT(algattr[_type], algid); /* 1 */ \
EMIT(minbitsattr[_type], minbits); /* 2 */ \
EMIT(maxbitsattr[_type], maxbits); /* 3 */ \
EMIT(defbitsattr[_type], defbits); /* 4 */ \
@@ -2481,9 +2481,9 @@ spdsock_dumpalgs(queue_t *q, mblk_t *mp)
attr = (struct spd_attribute *)cur;
#define EMIT(tag, value) { \
- attr->spd_attr_tag = (tag); \
- attr->spd_attr_value = (value); \
- attr++; \
+ attr->spd_attr_tag = (tag); \
+ attr->spd_attr_value = (value); \
+ attr++; \
}
for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
@@ -3452,7 +3452,7 @@ spdsock_wput_other(queue_t *q, mblk_t *mp)
freemsg(mp);
}
-static void
+static int
spdsock_wput(queue_t *q, mblk_t *mp)
{
uint8_t *rptr = mp->b_rptr;
@@ -3467,7 +3467,7 @@ spdsock_wput(queue_t *q, mblk_t *mp)
if (ss->spdsock_dump_req != NULL) {
if (!putq(q, mp))
freemsg(mp);
- return;
+ return (0);
}
switch (mp->b_datap->db_type) {
@@ -3477,7 +3477,7 @@ spdsock_wput(queue_t *q, mblk_t *mp)
*/
ss2dbg(spds, ("raw M_DATA in spdsock.\n"));
freemsg(mp);
- return;
+ return (0);
case M_PROTO:
case M_PCPROTO:
if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) {
@@ -3487,7 +3487,7 @@ spdsock_wput(queue_t *q, mblk_t *mp)
ss2dbg(spds,
("No data after DATA_REQ.\n"));
freemsg(mp);
- return;
+ return (0);
}
freeb(mp);
mp = mp1;
@@ -3500,11 +3500,12 @@ spdsock_wput(queue_t *q, mblk_t *mp)
ss3dbg(spds, ("In default wput case (%d %d).\n",
mp->b_datap->db_type, ((union T_primitives *)rptr)->type));
spdsock_wput_other(q, mp);
- return;
+ return (0);
}
/* I now have a PF_POLICY message in an M_DATA block. */
spdsock_parse(q, mp);
+ return (0);
}
/*
@@ -3577,7 +3578,7 @@ spdsock_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
* Dump another chunk if we were dumping before; when we finish, kick
* the write-side queue in case it's waiting for read queue space.
*/
-void
+int
spdsock_rsrv(queue_t *q)
{
spdsock_t *ss = q->q_ptr;
@@ -3587,13 +3588,14 @@ spdsock_rsrv(queue_t *q)
if (ss->spdsock_dump_req == NULL)
qenable(OTHERQ(q));
+ return (0);
}
/*
* Write-side service procedure, invoked when we defer processing
* if another message is received while a dump is in progress.
*/
-void
+int
spdsock_wsrv(queue_t *q)
{
spdsock_t *ss = q->q_ptr;
@@ -3602,20 +3604,21 @@ spdsock_wsrv(queue_t *q)
if (ss->spdsock_dump_req != NULL) {
qenable(OTHERQ(q));
- return;
+ return (0);
}
while ((mp = getq(q)) != NULL) {
if (ipsec_loaded(ipss)) {
spdsock_wput(q, mp);
if (ss->spdsock_dump_req != NULL)
- return;
+ return (0);
} else if (!ipsec_failed(ipss)) {
(void) putq(q, mp);
} else {
spdsock_error(q, mp, EPFNOSUPPORT, 0);
}
}
+ return (0);
}
/* ARGSUSED */
diff --git a/usr/src/uts/common/inet/ip_stack.h b/usr/src/uts/common/inet/ip_stack.h
index ab954c7c31..85885f9dd9 100644
--- a/usr/src/uts/common/inet/ip_stack.h
+++ b/usr/src/uts/common/inet/ip_stack.h
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
#ifndef _INET_IP_STACK_H
#define _INET_IP_STACK_H
@@ -64,6 +68,9 @@ typedef struct ip_stat {
kstat_named_t ip_ire_reclaim_deleted;
kstat_named_t ip_nce_reclaim_calls;
kstat_named_t ip_nce_reclaim_deleted;
+ kstat_named_t ip_nce_mcast_reclaim_calls;
+ kstat_named_t ip_nce_mcast_reclaim_deleted;
+ kstat_named_t ip_nce_mcast_reclaim_tqfail;
kstat_named_t ip_dce_reclaim_calls;
kstat_named_t ip_dce_reclaim_deleted;
kstat_named_t ip_tcp_in_full_hw_cksum_err;
@@ -143,7 +150,7 @@ struct ip_stack {
uint_t ips_src_generation; /* Both IPv4 and IPv6 */
- struct mod_prop_info_s *ips_propinfo_tbl; /* ip tunables table */
+ struct mod_prop_info_s *ips_propinfo_tbl; /* ip tunables table */
mib2_ipIfStatsEntry_t ips_ip_mib; /* SNMP fixed size info */
mib2_icmp_t ips_icmp_mib;
@@ -200,16 +207,16 @@ struct ip_stack {
/* ip.c */
/* Following protected by igmp_timer_lock */
- int ips_igmp_time_to_next; /* Time since last timeout */
- int ips_igmp_timer_scheduled_last;
+ int ips_igmp_time_to_next; /* Time since last timeout */
+ int ips_igmp_timer_scheduled_last;
int ips_igmp_deferred_next;
timeout_id_t ips_igmp_timeout_id;
boolean_t ips_igmp_timer_setter_active;
boolean_t ips_igmp_timer_quiesce;
/* Following protected by mld_timer_lock */
- int ips_mld_time_to_next; /* Time since last timeout */
- int ips_mld_timer_scheduled_last;
+ int ips_mld_time_to_next; /* Time since last timeout */
+ int ips_mld_timer_scheduled_last;
int ips_mld_deferred_next;
timeout_id_t ips_mld_timeout_id;
boolean_t ips_mld_timer_setter_active;
@@ -247,8 +254,8 @@ struct ip_stack {
uint32_t ips_ip6_ftable_hash_size;
- ire_stats_t ips_ire_stats_v4; /* IPv4 ire statistics */
- ire_stats_t ips_ire_stats_v6; /* IPv6 ire statistics */
+ ire_stats_t ips_ire_stats_v4; /* IPv4 ire statistics */
+ ire_stats_t ips_ire_stats_v6; /* IPv6 ire statistics */
/* Count how many condemned objects for kmem_cache callbacks */
uint32_t ips_num_ire_condemned;
@@ -344,7 +351,7 @@ struct ip_stack {
* reg_vif_num is protected by numvifs_mutex
*/
/* Whether or not special PIM assert processing is enabled. */
- ushort_t ips_reg_vif_num; /* Index to Register vif */
+ ushort_t ips_reg_vif_num; /* Index to Register vif */
int ips_pim_assert;
union ill_g_head_u *ips_ill_g_heads; /* ILL List Head */
diff --git a/usr/src/uts/common/inet/ipd/ipd.c b/usr/src/uts/common/inet/ipd/ipd.c
index 747a7a814f..25e0b699c5 100644
--- a/usr/src/uts/common/inet/ipd/ipd.c
+++ b/usr/src/uts/common/inet/ipd/ipd.c
@@ -241,7 +241,7 @@ static unsigned int ipd_max_delay = IPD_MAX_DELAY; /* max delay in us */
static kmutex_t ipd_nsl_lock; /* lock for the nestack list */
static list_t ipd_nsl; /* list of netstacks */
static kmutex_t ipd_nactive_lock; /* lock for nactive */
-static unsigned int ipd_nactive; /* number of active netstacks */
+static unsigned int ipd_nactive; /* number of active netstacks */
static int ipd_nactive_fudge = 4; /* amount to fudge by in list */
/*
@@ -880,7 +880,7 @@ ipd_ioctl_list(intptr_t arg, cred_t *cr)
nzones = MIN(cur, rzones);
if (nzones > 0) {
if (ddi_copyout(configs, STRUCT_FGETP(h, ipil_info),
- nzones * sizeof (ipd_ioc_info_t), NULL) != 0)
+ nzones * sizeof (ipd_ioc_info_t), 0) != 0)
rval = EFAULT;
}
diff --git a/usr/src/uts/common/inet/nca/ncaddi.c b/usr/src/uts/common/inet/nca/ncaddi.c
index e4fa85ef00..f02924d131 100644
--- a/usr/src/uts/common/inet/nca/ncaddi.c
+++ b/usr/src/uts/common/inet/nca/ncaddi.c
@@ -90,14 +90,15 @@ nca_close(queue_t *q, int flags __unused, cred_t *credp __unused)
return (0);
}
-static void
+static int
nca_rput(queue_t *q, mblk_t *mp)
{
/* Passthrough */
putnext(q, mp);
+ return (0);
}
-static void
+static int
nca_wput(queue_t *q, mblk_t *mp)
{
struct iocblk *iocp;
@@ -106,11 +107,11 @@ nca_wput(queue_t *q, mblk_t *mp)
iocp = (struct iocblk *)mp->b_rptr;
if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_cmd == NCA_SET_IF) {
miocnak(q, mp, 0, ENOTSUP);
- return;
+ return (0);
}
/* Module, passthrough */
putnext(q, mp);
- return;
+ return (0);
}
switch (DB_TYPE(mp)) {
@@ -121,7 +122,7 @@ nca_wput(queue_t *q, mblk_t *mp)
case ND_GET:
if (! nd_getset(q, nca_g_nd, mp)) {
miocnak(q, mp, 0, ENOENT);
- return;
+ return (0);
}
qreply(q, mp);
break;
@@ -134,6 +135,7 @@ nca_wput(queue_t *q, mblk_t *mp)
freemsg(mp);
break;
}
+ return (0);
}
static struct module_info info = {
@@ -141,11 +143,11 @@ static struct module_info info = {
};
static struct qinit rinit = {
- (pfi_t)nca_rput, NULL, nca_open, nca_close, NULL, &info
+ nca_rput, NULL, nca_open, nca_close, NULL, &info
};
static struct qinit winit = {
- (pfi_t)nca_wput, NULL, nca_open, nca_close, NULL, &info
+ nca_wput, NULL, nca_open, nca_close, NULL, &info
};
struct streamtab ncainfo = {
diff --git a/usr/src/uts/common/io/aac/aac.c b/usr/src/uts/common/io/aac/aac.c
index 36c48d96e6..f9d3672963 100644
--- a/usr/src/uts/common/io/aac/aac.c
+++ b/usr/src/uts/common/io/aac/aac.c
@@ -255,8 +255,8 @@ static int aac_add_intrs(struct aac_softstate *);
static void aac_remove_intrs(struct aac_softstate *);
static int aac_enable_intrs(struct aac_softstate *);
static int aac_disable_intrs(struct aac_softstate *);
-static uint_t aac_intr_old(caddr_t);
-static uint_t aac_intr_new(caddr_t);
+static uint_t aac_intr_old(caddr_t, caddr_t);
+static uint_t aac_intr_new(caddr_t, caddr_t);
static uint_t aac_softintr(caddr_t);
/*
@@ -1416,7 +1416,7 @@ aac_process_intr_new(struct aac_softstate *softs)
}
static uint_t
-aac_intr_new(caddr_t arg)
+aac_intr_new(caddr_t arg, caddr_t arg1 __unused)
{
struct aac_softstate *softs = (void *)arg;
uint_t rval;
@@ -1555,7 +1555,7 @@ aac_process_intr_old(struct aac_softstate *softs)
}
static uint_t
-aac_intr_old(caddr_t arg)
+aac_intr_old(caddr_t arg, caddr_t arg1 __unused)
{
struct aac_softstate *softs = (void *)arg;
int rval;
@@ -1674,7 +1674,7 @@ aac_add_intrs(struct aac_softstate *softs)
ddi_intr_handler_t *aac_intr;
actual = softs->intr_cnt;
- aac_intr = (ddi_intr_handler_t *)((softs->flags & AAC_FLAGS_NEW_COMM) ?
+ aac_intr = ((softs->flags & AAC_FLAGS_NEW_COMM) ?
aac_intr_new : aac_intr_old);
/* Call ddi_intr_add_handler() */
diff --git a/usr/src/uts/common/io/bpf/bpf.c b/usr/src/uts/common/io/bpf/bpf.c
index 59c71f8d4b..564637f824 100644
--- a/usr/src/uts/common/io/bpf/bpf.c
+++ b/usr/src/uts/common/io/bpf/bpf.c
@@ -294,7 +294,7 @@ next:
MBPF_CLIENT_CLOSE(bpr, mcip);
mcip = 0;
}
- if (mh != NULL) {
+ if (mh != 0) {
MBPF_CLOSE(bpr, mh);
mh = 0;
}
@@ -1386,7 +1386,7 @@ bpf_ifname(struct bpf_d *d, char *buffer, int bufsize)
{
mutex_enter(&d->bd_lock);
- if (d->bd_bif == NULL) {
+ if (d->bd_bif == 0) {
mutex_exit(&d->bd_lock);
return (EINVAL);
}
diff --git a/usr/src/uts/common/io/conskbd.c b/usr/src/uts/common/io/conskbd.c
index c250a6be8c..feaf659d33 100644
--- a/usr/src/uts/common/io/conskbd.c
+++ b/usr/src/uts/common/io/conskbd.c
@@ -455,7 +455,7 @@ conskbd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
}
if ((ddi_create_minor_node(devi, "kbd", S_IFCHR,
- 0, DDI_PSEUDO, NULL) == DDI_FAILURE) ||
+ 0, DDI_PSEUDO, 0) == DDI_FAILURE) ||
(ddi_create_internal_pathname(devi, "conskbd", S_IFCHR,
1) == DDI_FAILURE)) {
ddi_remove_minor_node(devi, NULL);
@@ -1686,7 +1686,7 @@ conskbd_alloc_firm_event(ushort_t id, int value)
fe = (Firm_event *)mb->b_wptr;
fe->id = id;
fe->pair_type = FE_PAIR_NONE;
- fe->pair = NULL;
+ fe->pair = '\0';
fe->value = value;
mb->b_wptr += sizeof (Firm_event);
}
diff --git a/usr/src/uts/common/io/devinfo.c b/usr/src/uts/common/io/devinfo.c
index 84a48e086e..68ccd8eea4 100644
--- a/usr/src/uts/common/io/devinfo.c
+++ b/usr/src/uts/common/io/devinfo.c
@@ -461,9 +461,9 @@ di_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
di_max_opens * sizeof (struct di_state *), KM_SLEEP);
if (ddi_create_minor_node(dip, "devinfo", S_IFCHR,
- DI_FULL_PARENT, DDI_PSEUDO, NULL) == DDI_FAILURE ||
+ DI_FULL_PARENT, DDI_PSEUDO, 0) == DDI_FAILURE ||
ddi_create_minor_node(dip, "devinfo,ro", S_IFCHR,
- DI_READONLY_PARENT, DDI_PSEUDO, NULL) == DDI_FAILURE) {
+ DI_READONLY_PARENT, DDI_PSEUDO, 0) == DDI_FAILURE) {
kmem_free(di_states,
di_max_opens * sizeof (struct di_state *));
ddi_remove_minor_node(dip, NULL);
@@ -1298,7 +1298,7 @@ di_key_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
static void
di_copy_aliases(struct di_state *st, alias_pair_t *apair, di_off_t *offp)
{
- di_off_t off;
+ di_off_t off;
struct di_all *all = DI_ALL_PTR(st);
struct di_alias *di_alias;
di_off_t curroff;
@@ -1817,7 +1817,7 @@ di_copynode(struct dev_info *node, struct di_stack *dsp, struct di_state *st)
me->top_phci = 0; /* Filled up by build_phci_list. */
me->next_phci = 0; /* Filled up by build_phci_list. */
me->multipath_component = MULTIPATH_COMPONENT_NONE; /* set default. */
- me->user_private_data = NULL;
+ me->user_private_data = 0;
/*
* Get parent's offset in snapshot from the stack
@@ -2517,7 +2517,7 @@ out:
*/
static di_off_t
di_getmdata(struct ddi_minor_data *mnode, di_off_t *off_p, di_off_t node,
- struct di_state *st)
+ struct di_state *st)
{
di_off_t off;
struct di_minor *me;
@@ -2536,7 +2536,7 @@ di_getmdata(struct ddi_minor_data *mnode, di_off_t *off_p, di_off_t node,
me->self = off;
me->type = mnode->type;
me->node = node;
- me->user_private_data = NULL;
+ me->user_private_data = 0;
off += sizeof (struct di_minor);
diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c
index 238dd9bb22..1371fa47c0 100644
--- a/usr/src/uts/common/io/dld/dld_proto.c
+++ b/usr/src/uts/common/io/dld/dld_proto.c
@@ -1291,7 +1291,7 @@ proto_unitdata_req(dld_str_t *dsp, mblk_t *mp)
* No lock can be held across modules and putnext()'s,
* which can happen here with the call from DLD_TX().
*/
- if (DLD_TX(dsp, bp, 0, 0) != NULL) {
+ if (DLD_TX(dsp, bp, 0, 0) != 0) {
/* flow-controlled */
DLD_SETQFULL(dsp);
}
diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c
index a8ab4eba50..3029288b19 100644
--- a/usr/src/uts/common/io/dld/dld_str.c
+++ b/usr/src/uts/common/io/dld/dld_str.c
@@ -955,7 +955,7 @@ str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp, uintptr_t f_hint,
}
}
- if ((cookie = DLD_TX(dsp, mp, f_hint, flag)) != NULL) {
+ if ((cookie = DLD_TX(dsp, mp, f_hint, flag)) != 0) {
DLD_SETQFULL(dsp);
}
return (cookie);
@@ -963,7 +963,7 @@ str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp, uintptr_t f_hint,
discard:
/* TODO: bump kstat? */
freemsg(mp);
- return (NULL);
+ return (0);
}
/*
@@ -1025,7 +1025,7 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp)
goto discard;
}
- if (DLD_TX(dsp, mp, 0, 0) != NULL) {
+ if (DLD_TX(dsp, mp, 0, 0) != 0) {
/* Turn on flow-control for dld */
DLD_SETQFULL(dsp);
}
diff --git a/usr/src/uts/common/io/dls/dls.c b/usr/src/uts/common/io/dls/dls.c
index 303ea8eb24..b71d95bd44 100644
--- a/usr/src/uts/common/io/dls/dls.c
+++ b/usr/src/uts/common/io/dls/dls.c
@@ -25,7 +25,7 @@
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -218,13 +218,15 @@ dls_unbind(dld_str_t *dsp)
mac_rx_bypass_enable(dsp->ds_mch);
/*
- * For VLAN SAP, there was a promisc handle registered when dls_bind.
- * When unbind this dls link, we need to remove the promisc handle.
- * See comments in dls_bind().
+ * A VLAN SAP does not actually add itself to the STREAM head today.
+ * While we initially set up a VLAN handle below, it's possible that
+ * something else will have come in and clobbered it.
*/
- if (dsp->ds_vlan_mph != NULL) {
- mac_promisc_remove(dsp->ds_vlan_mph);
- dsp->ds_vlan_mph = NULL;
+ if (dsp->ds_sap == ETHERTYPE_VLAN) {
+ if (dsp->ds_vlan_mph != NULL) {
+ mac_promisc_remove(dsp->ds_vlan_mph);
+ dsp->ds_vlan_mph = NULL;
+ }
return;
}
diff --git a/usr/src/uts/common/io/dump.c b/usr/src/uts/common/io/dump.c
index ab5a9d0240..4fd52e6448 100644
--- a/usr/src/uts/common/io/dump.c
+++ b/usr/src/uts/common/io/dump.c
@@ -54,7 +54,7 @@ dump_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
- if (ddi_create_minor_node(devi, "dump", S_IFCHR, 0, DDI_PSEUDO, NULL) ==
+ if (ddi_create_minor_node(devi, "dump", S_IFCHR, 0, DDI_PSEUDO, 0) ==
DDI_FAILURE) {
ddi_remove_minor_node(devi, NULL);
return (DDI_FAILURE);
@@ -235,7 +235,7 @@ struct cb_ops dump_cb_ops = {
dump_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
- nodev, /* segmap */
+ nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* prop_op */
0, /* streamtab */
diff --git a/usr/src/uts/common/io/ecpp.c b/usr/src/uts/common/io/ecpp.c
index c7c03826b5..ce2411ea71 100644
--- a/usr/src/uts/common/io/ecpp.c
+++ b/usr/src/uts/common/io/ecpp.c
@@ -177,19 +177,19 @@ int ecpp_debug = ECPP_DEBUG;
int noecp = 0; /* flag not to use ECP mode */
/* driver entry point fn definitions */
-static int ecpp_open(queue_t *, dev_t *, int, int, cred_t *);
+static int ecpp_open(queue_t *, dev_t *, int, int, cred_t *);
static int ecpp_close(queue_t *, int, cred_t *);
-static uint_t ecpp_isr(caddr_t);
+static uint_t ecpp_isr(caddr_t);
static uint_t ecpp_softintr(caddr_t);
/* configuration entry point fn definitions */
-static int ecpp_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int ecpp_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
static int ecpp_attach(dev_info_t *, ddi_attach_cmd_t);
static int ecpp_detach(dev_info_t *, ddi_detach_cmd_t);
static struct ecpp_hw_bind *ecpp_determine_sio_type(struct ecppunit *);
/* isr support routines */
-static uint_t ecpp_nErr_ihdlr(struct ecppunit *);
+static uint_t ecpp_nErr_ihdlr(struct ecppunit *);
static uint_t ecpp_pio_ihdlr(struct ecppunit *);
static uint_t ecpp_dma_ihdlr(struct ecppunit *);
static uint_t ecpp_M1553_intr(struct ecppunit *);
@@ -213,8 +213,8 @@ static void ecpp_putioc_stateful_copyin(queue_t *, mblk_t *, size_t);
static void ecpp_srvioc_devid(queue_t *, mblk_t *,
struct ecpp_device_id *, int *);
static void ecpp_srvioc_prnif(queue_t *, mblk_t *);
-static void ecpp_ack_ioctl(queue_t *, mblk_t *);
-static void ecpp_nack_ioctl(queue_t *, mblk_t *, int);
+static void ecpp_ack_ioctl(queue_t *, mblk_t *);
+static void ecpp_nack_ioctl(queue_t *, mblk_t *, int);
/* kstat routines */
static void ecpp_kstat_init(struct ecppunit *);
@@ -275,10 +275,10 @@ static uint8_t m1553_read_config_reg(struct ecppunit *, uint8_t);
static void m1553_write_config_reg(struct ecppunit *, uint8_t, uint8_t);
/* M1553 Southbridge DMAC 8237 support routines */
-static int dma8237_dma_start(struct ecppunit *);
+static int dma8237_dma_start(struct ecppunit *);
static int dma8237_dma_stop(struct ecppunit *, size_t *);
static size_t dma8237_getcnt(struct ecppunit *);
-static void dma8237_write_addr(struct ecppunit *, uint32_t);
+static void dma8237_write_addr(struct ecppunit *, uint32_t);
static void dma8237_write_count(struct ecppunit *, uint32_t);
static uint32_t dma8237_read_count(struct ecppunit *);
static void dma8237_write(struct ecppunit *, int, uint8_t);
@@ -301,7 +301,7 @@ static size_t x86_getcnt(struct ecppunit *);
/* IEEE 1284 phase transitions */
static void ecpp_1284_init_interface(struct ecppunit *);
static int ecpp_1284_termination(struct ecppunit *);
-static uchar_t ecpp_idle_phase(struct ecppunit *);
+static uchar_t ecpp_idle_phase(struct ecppunit *);
static int ecp_forward2reverse(struct ecppunit *);
static int ecp_reverse2forward(struct ecppunit *);
static int read_nibble_backchan(struct ecppunit *);
@@ -315,8 +315,8 @@ static void ecpp_ecp_read_timeout(void *);
static void ecpp_ecp_read_completion(struct ecppunit *);
/* IEEE 1284 mode transitions */
-static void ecpp_default_negotiation(struct ecppunit *);
-static int ecpp_mode_negotiation(struct ecppunit *, uchar_t);
+static void ecpp_default_negotiation(struct ecppunit *);
+static int ecpp_mode_negotiation(struct ecppunit *, uchar_t);
static int ecpp_1284_negotiation(struct ecppunit *, uint8_t, uint8_t *);
static int ecp_negotiation(struct ecppunit *);
static int nibble_negotiation(struct ecppunit *);
@@ -691,7 +691,7 @@ ecpp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
(void) sprintf(name, "ecpp%d", instance);
if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
- DDI_NT_PRINTER, NULL) == DDI_FAILURE) {
+ DDI_NT_PRINTER, 0) == DDI_FAILURE) {
ecpp_error(dip, "ecpp_attach: create_minor_node failed\n");
goto fail_minor;
}
@@ -2353,7 +2353,7 @@ ecpp_srvioc(queue_t *q, mblk_t *mp)
break;
}
- if (new_ifcap & PRN_BIDI) { /* go bidirectional */
+ if (new_ifcap & PRN_BIDI) { /* go bidirectional */
ecpp_default_negotiation(pp);
} else { /* go unidirectional */
(void) ecpp_mode_negotiation(pp, ECPP_CENTRONICS);
@@ -2393,7 +2393,7 @@ ecpp_srvioc(queue_t *q, mblk_t *mp)
static void
ecpp_srvioc_devid(queue_t *q, mblk_t *mp, struct ecpp_device_id *id, int *rlen)
{
- struct ecppunit *pp;
+ struct ecppunit *pp;
struct copyresp *csp;
struct ecpp_copystate *stp;
int error;
@@ -3535,7 +3535,7 @@ ecpp_softintr(caddr_t arg)
/*
* Transfer clean-up:
- * shut down the DMAC
+ * shut down the DMAC
* stop the transfer timer
* enable write queue
*/
@@ -4112,7 +4112,7 @@ ecpp_determine_sio_type(struct ecppunit *pp)
/*
*
* IEEE 1284 support routines:
- * negotiation and termination;
+ * negotiation and termination;
* phase transitions;
* device ID;
*
@@ -4281,7 +4281,7 @@ ecpp_1284_negotiation(struct ecppunit *pp, uint8_t xreq, uint8_t *rdsr)
/*
* Event 2: peripheral asserts nAck, deasserts nFault,
- * asserts Select, asserts PError
+ * asserts Select, asserts PError
*/
if (wait_dsr(pp, ECPP_nERR | ECPP_SLCT | ECPP_PE | ECPP_nACK,
ECPP_nERR | ECPP_SLCT | ECPP_PE, 35000) < 0) {
@@ -6203,7 +6203,7 @@ dma8237_read_count(struct ecppunit *pp)
break;
default:
- return (NULL);
+ return (0);
}
p = (uint16_t *)&pp->uh.m1553.isa_space->isa_reg[c_wcnt];
diff --git a/usr/src/uts/common/io/fd.c b/usr/src/uts/common/io/fd.c
index d591e04331..5ad6022610 100644
--- a/usr/src/uts/common/io/fd.c
+++ b/usr/src/uts/common/io/fd.c
@@ -493,7 +493,7 @@ fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
sig_minor = drive_num << 3;
for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
- sig_minor | dmdp->minor, DDI_NT_FD, NULL)
+ sig_minor | dmdp->minor, DDI_NT_FD, 0)
== DDI_FAILURE) {
ddi_remove_minor_node(dip, NULL);
goto no_attach;
@@ -2174,7 +2174,7 @@ fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
* request is passed to ddi_prop_op.
*/
if (dev == DDI_DEV_T_ANY) {
-pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags,
+pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags,
name, valuep, lengthp));
} else {
/*
@@ -2308,7 +2308,7 @@ fd_check_media(dev_t dev, enum dkio_state state)
/*
* fd_get_media_info :
- * Collects medium information for
+ * Collects medium information for
* DKIOCGMEDIAINFO ioctl.
*/
diff --git a/usr/src/uts/common/io/hxge/hxge_hw.c b/usr/src/uts/common/io/hxge/hxge_hw.c
index dec54b5de8..421ce11d5e 100644
--- a/usr/src/uts/common/io/hxge/hxge_hw.c
+++ b/usr/src/uts/common/io/hxge/hxge_hw.c
@@ -330,7 +330,7 @@ hxge_peu_handle_sys_errors(p_hxge_t hxgep)
"==> hxge_peu_handle_sys_errors: hcr_parerr"));
}
- HXGE_FM_REPORT_ERROR(hxgep, NULL, HXGE_FM_EREPORT_PEU_ERR);
+ HXGE_FM_REPORT_ERROR(hxgep, 0, HXGE_FM_EREPORT_PEU_ERR);
return (HXGE_OK);
}
@@ -396,11 +396,11 @@ hxge_syserr_intr(caddr_t arg1, caddr_t arg2)
(void) hxge_peu_handle_sys_errors(hxgep);
if (estat.bits.peu_err1)
- HXGE_FM_REPORT_ERROR(hxgep, NULL,
+ HXGE_FM_REPORT_ERROR(hxgep, 0,
HXGE_FM_EREPORT_PEU_ERR);
if (estat.bits.vnm_pio_err1)
- HXGE_FM_REPORT_ERROR(hxgep, NULL,
+ HXGE_FM_REPORT_ERROR(hxgep, 0,
HXGE_FM_EREPORT_PEU_VNM_PIO_ERR);
} else if (estat.value != 0) {
HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
diff --git a/usr/src/uts/common/io/hxge/hxge_kstats.c b/usr/src/uts/common/io/hxge/hxge_kstats.c
index 09cd73c3a0..f21f690c0a 100644
--- a/usr/src/uts/common/io/hxge/hxge_kstats.c
+++ b/usr/src/uts/common/io/hxge/hxge_kstats.c
@@ -102,7 +102,7 @@ hxge_kstat_index_t hxge_rdc_stats[] = {
{RDC_STAT_RCRTO, KSTAT_DATA_ULONG, "rdc_rcrto"},
{RDC_STAT_RCRTHRES, KSTAT_DATA_ULONG, "rdc_rcrthres"},
{RDC_STAT_PKT_DROP, KSTAT_DATA_ULONG, "rdc_pkt_drop"},
- {RDC_STAT_END, NULL, NULL}
+ {RDC_STAT_END, KSTAT_DATA_ULONG, NULL}
};
typedef enum {
@@ -118,7 +118,7 @@ hxge_kstat_index_t hxge_rdc_sys_stats[] = {
{RDC_SYS_STAT_CTRL_FIFO_DED, KSTAT_DATA_UINT64, "rdc_ctrl_fifo_ded"},
{RDC_SYS_STAT_DATA_FIFO_SEC, KSTAT_DATA_UINT64, "rdc_data_fifo_sec"},
{RDC_SYS_STAT_DATA_FIFO_DED, KSTAT_DATA_UINT64, "tdc_data_fifo_ded"},
- {RDC_SYS_STAT_END, NULL, NULL}
+ {RDC_SYS_STAT_END, KSTAT_DATA_UINT64, NULL}
};
typedef enum {
@@ -184,7 +184,7 @@ hxge_kstat_index_t hxge_tdc_stats[] = {
{TDC_STAT_TX_JUMBO_PKTS, KSTAT_DATA_ULONG, "tdc_tx_jumbo_pkts"},
{TDC_STAT_TX_MAX_PEND, KSTAT_DATA_ULONG, "tdc_tx_max_pend"},
{TDC_STAT_TX_MARKS, KSTAT_DATA_ULONG, "tdc_tx_marks"},
- {TDC_STAT_END, NULL, NULL}
+ {TDC_STAT_END, KSTAT_DATA_ULONG, NULL}
};
typedef enum {
@@ -198,7 +198,7 @@ hxge_kstat_index_t hxge_tdc_sys_stats[] = {
{REORD_TBL_PAR_ERR, KSTAT_DATA_UINT64, "reord_tbl_par_err"},
{REORD_BUF_DED_ERR, KSTAT_DATA_UINT64, "reord_buf_ded_err"},
{REORD_BUF_SEC_ERR, KSTAT_DATA_UINT64, "reord_buf_sec_err"},
- {TDC_SYS_STAT_END, NULL, NULL}
+ {TDC_SYS_STAT_END, KSTAT_DATA_UINT64, NULL}
};
typedef enum {
@@ -230,7 +230,7 @@ hxge_kstat_index_t hxge_vmac_stats[] = {
{VMAC_STAT_RX_PAUSE_CNT, KSTAT_DATA_UINT64, "vmac_rx_pause_cnt"},
{VMAC_STAT_RX_BCAST_FR_CNT, KSTAT_DATA_UINT64, "vmac_rx_bcast_fr_cnt"},
{VMAC_STAT_RX_MCAST_FR_CNT, KSTAT_DATA_UINT64, "vmac_rx_mcast_fr_cnt"},
- {VMAC_STAT_END, NULL, NULL}
+ {VMAC_STAT_END, KSTAT_DATA_UINT64, NULL}
};
typedef enum {
@@ -259,7 +259,7 @@ hxge_kstat_index_t hxge_pfc_stats[] = {
" pfc_pkt_drop_class_code"},
{PFC_STAT_TCAM_DROP, KSTAT_DATA_ULONG, " pfc_pkt_drop_tcam"},
{PFC_STAT_VLAN_DROP, KSTAT_DATA_ULONG, " pfc_pkt_drop_vlan"},
- {PFC_STAT_END, NULL, NULL}
+ {PFC_STAT_END, KSTAT_DATA_ULONG, NULL}
};
typedef enum {
@@ -297,7 +297,7 @@ hxge_kstat_index_t hxge_peu_sys_stats[] = {
{NP_DATAQ_PARERR, KSTAT_DATA_UINT64, "np_dataq_parerr"},
{EIC_MSIX_PARERR, KSTAT_DATA_UINT64, "eic_msix_parerr"},
{HCR_PARERR, KSTAT_DATA_UINT64, "hcr_parerr"},
- {TDC_SYS_STAT_END, NULL, NULL}
+ {TDC_SYS_STAT_END, KSTAT_DATA_UINT64, NULL}
};
typedef enum {
@@ -341,7 +341,7 @@ hxge_kstat_index_t hxge_mmac_stats[] = {
{MMAC_ADDR_POOL14, KSTAT_DATA_UINT64, "mmac_addr_14"},
{MMAC_ADDR_POOL15, KSTAT_DATA_UINT64, "mmac_addr_15"},
{MMAC_ADDR_POOL16, KSTAT_DATA_UINT64, "mmac_addr_16"},
- {MMAC_STATS_END, NULL, NULL},
+ {MMAC_STATS_END, KSTAT_DATA_UINT64, NULL},
};
@@ -624,8 +624,8 @@ hxge_peu_sys_stat_update(kstat_t *ksp, int rw)
static kstat_t *
hxge_setup_local_kstat(p_hxge_t hxgep, int instance, char *name,
- const hxge_kstat_index_t *ksip, size_t count,
- int (*update) (kstat_t *, int))
+ const hxge_kstat_index_t *ksip, size_t count,
+ int (*update) (kstat_t *, int))
{
kstat_t *ksp;
kstat_named_t *knp;
diff --git a/usr/src/uts/common/io/hxge/hxge_main.c b/usr/src/uts/common/io/hxge/hxge_main.c
index 102b7cb285..39683c9bb1 100644
--- a/usr/src/uts/common/io/hxge/hxge_main.c
+++ b/usr/src/uts/common/io/hxge/hxge_main.c
@@ -2394,7 +2394,7 @@ hxge_dma_mem_free(p_hxge_dma_common_t dma_p)
}
dma_p->kaddrp = NULL;
- dma_p->alength = NULL;
+ dma_p->alength = 0;
}
/*
@@ -3255,7 +3255,7 @@ static int
hxge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
uint_t pr_valsize, void *pr_val)
{
- hxge_t *hxgep = barg;
+ hxge_t *hxgep = barg;
p_hxge_stats_t statsp = hxgep->statsp;
int err = 0;
link_flowctrl_t fl;
@@ -4462,9 +4462,9 @@ hxge_link_update(p_hxge_t hxgep, link_state_t state)
static void
hxge_msix_init(p_hxge_t hxgep)
{
- uint32_t data0;
- uint32_t data1;
- uint32_t data2;
+ uint32_t data0;
+ uint32_t data1;
+ uint32_t data2;
int i;
uint32_t msix_entry0;
uint32_t msix_entry1;
diff --git a/usr/src/uts/common/io/hxge/hxge_pfc.c b/usr/src/uts/common/io/hxge/hxge_pfc.c
index e26b4a7c3a..0e4ff9a4fc 100644
--- a/usr/src/uts/common/io/hxge/hxge_pfc.c
+++ b/usr/src/uts/common/io/hxge/hxge_pfc.c
@@ -511,7 +511,7 @@ hxge_pfc_set_hash(p_hxge_t hxgep, uint32_t seed)
{
hpi_status_t rs = HPI_SUCCESS;
hpi_handle_t handle;
- p_hxge_class_pt_cfg_t p_class_cfgp;
+ p_hxge_class_pt_cfg_t p_class_cfgp;
HXGE_DEBUG_MSG((hxgep, PFC_CTL, " ==> hxge_pfc_set_hash"));
@@ -777,7 +777,7 @@ hxge_status_t
hxge_pfc_ip_class_config(p_hxge_t hxgep, tcam_class_t class, uint32_t config)
{
uint32_t class_config;
- p_hxge_class_pt_cfg_t p_class_cfgp;
+ p_hxge_class_pt_cfg_t p_class_cfgp;
tcam_key_cfg_t cfg;
hpi_handle_t handle;
hpi_status_t rs = HPI_SUCCESS;
@@ -866,7 +866,7 @@ hxge_pfc_update_hw(p_hxge_t hxgep)
int max_vlan_groups;
int vlan_group_step;
- p_hxge_class_pt_cfg_t p_class_cfgp;
+ p_hxge_class_pt_cfg_t p_class_cfgp;
HXGE_DEBUG_MSG((hxgep, PFC_CTL, "==> hxge_pfc_update_hw"));
p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
@@ -1017,7 +1017,7 @@ hxge_classify_init_sw(p_hxge_t hxgep)
classify_ptr->tcam_size = TCAM_HXGE_TCAM_MAX_ENTRY;
alloc_size = sizeof (tcam_flow_spec_t) * classify_ptr->tcam_size;
- classify_ptr->tcam_entries = KMEM_ZALLOC(alloc_size, NULL);
+ classify_ptr->tcam_entries = KMEM_ZALLOC(alloc_size, KM_SLEEP);
bzero(classify_ptr->class_usage, sizeof (classify_ptr->class_usage));
/* Start from the beginning of TCAM */
@@ -1044,7 +1044,7 @@ hxge_classify_exit_sw(p_hxge_t hxgep)
alloc_size = fsize * classify_ptr->tcam_size;
KMEM_FREE((void *) classify_ptr->tcam_entries, alloc_size);
}
- hxgep->classifier.state = NULL;
+ hxgep->classifier.state = 0;
HXGE_DEBUG_MSG((hxgep, PFC_CTL, "<== hxge_classify_exit_sw"));
diff --git a/usr/src/uts/common/io/hxge/hxge_rxdma.c b/usr/src/uts/common/io/hxge/hxge_rxdma.c
index d953061d8b..92e9df2b02 100644
--- a/usr/src/uts/common/io/hxge/hxge_rxdma.c
+++ b/usr/src/uts/common/io/hxge/hxge_rxdma.c
@@ -183,7 +183,7 @@ hxge_enable_rxdma_channel(p_hxge_t hxgep, uint16_t channel,
int n_init_kick)
{
hpi_handle_t handle;
- rdc_desc_cfg_t rdc_desc;
+ rdc_desc_cfg_t rdc_desc;
rdc_rcr_cfg_b_t *cfgb_p;
hpi_status_t rs = HPI_SUCCESS;
@@ -1900,7 +1900,7 @@ hxge_receive_packet(p_hxge_t hxgep, p_rx_rcr_ring_t rcr_p,
rdc_stats->ierrors++;
/* Update error stats */
rdc_stats->errlog.compl_err_type = error_type;
- HXGE_FM_REPORT_ERROR(hxgep, NULL, HXGE_FM_EREPORT_RDMC_RCR_ERR);
+ HXGE_FM_REPORT_ERROR(hxgep, 0, HXGE_FM_EREPORT_RDMC_RCR_ERR);
if (error_type & RCR_CTRL_FIFO_DED) {
rdc_stats->ctrl_fifo_ecc_err++;
@@ -2561,13 +2561,13 @@ hxge_map_rxdma_channel_cfg_ring(p_hxge_t hxgep, uint16_t dma_channel,
p_hxge_dma_common_t *dma_mbox_cntl_p, p_rx_rbr_ring_t *rbr_p,
p_rx_rcr_ring_t *rcr_p, p_rx_mbox_t *rx_mbox_p)
{
- p_rx_rbr_ring_t rbrp;
- p_rx_rcr_ring_t rcrp;
- p_rx_mbox_t mboxp;
- p_hxge_dma_common_t cntl_dmap;
- p_hxge_dma_common_t dmap;
- p_rx_msg_t *rx_msg_ring;
- p_rx_msg_t rx_msg_p;
+ p_rx_rbr_ring_t rbrp;
+ p_rx_rcr_ring_t rcrp;
+ p_rx_mbox_t mboxp;
+ p_hxge_dma_common_t cntl_dmap;
+ p_hxge_dma_common_t dmap;
+ p_rx_msg_t *rx_msg_ring;
+ p_rx_msg_t rx_msg_p;
rdc_rbr_cfg_a_t *rcfga_p;
rdc_rbr_cfg_b_t *rcfgb_p;
rdc_rcr_cfg_a_t *cfga_p;
@@ -2580,7 +2580,7 @@ hxge_map_rxdma_channel_cfg_ring(p_hxge_t hxgep, uint16_t dma_channel,
uint32_t bkaddr;
hxge_status_t status = HXGE_OK;
int i;
- uint32_t hxge_port_rcr_size;
+ uint32_t hxge_port_rcr_size;
HXGE_DEBUG_MSG((hxgep, MEM2_CTL,
"==> hxge_map_rxdma_channel_cfg_ring"));
@@ -3535,7 +3535,7 @@ hxge_rxdma_handle_sys_errors(p_hxge_t hxgep)
if (stat.bits.rx_ctrl_fifo_ded) {
/* Global fatal error encountered */
statsp->ctrl_fifo_ded++;
- HXGE_FM_REPORT_ERROR(hxgep, NULL,
+ HXGE_FM_REPORT_ERROR(hxgep, 0,
HXGE_FM_EREPORT_RDMC_CTRL_FIFO_DED);
HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
"==> hxge_rxdma_handle_sys_errors: "
@@ -3553,7 +3553,7 @@ hxge_rxdma_handle_sys_errors(p_hxge_t hxgep)
if (stat.bits.rx_data_fifo_ded) {
/* Global fatal error encountered */
statsp->data_fifo_ded++;
- HXGE_FM_REPORT_ERROR(hxgep, NULL,
+ HXGE_FM_REPORT_ERROR(hxgep, 0,
HXGE_FM_EREPORT_RDMC_DATA_FIFO_DED);
HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
"==> hxge_rxdma_handle_sys_errors: "
@@ -3576,7 +3576,7 @@ static hxge_status_t
hxge_rxdma_fatal_err_recover(p_hxge_t hxgep, uint16_t channel)
{
hpi_handle_t handle;
- hpi_status_t rs = HPI_SUCCESS;
+ hpi_status_t rs = HPI_SUCCESS;
p_rx_rbr_ring_t rbrp;
p_rx_rcr_ring_t rcrp;
p_rx_mbox_t mboxp;
diff --git a/usr/src/uts/common/io/hxge/hxge_txdma.c b/usr/src/uts/common/io/hxge/hxge_txdma.c
index deb5c2b3a1..cf5d0f3eb2 100644
--- a/usr/src/uts/common/io/hxge/hxge_txdma.c
+++ b/usr/src/uts/common/io/hxge/hxge_txdma.c
@@ -2684,7 +2684,7 @@ hxge_txdma_handle_sys_errors(p_hxge_t hxgep)
tdc_sys_stats = &hxgep->statsp->tdc_sys_stats;
if (fifo_stat.bits.reord_tbl_par_err) {
tdc_sys_stats->reord_tbl_par_err++;
- HXGE_FM_REPORT_ERROR(hxgep, NULL,
+ HXGE_FM_REPORT_ERROR(hxgep, 0,
HXGE_FM_EREPORT_TDMC_REORD_TBL_PAR);
HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
"==> hxge_txdma_handle_sys_errors: fatal error: "
@@ -2693,7 +2693,7 @@ hxge_txdma_handle_sys_errors(p_hxge_t hxgep)
if (fifo_stat.bits.reord_buf_ded_err) {
tdc_sys_stats->reord_buf_ded_err++;
- HXGE_FM_REPORT_ERROR(hxgep, NULL,
+ HXGE_FM_REPORT_ERROR(hxgep, 0,
HXGE_FM_EREPORT_TDMC_REORD_BUF_DED);
HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
"==> hxge_txdma_handle_sys_errors: "
diff --git a/usr/src/uts/common/io/i40e/i40e_main.c b/usr/src/uts/common/io/i40e/i40e_main.c
index 20f74d4e95..0623aee513 100644
--- a/usr/src/uts/common/io/i40e/i40e_main.c
+++ b/usr/src/uts/common/io/i40e/i40e_main.c
@@ -11,7 +11,7 @@
/*
* Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
* Copyright 2017 Tegile Systems, Inc. All rights reserved.
*/
@@ -369,7 +369,7 @@
#include "i40e_sw.h"
-static char i40e_ident[] = "Intel 10/40Gb Ethernet v1.0.2";
+static char i40e_ident[] = "Intel 10/40Gb Ethernet v1.0.3";
/*
* The i40e_glock primarily protects the lists below and the i40e_device_t
@@ -2454,6 +2454,7 @@ i40e_chip_start(i40e_t *i40e)
i40e_hw_t *hw = &i40e->i40e_hw_space;
struct i40e_filter_control_settings filter;
int rc;
+ uint8_t err;
if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
(hw->aq.fw_maj_ver < 4)) {
@@ -2469,6 +2470,15 @@ i40e_chip_start(i40e_t *i40e)
/* Determine hardware state */
i40e_get_hw_state(i40e, hw);
+ /* For now, we always disable Ethernet Flow Control. */
+ hw->fc.requested_mode = I40E_FC_NONE;
+ rc = i40e_set_fc(hw, &err, B_TRUE);
+ if (rc != I40E_SUCCESS) {
+ i40e_error(i40e, "Setting flow control failed, returned %d"
+ " with error: 0x%x", rc, err);
+ return (B_FALSE);
+ }
+
/* Initialize mac addresses. */
i40e_init_macaddrs(i40e, hw);
diff --git a/usr/src/uts/common/io/i40e/i40e_stats.c b/usr/src/uts/common/io/i40e/i40e_stats.c
index 97e1a08628..44fe2b0d14 100644
--- a/usr/src/uts/common/io/i40e/i40e_stats.c
+++ b/usr/src/uts/common/io/i40e/i40e_stats.c
@@ -11,7 +11,7 @@
/*
* Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include "i40e_sw.h"
@@ -1232,6 +1232,12 @@ i40e_stats_trqpair_init(i40e_trqpair_t *itrq)
kstat_named_init(&tsp->itxs_recycled, "tx_recycled",
KSTAT_DATA_UINT64);
tsp->itxs_recycled.value.ui64 = 0;
+ kstat_named_init(&tsp->itxs_force_copy, "tx_force_copy",
+ KSTAT_DATA_UINT64);
+ tsp->itxs_force_copy.value.ui64 = 0;
+ kstat_named_init(&tsp->itxs_tso_force_copy, "tx_tso_force_copy",
+ KSTAT_DATA_UINT64);
+ tsp->itxs_tso_force_copy.value.ui64 = 0;
kstat_named_init(&tsp->itxs_hck_meoifail, "tx_hck_meoifail",
KSTAT_DATA_UINT64);
diff --git a/usr/src/uts/common/io/i40e/i40e_sw.h b/usr/src/uts/common/io/i40e/i40e_sw.h
index fbb6d11b41..e735d3eeb0 100644
--- a/usr/src/uts/common/io/i40e/i40e_sw.h
+++ b/usr/src/uts/common/io/i40e/i40e_sw.h
@@ -11,7 +11,7 @@
/*
* Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
* Copyright 2017 Tegile Systems, Inc. All rights reserved.
*/
@@ -529,6 +529,8 @@ typedef struct i40e_txq_stat {
kstat_named_t itxs_packets; /* Packets out on queue */
kstat_named_t itxs_descriptors; /* Descriptors issued */
kstat_named_t itxs_recycled; /* Descriptors reclaimed */
+ kstat_named_t itxs_force_copy; /* non-TSO force copy */
+ kstat_named_t itxs_tso_force_copy; /* TSO force copy */
/*
* Various failure conditions.
*/
diff --git a/usr/src/uts/common/io/i40e/i40e_transceiver.c b/usr/src/uts/common/io/i40e/i40e_transceiver.c
index 28f3b88dee..dbb8ae2f67 100644
--- a/usr/src/uts/common/io/i40e/i40e_transceiver.c
+++ b/usr/src/uts/common/io/i40e/i40e_transceiver.c
@@ -11,7 +11,7 @@
/*
* Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include "i40e_sw.h"
@@ -258,19 +258,29 @@
* The driver is asked to process a single frame at a time. That message block
* may be made up of multiple fragments linked together by the mblk_t`b_cont
* member. The device has a hard limit of up to 8 buffers being allowed for use
- * for a single logical frame. For each fragment, we'll try and use an entry
- * from the TX descriptor ring and then we'll allocate a corresponding TX
- * control block.
+ * for a single non-LSO packet or LSO segment. The number of TX ring entires
+ * (and thus TX control blocks) used depends on the fragment sizes and DMA
+ * layout, as explained below.
*
- * We alter our DMA strategy based on a threshold tied to the frame size.
+ * We alter our DMA strategy based on a threshold tied to the fragment size.
* This threshold is configurable via the tx_dma_threshold property. If the
- * frame size is above the threshold, we do DMA binding of the fragments,
- * building a control block and data descriptor for each piece. If it's below
- * or at the threshold then we just use a single control block and data
- * descriptor and simply bcopy all of the fragments into the pre-allocated DMA
- * buffer in the control block. For the LSO TX case we always do DMA binding of
- * the fragments, with one control block and one TX data descriptor allocated
- * per fragment.
+ * fragment is above the threshold, we DMA bind it -- consuming one TCB and
+ * potentially several data descriptors. The exact number of descriptors (equal
+ * to the number of DMA cookies) depends on page size, MTU size, b_rptr offset
+ * into page, b_wptr offset into page, and the physical layout of the dblk's
+ * memory (contiguous or not). Essentially, we are at the mercy of the DMA
+ * engine and the dblk's memory allocation. Knowing the exact number of
+ * descriptors up front is a task best not taken on by the driver itself.
+ * Instead, we attempt to DMA bind the fragment and verify the descriptor
+ * layout meets hardware constraints. If the proposed DMA bind does not satisfy
+ * the hardware constaints, then we discard it and instead copy the entire
+ * fragment into the pre-allocated TCB buffer (or buffers if the fragment is
+ * larger than the TCB buffer).
+ *
+ * If the fragment is below or at the threshold, we copy it to the pre-allocated
+ * buffer of a TCB. We compress consecutive copy fragments into a single TCB to
+ * conserve resources. We are guaranteed that the TCB buffer is made up of only
+ * 1 DMA cookie; and therefore consumes only one descriptor on the controller.
*
* Furthermore, if the frame requires HW offloads such as LSO, tunneling or
* filtering, then the TX data descriptors must be preceeded by a single TX
@@ -1846,11 +1856,9 @@ mac_ether_offload_info(mblk_t *mp, mac_ether_offload_info_t *meoi)
*/
static int
i40e_tx_context(i40e_t *i40e, i40e_trqpair_t *itrq, mblk_t *mp,
- i40e_tx_context_t *tctx)
+ mac_ether_offload_info_t *meo, i40e_tx_context_t *tctx)
{
- int ret;
uint32_t chkflags, start, mss, lsoflags;
- mac_ether_offload_info_t meo;
i40e_txq_stat_t *txs = &itrq->itrq_txstat;
bzero(tctx, sizeof (i40e_tx_context_t));
@@ -1864,33 +1872,28 @@ i40e_tx_context(i40e_t *i40e, i40e_trqpair_t *itrq, mblk_t *mp,
if (chkflags == 0 && lsoflags == 0)
return (0);
- if ((ret = mac_ether_offload_info(mp, &meo)) != 0) {
- txs->itxs_hck_meoifail.value.ui64++;
- return (ret);
- }
-
/*
* Have we been asked to checksum an IPv4 header. If so, verify that we
* have sufficient information and then set the proper fields in the
* command structure.
*/
if (chkflags & HCK_IPV4_HDRCKSUM) {
- if ((meo.meoi_flags & MEOI_L2INFO_SET) == 0) {
+ if ((meo->meoi_flags & MEOI_L2INFO_SET) == 0) {
txs->itxs_hck_nol2info.value.ui64++;
return (-1);
}
- if ((meo.meoi_flags & MEOI_L3INFO_SET) == 0) {
+ if ((meo->meoi_flags & MEOI_L3INFO_SET) == 0) {
txs->itxs_hck_nol3info.value.ui64++;
return (-1);
}
- if (meo.meoi_l3proto != ETHERTYPE_IP) {
+ if (meo->meoi_l3proto != ETHERTYPE_IP) {
txs->itxs_hck_badl3.value.ui64++;
return (-1);
}
tctx->itc_data_cmdflags |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
- tctx->itc_data_offsets |= (meo.meoi_l2hlen >> 1) <<
+ tctx->itc_data_offsets |= (meo->meoi_l2hlen >> 1) <<
I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
- tctx->itc_data_offsets |= (meo.meoi_l3hlen >> 2) <<
+ tctx->itc_data_offsets |= (meo->meoi_l3hlen >> 2) <<
I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
}
@@ -1901,38 +1904,38 @@ i40e_tx_context(i40e_t *i40e, i40e_trqpair_t *itrq, mblk_t *mp,
* offload.
*/
if (chkflags & HCK_PARTIALCKSUM) {
- if ((meo.meoi_flags & MEOI_L4INFO_SET) == 0) {
+ if ((meo->meoi_flags & MEOI_L4INFO_SET) == 0) {
txs->itxs_hck_nol4info.value.ui64++;
return (-1);
}
if (!(chkflags & HCK_IPV4_HDRCKSUM)) {
- if ((meo.meoi_flags & MEOI_L2INFO_SET) == 0) {
+ if ((meo->meoi_flags & MEOI_L2INFO_SET) == 0) {
txs->itxs_hck_nol2info.value.ui64++;
return (-1);
}
- if ((meo.meoi_flags & MEOI_L3INFO_SET) == 0) {
+ if ((meo->meoi_flags & MEOI_L3INFO_SET) == 0) {
txs->itxs_hck_nol3info.value.ui64++;
return (-1);
}
- if (meo.meoi_l3proto == ETHERTYPE_IP) {
+ if (meo->meoi_l3proto == ETHERTYPE_IP) {
tctx->itc_data_cmdflags |=
I40E_TX_DESC_CMD_IIPT_IPV4;
- } else if (meo.meoi_l3proto == ETHERTYPE_IPV6) {
+ } else if (meo->meoi_l3proto == ETHERTYPE_IPV6) {
tctx->itc_data_cmdflags |=
I40E_TX_DESC_CMD_IIPT_IPV6;
} else {
txs->itxs_hck_badl3.value.ui64++;
return (-1);
}
- tctx->itc_data_offsets |= (meo.meoi_l2hlen >> 1) <<
+ tctx->itc_data_offsets |= (meo->meoi_l2hlen >> 1) <<
I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
- tctx->itc_data_offsets |= (meo.meoi_l3hlen >> 2) <<
+ tctx->itc_data_offsets |= (meo->meoi_l3hlen >> 2) <<
I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
}
- switch (meo.meoi_l4proto) {
+ switch (meo->meoi_l4proto) {
case IPPROTO_TCP:
tctx->itc_data_cmdflags |=
I40E_TX_DESC_CMD_L4T_EOFT_TCP;
@@ -1950,7 +1953,7 @@ i40e_tx_context(i40e_t *i40e, i40e_trqpair_t *itrq, mblk_t *mp,
return (-1);
}
- tctx->itc_data_offsets |= (meo.meoi_l4hlen >> 2) <<
+ tctx->itc_data_offsets |= (meo->meoi_l4hlen >> 2) <<
I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
}
@@ -1968,7 +1971,7 @@ i40e_tx_context(i40e_t *i40e, i40e_trqpair_t *itrq, mblk_t *mp,
tctx->itc_ctx_cmdflags |= I40E_TX_CTX_DESC_TSO;
tctx->itc_ctx_mss = mss;
tctx->itc_ctx_tsolen = msgsize(mp) -
- (meo.meoi_l2hlen + meo.meoi_l3hlen + meo.meoi_l4hlen);
+ (meo->meoi_l2hlen + meo->meoi_l3hlen + meo->meoi_l4hlen);
}
return (0);
@@ -2205,9 +2208,28 @@ i40e_tx_recycle_ring(i40e_trqpair_t *itrq)
DTRACE_PROBE2(i40e__recycle, i40e_trqpair_t *, itrq, uint32_t, count);
}
+static void
+i40e_tx_copy_fragment(i40e_tx_control_block_t *tcb, const mblk_t *mp,
+ const size_t off, const size_t len)
+{
+ const void *soff = mp->b_rptr + off;
+ void *doff = tcb->tcb_dma.dmab_address + tcb->tcb_dma.dmab_len;
+
+ ASSERT3U(len, >, 0);
+ ASSERT3P(soff, >=, mp->b_rptr);
+ ASSERT3P(soff, <=, mp->b_wptr);
+ ASSERT3U(len, <=, MBLKL(mp));
+ ASSERT3U((uintptr_t)soff + len, <=, (uintptr_t)mp->b_wptr);
+ ASSERT3U(tcb->tcb_dma.dmab_size - tcb->tcb_dma.dmab_len, >=, len);
+ bcopy(soff, doff, len);
+ tcb->tcb_type = I40E_TX_COPY;
+ tcb->tcb_dma.dmab_len += len;
+ I40E_DMA_SYNC(&tcb->tcb_dma, DDI_DMA_SYNC_FORDEV);
+}
+
static i40e_tx_control_block_t *
i40e_tx_bind_fragment(i40e_trqpair_t *itrq, const mblk_t *mp,
- boolean_t use_lso)
+ size_t off, boolean_t use_lso)
{
ddi_dma_handle_t dma_handle;
ddi_dma_cookie_t dma_cookie;
@@ -2228,11 +2250,12 @@ i40e_tx_bind_fragment(i40e_trqpair_t *itrq, const mblk_t *mp,
dmaflags = DDI_DMA_WRITE | DDI_DMA_STREAMING;
if (ddi_dma_addr_bind_handle(dma_handle, NULL,
- (caddr_t)mp->b_rptr, MBLKL(mp), dmaflags, DDI_DMA_DONTWAIT, NULL,
- &dma_cookie, &ncookies) != DDI_DMA_MAPPED) {
+ (caddr_t)(mp->b_rptr + off), MBLKL(mp) - off, dmaflags,
+ DDI_DMA_DONTWAIT, NULL, &dma_cookie, &ncookies) != DDI_DMA_MAPPED) {
txs->itxs_bind_fails.value.ui64++;
goto bffail;
}
+
tcb->tcb_bind_ncookies = ncookies;
tcb->tcb_used_lso = use_lso;
@@ -2261,7 +2284,7 @@ bffail:
static void
i40e_tx_set_data_desc(i40e_trqpair_t *itrq, i40e_tx_context_t *tctx,
- struct i40e_dma_bind_info *dbi, boolean_t last_desc)
+ caddr_t buff, size_t len, boolean_t last_desc)
{
i40e_tx_desc_t *txdesc;
int cmd;
@@ -2290,21 +2313,479 @@ i40e_tx_set_data_desc(i40e_trqpair_t *itrq, i40e_tx_context_t *tctx,
* Per the X710 manual, section 8.4.2.1.1, the buffer size
* must be a value from 1 to 16K minus 1, inclusive.
*/
- ASSERT3U(dbi->dbi_len, >=, 1);
- ASSERT3U(dbi->dbi_len, <=, I40E_MAX_TX_BUFSZ - 1);
+ ASSERT3U(len, >=, 1);
+ ASSERT3U(len, <=, I40E_MAX_TX_BUFSZ - 1);
- txdesc->buffer_addr = CPU_TO_LE64((uintptr_t)dbi->dbi_paddr);
+ txdesc->buffer_addr = CPU_TO_LE64((uintptr_t)buff);
txdesc->cmd_type_offset_bsz =
LE_64(((uint64_t)I40E_TX_DESC_DTYPE_DATA |
((uint64_t)tctx->itc_data_offsets << I40E_TXD_QW1_OFFSET_SHIFT) |
((uint64_t)cmd << I40E_TXD_QW1_CMD_SHIFT) |
- ((uint64_t)dbi->dbi_len << I40E_TXD_QW1_TX_BUF_SZ_SHIFT)));
+ ((uint64_t)len << I40E_TXD_QW1_TX_BUF_SZ_SHIFT)));
+}
+
+/*
+ * Place 'tcb' on the tail of the list represented by 'head'/'tail'.
+ */
+static inline void
+tcb_list_append(i40e_tx_control_block_t **head, i40e_tx_control_block_t **tail,
+ i40e_tx_control_block_t *tcb)
+{
+ if (*head == NULL) {
+ *head = tcb;
+ *tail = *head;
+ } else {
+ ASSERT3P(*tail, !=, NULL);
+ ASSERT3P((*tail)->tcb_next, ==, NULL);
+ (*tail)->tcb_next = tcb;
+ *tail = tcb;
+ }
+}
+
+/*
+ * This function takes a single packet, possibly consisting of
+ * multiple mblks, and creates a TCB chain to send to the controller.
+ * This TCB chain may span up to a maximum of 8 descriptors. A copy
+ * TCB consumes one descriptor; whereas a DMA TCB may consume 1 or
+ * more, depending on several factors. For each fragment (invidual
+ * mblk making up the packet), we determine if its size dictates a
+ * copy to the TCB buffer or a DMA bind of the dblk buffer. We keep a
+ * count of descriptors used; when that count reaches the max we force
+ * all remaining fragments into a single TCB buffer. We have a
+ * guarantee that the TCB buffer is always larger than the MTU -- so
+ * there is always enough room. Consecutive fragments below the DMA
+ * threshold are copied into a single TCB. In the event of an error
+ * this function returns NULL but leaves 'mp' alone.
+ */
+static i40e_tx_control_block_t *
+i40e_non_lso_chain(i40e_trqpair_t *itrq, mblk_t *mp, uint_t *ndesc)
+{
+ const mblk_t *nmp = mp;
+ uint_t needed_desc = 0;
+ boolean_t force_copy = B_FALSE;
+ i40e_tx_control_block_t *tcb = NULL, *tcbhead = NULL, *tcbtail = NULL;
+ i40e_t *i40e = itrq->itrq_i40e;
+ i40e_txq_stat_t *txs = &itrq->itrq_txstat;
+
+ /* TCB buffer is always larger than MTU. */
+ ASSERT3U(msgsize(mp), <, i40e->i40e_tx_buf_size);
+
+ while (nmp != NULL) {
+ const size_t nmp_len = MBLKL(nmp);
+
+ /* Ignore zero-length mblks. */
+ if (nmp_len == 0) {
+ nmp = nmp->b_cont;
+ continue;
+ }
+
+ if (nmp_len < i40e->i40e_tx_dma_min || force_copy) {
+ /* Compress consecutive copies into one TCB. */
+ if (tcb != NULL && tcb->tcb_type == I40E_TX_COPY) {
+ i40e_tx_copy_fragment(tcb, nmp, 0, nmp_len);
+ nmp = nmp->b_cont;
+ continue;
+ }
+
+ if ((tcb = i40e_tcb_alloc(itrq)) == NULL) {
+ txs->itxs_err_notcb.value.ui64++;
+ goto fail;
+ }
+
+ /*
+ * TCB DMA buffer is guaranteed to be one
+ * cookie by i40e_alloc_dma_buffer().
+ */
+ i40e_tx_copy_fragment(tcb, nmp, 0, nmp_len);
+ needed_desc++;
+ tcb_list_append(&tcbhead, &tcbtail, tcb);
+ } else {
+ uint_t total_desc;
+
+ tcb = i40e_tx_bind_fragment(itrq, nmp, 0, B_FALSE);
+ if (tcb == NULL) {
+ i40e_error(i40e, "dma bind failed!");
+ goto fail;
+ }
+
+ /*
+ * If the new total exceeds the max or we've
+ * reached the limit and there's data left,
+ * then give up binding and copy the rest into
+ * the pre-allocated TCB buffer.
+ */
+ total_desc = needed_desc + tcb->tcb_bind_ncookies;
+ if ((total_desc > I40E_TX_MAX_COOKIE) ||
+ (total_desc == I40E_TX_MAX_COOKIE &&
+ nmp->b_cont != NULL)) {
+ i40e_tcb_reset(tcb);
+ i40e_tcb_free(itrq, tcb);
+
+ if (tcbtail != NULL &&
+ tcbtail->tcb_type == I40E_TX_COPY) {
+ tcb = tcbtail;
+ } else {
+ tcb = NULL;
+ }
+
+ force_copy = B_TRUE;
+ txs->itxs_force_copy.value.ui64++;
+ continue;
+ }
+
+ needed_desc += tcb->tcb_bind_ncookies;
+ tcb_list_append(&tcbhead, &tcbtail, tcb);
+ }
+
+ nmp = nmp->b_cont;
+ }
+
+ ASSERT3P(nmp, ==, NULL);
+ ASSERT3U(needed_desc, <=, I40E_TX_MAX_COOKIE);
+ ASSERT3P(tcbhead, !=, NULL);
+ *ndesc += needed_desc;
+ return (tcbhead);
+
+fail:
+ tcb = tcbhead;
+ while (tcb != NULL) {
+ i40e_tx_control_block_t *next = tcb->tcb_next;
+
+ ASSERT(tcb->tcb_type == I40E_TX_DMA ||
+ tcb->tcb_type == I40E_TX_COPY);
+
+ tcb->tcb_mp = NULL;
+ i40e_tcb_reset(tcb);
+ i40e_tcb_free(itrq, tcb);
+ tcb = next;
+ }
+
+ return (NULL);
+}
+
+/*
+ * Section 8.4.1 of the 700-series programming guide states that a
+ * segment may span up to 8 data descriptors; including both header
+ * and payload data. However, empirical evidence shows that the
+ * controller freezes the Tx queue when presented with a segment of 8
+ * descriptors. Or, at least, when the first segment contains 8
+ * descriptors. One explanation is that the controller counts the
+ * context descriptor against the first segment, even though the
+ * programming guide makes no mention of such a constraint. In any
+ * case, we limit TSO segments to 7 descriptors to prevent Tx queue
+ * freezes. We still allow non-TSO segments to utilize all 8
+ * descriptors as they have not demonstrated the faulty behavior.
+ */
+uint_t i40e_lso_num_descs = 7;
+
+#define I40E_TCB_LEFT(tcb) \
+ ((tcb)->tcb_dma.dmab_size - (tcb)->tcb_dma.dmab_len)
+
+/*
+ * This function is similar in spirit to i40e_non_lso_chain(), but
+ * much more complicated in reality. Like the previous function, it
+ * takes a packet (an LSO packet) as input and returns a chain of
+ * TCBs. The complication comes with the fact that we are no longer
+ * trying to fit the entire packet into 8 descriptors, but rather we
+ * must fit each MSS-size segment of the LSO packet into 8 descriptors.
+ * Except it's really 7 descriptors, see i40e_lso_num_descs.
+ *
+ * Your first inclination might be to verify that a given segment
+ * spans no more than 7 mblks; but it's actually much more subtle than
+ * that. First, let's describe what the hardware expects, and then we
+ * can expound on the software side of things.
+ *
+ * For an LSO packet the hardware expects the following:
+ *
+ * o Each MSS-sized segment must span no more than 7 descriptors.
+ *
+ * o The header size does not count towards the segment size.
+ *
+ * o If header and payload share the first descriptor, then the
+ * controller will count the descriptor twice.
+ *
+ * The most important thing to keep in mind is that the hardware does
+ * not view the segments in terms of mblks, like we do. The hardware
+ * only sees descriptors. It will iterate each descriptor in turn,
+ * keeping a tally of bytes seen and descriptors visited. If the byte
+ * count hasn't reached MSS by the time the descriptor count reaches
+ * 7, then the controller freezes the queue and we are stuck.
+ * Furthermore, the hardware picks up its tally where it left off. So
+ * if it reached MSS in the middle of a descriptor, it will start
+ * tallying the next segment in the middle of that descriptor. The
+ * hardware's view is entirely removed from the mblk chain or even the
+ * descriptor layout. Consider these facts:
+ *
+ * o The MSS will vary dpeneding on MTU and other factors.
+ *
+ * o The dblk allocation will sit at various offsets within a
+ * memory page.
+ *
+ * o The page size itself could vary in the future (i.e. not
+ * always 4K).
+ *
+ * o Just because a dblk is virtually contiguous doesn't mean
+ * it's physically contiguous. The number of cookies
+ * (descriptors) required by a DMA bind of a single dblk is at
+ * the mercy of the page size and physical layout.
+ *
+ * o The descriptors will most often NOT start/end on a MSS
+ * boundary. Thus the hardware will often start counting the
+ * MSS mid descriptor and finish mid descriptor.
+ *
+ * The upshot of all this is that the driver must learn to think like
+ * the controller; and verify that none of the constraints are broken.
+ * It does this by tallying up the segment just like the hardware
+ * would. This is handled by the two variables 'segsz' and 'segdesc'.
+ * After each attempt to bind a dblk, we check the constaints. If
+ * violated, we undo the DMA and force a copy until MSS is met. We
+ * have a guarantee that the TCB buffer is larger than MTU; thus
+ * ensuring we can always meet the MSS with a single copy buffer. We
+ * also copy consecutive non-DMA fragments into the same TCB buffer.
+ */
+static i40e_tx_control_block_t *
+i40e_lso_chain(i40e_trqpair_t *itrq, const mblk_t *mp,
+ const mac_ether_offload_info_t *meo, const i40e_tx_context_t *tctx,
+ uint_t *ndesc)
+{
+ size_t mp_len = MBLKL(mp);
+ /*
+ * The cpoff (copy offset) variable tracks the offset inside
+ * the current mp. There are cases where the entire mp is not
+ * fully copied in one go: such as the header copy followed by
+ * a non-DMA mblk, or a TCB buffer that only has enough space
+ * to copy part of the current mp.
+ */
+ size_t cpoff = 0;
+ /*
+ * The segsz and segdesc variables track the controller's view
+ * of the segment. The needed_desc variable tracks the total
+ * number of data descriptors used by the driver.
+ */
+ size_t segsz = 0;
+ uint_t segdesc = 0;
+ uint_t needed_desc = 0;
+ const size_t hdrlen =
+ meo->meoi_l2hlen + meo->meoi_l3hlen + meo->meoi_l4hlen;
+ const size_t mss = tctx->itc_ctx_mss;
+ boolean_t force_copy = B_FALSE;
+ i40e_tx_control_block_t *tcb = NULL, *tcbhead = NULL, *tcbtail = NULL;
+ i40e_t *i40e = itrq->itrq_i40e;
+ i40e_txq_stat_t *txs = &itrq->itrq_txstat;
+
+ /*
+ * We always copy the header in order to avoid more
+ * complicated code dealing with various edge cases.
+ */
+ ASSERT3U(MBLKL(mp), >=, hdrlen);
+ if ((tcb = i40e_tcb_alloc(itrq)) == NULL) {
+ txs->itxs_err_notcb.value.ui64++;
+ goto fail;
+ }
+ needed_desc++;
+
+ tcb_list_append(&tcbhead, &tcbtail, tcb);
+ i40e_tx_copy_fragment(tcb, mp, 0, hdrlen);
+ cpoff += hdrlen;
+
+ /*
+ * A single descriptor containing both header and data is
+ * counted twice by the controller.
+ */
+ if ((mp_len > hdrlen && mp_len < i40e->i40e_tx_dma_min) ||
+ (mp->b_cont != NULL &&
+ MBLKL(mp->b_cont) < i40e->i40e_tx_dma_min)) {
+ segdesc = 2;
+ } else {
+ segdesc = 1;
+ }
+
+ /* If this fragment was pure header, then move to the next one. */
+ if (cpoff == mp_len) {
+ mp = mp->b_cont;
+ cpoff = 0;
+ }
+
+ while (mp != NULL) {
+ mp_len = MBLKL(mp);
+force_copy:
+ /* Ignore zero-length mblks. */
+ if (mp_len == 0) {
+ mp = mp->b_cont;
+ cpoff = 0;
+ continue;
+ }
+
+ /*
+ * We copy into the preallocated TCB buffer when the
+ * current fragment is less than the DMA threshold OR
+ * when the DMA bind can't meet the controller's
+ * segment descriptor limit.
+ */
+ if (mp_len < i40e->i40e_tx_dma_min || force_copy) {
+ size_t tocopy;
+
+ /*
+ * Our objective here is to compress
+ * consecutive copies into one TCB (until it
+ * is full). If there is no current TCB, or if
+ * it is a DMA TCB, then allocate a new one.
+ */
+ if (tcb == NULL ||
+ (tcb != NULL && tcb->tcb_type != I40E_TX_COPY)) {
+ if ((tcb = i40e_tcb_alloc(itrq)) == NULL) {
+ txs->itxs_err_notcb.value.ui64++;
+ goto fail;
+ }
+
+ /*
+ * The TCB DMA buffer is guaranteed to
+ * be one cookie by i40e_alloc_dma_buffer().
+ */
+ needed_desc++;
+ segdesc++;
+ ASSERT3U(segdesc, <=, i40e_lso_num_descs);
+ tcb_list_append(&tcbhead, &tcbtail, tcb);
+ }
+
+ tocopy = MIN(I40E_TCB_LEFT(tcb), mp_len - cpoff);
+ i40e_tx_copy_fragment(tcb, mp, cpoff, tocopy);
+ cpoff += tocopy;
+ segsz += tocopy;
+
+ /* We have consumed the current mp. */
+ if (cpoff == mp_len) {
+ mp = mp->b_cont;
+ cpoff = 0;
+ }
+
+ /* We have consumed the current TCB buffer. */
+ if (I40E_TCB_LEFT(tcb) == 0) {
+ tcb = NULL;
+ }
+
+ /*
+ * We have met MSS with this copy; restart the
+ * counters.
+ */
+ if (segsz >= mss) {
+ segsz = segsz % mss;
+ segdesc = segsz == 0 ? 0 : 1;
+ force_copy = B_FALSE;
+ }
+
+ /*
+ * We are at the controller's descriptor
+ * limit; we must copy into the current TCB
+ * until MSS is reached. The TCB buffer is
+ * always bigger than the MTU so we know it is
+ * big enough to meet the MSS.
+ */
+ if (segdesc == i40e_lso_num_descs) {
+ force_copy = B_TRUE;
+ }
+ } else {
+ uint_t tsegdesc = segdesc;
+ size_t tsegsz = segsz;
+
+ ASSERT(force_copy == B_FALSE);
+ ASSERT3U(tsegdesc, <, i40e_lso_num_descs);
+
+ tcb = i40e_tx_bind_fragment(itrq, mp, cpoff, B_TRUE);
+ if (tcb == NULL) {
+ i40e_error(i40e, "dma bind failed!");
+ goto fail;
+ }
+
+ for (uint_t i = 0; i < tcb->tcb_bind_ncookies; i++) {
+ struct i40e_dma_bind_info dbi =
+ tcb->tcb_bind_info[i];
+
+ tsegsz += dbi.dbi_len;
+ tsegdesc++;
+ ASSERT3U(tsegdesc, <=, i40e_lso_num_descs);
+
+ /*
+ * We've met the MSS with this portion
+ * of the DMA.
+ */
+ if (tsegsz >= mss) {
+ tsegdesc = 1;
+ tsegsz = tsegsz % mss;
+ }
+
+ /*
+ * We've reached max descriptors but
+ * have not met the MSS. Undo the bind
+ * and instead copy.
+ */
+ if (tsegdesc == i40e_lso_num_descs) {
+ i40e_tcb_reset(tcb);
+ i40e_tcb_free(itrq, tcb);
+
+ if (tcbtail != NULL &&
+ I40E_TCB_LEFT(tcb) > 0 &&
+ tcbtail->tcb_type == I40E_TX_COPY) {
+ tcb = tcbtail;
+ } else {
+ tcb = NULL;
+ }
+
+ /*
+ * Remember, we are still on
+ * the same mp.
+ */
+ force_copy = B_TRUE;
+ txs->itxs_tso_force_copy.value.ui64++;
+ goto force_copy;
+ }
+ }
+
+ ASSERT3U(tsegdesc, <=, i40e_lso_num_descs);
+ ASSERT3U(tsegsz, <, mss);
+
+ /*
+ * We've made if through the loop without
+ * breaking the segment descriptor contract
+ * with the controller -- replace the segment
+ * tracking values with the temporary ones.
+ */
+ segdesc = tsegdesc;
+ segsz = tsegsz;
+ needed_desc += tcb->tcb_bind_ncookies;
+ cpoff = 0;
+ tcb_list_append(&tcbhead, &tcbtail, tcb);
+ mp = mp->b_cont;
+ }
+ }
+
+ ASSERT3P(mp, ==, NULL);
+ ASSERT3P(tcbhead, !=, NULL);
+ *ndesc += needed_desc;
+ return (tcbhead);
+
+fail:
+ tcb = tcbhead;
+ while (tcb != NULL) {
+ i40e_tx_control_block_t *next = tcb->tcb_next;
+
+ ASSERT(tcb->tcb_type == I40E_TX_DMA ||
+ tcb->tcb_type == I40E_TX_COPY);
+
+ tcb->tcb_mp = NULL;
+ i40e_tcb_reset(tcb);
+ i40e_tcb_free(itrq, tcb);
+ tcb = next;
+ }
+
+ return (NULL);
}
/*
* We've been asked to send a message block on the wire. We'll only have a
* single chain. There will not be any b_next pointers; however, there may be
- * multiple b_cont blocks.
+ * multiple b_cont blocks. The number of b_cont blocks may exceed the
+ * controller's Tx descriptor limit.
*
* We may do one of three things with any given mblk_t chain:
*
@@ -2319,17 +2800,14 @@ i40e_tx_set_data_desc(i40e_trqpair_t *itrq, i40e_tx_context_t *tctx,
mblk_t *
i40e_ring_tx(void *arg, mblk_t *mp)
{
- const mblk_t *nmp;
- size_t mpsize;
- i40e_tx_control_block_t *tcb_ctx = NULL, *tcb_data = NULL,
- **tcb_dma = NULL;
- i40e_tx_desc_t *txdesc;
+ size_t msglen;
+ i40e_tx_control_block_t *tcb_ctx = NULL, *tcb = NULL, *tcbhead = NULL;
i40e_tx_context_desc_t *ctxdesc;
+ mac_ether_offload_info_t meo;
i40e_tx_context_t tctx;
- int cmd, type;
- uint_t i, needed_desc = 0, nbufs = 0;
- boolean_t do_ctx_desc = B_FALSE, do_dma_bind = B_FALSE,
- use_lso = B_FALSE;
+ int type;
+ uint_t needed_desc = 0;
+ boolean_t do_ctx_desc = B_FALSE, use_lso = B_FALSE;
i40e_trqpair_t *itrq = arg;
i40e_t *i40e = itrq->itrq_i40e;
@@ -2347,12 +2825,18 @@ i40e_ring_tx(void *arg, mblk_t *mp)
return (NULL);
}
+ if (mac_ether_offload_info(mp, &meo) != 0) {
+ freemsg(mp);
+ itrq->itrq_txstat.itxs_hck_meoifail.value.ui64++;
+ return (NULL);
+ }
+
/*
* Figure out the relevant context about this frame that we might need
* for enabling checksum, LSO, etc. This also fills in information that
* we might set around the packet type, etc.
*/
- if (i40e_tx_context(i40e, itrq, mp, &tctx) < 0) {
+ if (i40e_tx_context(i40e, itrq, mp, &meo, &tctx) < 0) {
freemsg(mp);
itrq->itrq_txstat.itxs_err_context.value.ui64++;
return (NULL);
@@ -2368,20 +2852,7 @@ i40e_ring_tx(void *arg, mblk_t *mp)
* recycling to cut back on stalls in the TX path.
*/
- /*
- * Iterate through the mblks to calculate both the total size of the
- * frame and the number of fragments. This is used to determine
- * whether we're doing DMA binding and, if so, how many TX control
- * blocks we'll need.
- */
- mpsize = 0;
- for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) {
- size_t blksz = MBLKL(nmp);
- if (blksz > 0) {
- mpsize += blksz;
- nbufs++;
- }
- }
+ msglen = msgsize(mp);
if (do_ctx_desc) {
/*
@@ -2399,75 +2870,16 @@ i40e_ring_tx(void *arg, mblk_t *mp)
needed_desc++;
}
- /*
- * For the non-LSO TX case, we alter our DMA strategy based on a
- * threshold tied to the frame size. This threshold is configurable
- * via the tx_dma_threshold property.
- *
- * If the frame size is above the threshold, we do DMA binding of the
- * fragments, building a control block and data descriptor for each
- * piece.
- *
- * If it's below or at the threshold then we just use a single control
- * block and data descriptor and simply bcopy all of the fragments into
- * the pre-allocated DMA buffer in the control block.
- *
- * For the LSO TX case we always do DMA binding.
- */
- if (use_lso == B_TRUE || mpsize > i40e->i40e_tx_dma_min) {
- do_dma_bind = B_TRUE;
- tcb_dma =
- kmem_zalloc(nbufs * sizeof (i40e_tx_control_block_t *),
- KM_NOSLEEP);
- if (tcb_dma == NULL) {
- i40e_error(i40e, "failed to allocate tcb_dma list");
- goto txfail;
- }
- /*
- * For each b_cont: bind the control block's DMA handle to the
- * b_rptr, and record the cookies so that we can later iterate
- * through them and build TX data descriptors.
- */
- for (nmp = mp, i = 0; nmp != NULL; nmp = nmp->b_cont) {
- if (MBLKL(nmp) == 0)
- continue;
- tcb_dma[i] = i40e_tx_bind_fragment(itrq, nmp, use_lso);
- if (tcb_dma[i] == NULL) {
- i40e_error(i40e, "dma bind failed!");
- goto txfail;
- }
- if (i == 0)
- tcb_dma[i]->tcb_mp = mp;
- needed_desc += tcb_dma[i++]->tcb_bind_ncookies;
- }
+ if (!use_lso) {
+ tcbhead = i40e_non_lso_chain(itrq, mp, &needed_desc);
} else {
- /*
- * Just use a single control block and bcopy all of the
- * fragments into its pre-allocated DMA buffer.
- */
- if ((tcb_data = i40e_tcb_alloc(itrq)) == NULL) {
- txs->itxs_err_notcb.value.ui64++;
- goto txfail;
- }
- tcb_data->tcb_type = I40E_TX_COPY;
-
- ASSERT(tcb_data->tcb_dma.dmab_len == 0);
- ASSERT(tcb_data->tcb_dma.dmab_size >= mpsize);
-
- for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) {
- size_t clen = MBLKL(nmp);
- void *coff = tcb_data->tcb_dma.dmab_address +
- tcb_data->tcb_dma.dmab_len;
+ tcbhead = i40e_lso_chain(itrq, mp, &meo, &tctx, &needed_desc);
+ }
- bcopy(nmp->b_rptr, coff, clen);
- tcb_data->tcb_dma.dmab_len += clen;
- }
- ASSERT(tcb_data->tcb_dma.dmab_len == mpsize);
- I40E_DMA_SYNC(&tcb_data->tcb_dma, DDI_DMA_SYNC_FORDEV);
+ if (tcbhead == NULL)
+ goto txfail;
- tcb_data->tcb_mp = mp;
- needed_desc++;
- }
+ tcbhead->tcb_mp = mp;
/*
* The second condition ensures that 'itrq_desc_tail' never
@@ -2517,51 +2929,32 @@ i40e_ring_tx(void *arg, mblk_t *mp)
}
}
- if (do_dma_bind == B_TRUE) {
- /*
- * Next build up a transmit data descriptor for each buffer.
- */
- boolean_t last_desc = B_FALSE;
- for (i = 0; i < nbufs; i++) {
- itrq->itrq_tcb_work_list[itrq->itrq_desc_tail] =
- tcb_dma[i];
-
- for (uint_t c = 0; c < tcb_dma[i]->tcb_bind_ncookies;
- c++) {
- if (i == (nbufs - 1) &&
- c == (tcb_dma[i]->tcb_bind_ncookies - 1)) {
- last_desc = B_TRUE;
- }
+ tcb = tcbhead;
+ while (tcb != NULL) {
+
+ itrq->itrq_tcb_work_list[itrq->itrq_desc_tail] = tcb;
+ if (tcb->tcb_type == I40E_TX_COPY) {
+ boolean_t last_desc = (tcb->tcb_next == NULL);
+
+ i40e_tx_set_data_desc(itrq, &tctx,
+ (caddr_t)tcb->tcb_dma.dmab_dma_address,
+ tcb->tcb_dma.dmab_len, last_desc);
+ } else {
+ boolean_t last_desc = B_FALSE;
+ ASSERT3S(tcb->tcb_type, ==, I40E_TX_DMA);
+
+ for (uint_t c = 0; c < tcb->tcb_bind_ncookies; c++) {
+ last_desc = (c == tcb->tcb_bind_ncookies - 1) &&
+ (tcb->tcb_next == NULL);
+
i40e_tx_set_data_desc(itrq, &tctx,
- &tcb_dma[i]->tcb_bind_info[c], last_desc);
+ tcb->tcb_bind_info[c].dbi_paddr,
+ tcb->tcb_bind_info[c].dbi_len,
+ last_desc);
}
}
- kmem_free(tcb_dma, nbufs * sizeof (i40e_tx_control_block_t *));
- tcb_dma = NULL;
- } else {
- /*
- * Build up the single transmit data descriptor needed for the
- * non-DMA-bind case.
- */
- itrq->itrq_desc_free--;
- txdesc = &itrq->itrq_desc_ring[itrq->itrq_desc_tail];
- itrq->itrq_tcb_work_list[itrq->itrq_desc_tail] = tcb_data;
- itrq->itrq_desc_tail = i40e_next_desc(itrq->itrq_desc_tail, 1,
- itrq->itrq_tx_ring_size);
- type = I40E_TX_DESC_DTYPE_DATA;
- cmd = I40E_TX_DESC_CMD_EOP |
- I40E_TX_DESC_CMD_RS |
- I40E_TX_DESC_CMD_ICRC |
- tctx.itc_data_cmdflags;
- txdesc->buffer_addr =
- CPU_TO_LE64((uintptr_t)tcb_data->tcb_dma.dmab_dma_address);
- txdesc->cmd_type_offset_bsz = CPU_TO_LE64(((uint64_t)type |
- ((uint64_t)tctx.itc_data_offsets <<
- I40E_TXD_QW1_OFFSET_SHIFT) |
- ((uint64_t)cmd << I40E_TXD_QW1_CMD_SHIFT) |
- ((uint64_t)tcb_data->tcb_dma.dmab_len <<
- I40E_TXD_QW1_TX_BUF_SZ_SHIFT)));
+ tcb = tcb->tcb_next;
}
/*
@@ -2583,7 +2976,7 @@ i40e_ring_tx(void *arg, mblk_t *mp)
atomic_or_32(&i40e->i40e_state, I40E_ERROR);
}
- txs->itxs_bytes.value.ui64 += mpsize;
+ txs->itxs_bytes.value.ui64 += msglen;
txs->itxs_packets.value.ui64++;
txs->itxs_descriptors.value.ui64 += needed_desc;
@@ -2603,20 +2996,18 @@ txfail:
i40e_tcb_reset(tcb_ctx);
i40e_tcb_free(itrq, tcb_ctx);
}
- if (tcb_data != NULL) {
- tcb_data->tcb_mp = NULL;
- i40e_tcb_reset(tcb_data);
- i40e_tcb_free(itrq, tcb_data);
- }
- if (tcb_dma != NULL) {
- for (i = 0; i < nbufs; i++) {
- if (tcb_dma[i] == NULL)
- break;
- tcb_dma[i]->tcb_mp = NULL;
- i40e_tcb_reset(tcb_dma[i]);
- i40e_tcb_free(itrq, tcb_dma[i]);
- }
- kmem_free(tcb_dma, nbufs * sizeof (i40e_tx_control_block_t *));
+
+ tcb = tcbhead;
+ while (tcb != NULL) {
+ i40e_tx_control_block_t *next = tcb->tcb_next;
+
+ ASSERT(tcb->tcb_type == I40E_TX_DMA ||
+ tcb->tcb_type == I40E_TX_COPY);
+
+ tcb->tcb_mp = NULL;
+ i40e_tcb_reset(tcb);
+ i40e_tcb_free(itrq, tcb);
+ tcb = next;
}
mutex_enter(&itrq->itrq_tx_lock);
diff --git a/usr/src/uts/common/io/ib/clients/rds/rdsddi.c b/usr/src/uts/common/io/ib/clients/rds/rdsddi.c
index 35e7a55154..9ed6bdab8c 100644
--- a/usr/src/uts/common/io/ib/clients/rds/rdsddi.c
+++ b/usr/src/uts/common/io/ib/clients/rds/rdsddi.c
@@ -868,7 +868,7 @@ done:
return (error);
}
-static void
+static int
rds_rsrv(queue_t *q)
{
rds_t *rds = (rds_t *)q->q_ptr;
@@ -884,6 +884,7 @@ rds_rsrv(queue_t *q)
/* No more messages in the q, unstall the socket */
rds_transport_ops->rds_transport_resume_port(ntohs(rds->rds_port));
+ return (0);
}
int
@@ -949,11 +950,11 @@ static struct module_info info = {
};
static struct qinit rinit = {
- NULL, (pfi_t)rds_rsrv, rds_open, rds_close, NULL, &info
+ NULL, rds_rsrv, rds_open, rds_close, NULL, &info
};
static struct qinit winit = {
- (pfi_t)rds_wput, NULL, rds_open, rds_close, NULL, &info,
+ rds_wput, NULL, rds_open, rds_close, NULL, &info,
NULL, rds_wrw, NULL, STRUIOT_STANDARD
};
diff --git a/usr/src/uts/common/io/iwscons.c b/usr/src/uts/common/io/iwscons.c
index 615cd61cd2..aeb6660a2a 100644
--- a/usr/src/uts/common/io/iwscons.c
+++ b/usr/src/uts/common/io/iwscons.c
@@ -607,7 +607,7 @@ iwscnattach(dev_info_t *devi, ddi_attach_cmd_t cmd)
ASSERT(iwscn_dip == NULL);
if (ddi_create_minor_node(devi, "iwscn", S_IFCHR,
- 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
+ 0, DDI_PSEUDO, 0) == DDI_FAILURE) {
return (DDI_FAILURE);
}
@@ -655,7 +655,7 @@ struct cb_ops iwscn_cb_ops = {
iwscnioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
- nodev, /* segmap */
+ nodev, /* segmap */
iwscnpoll, /* poll */
ddi_prop_op, /* cb_prop_op */
NULL, /* streamtab */
diff --git a/usr/src/uts/common/io/mac/mac_util.c b/usr/src/uts/common/io/mac/mac_util.c
index 111b323f81..334d1d034b 100644
--- a/usr/src/uts/common/io/mac/mac_util.c
+++ b/usr/src/uts/common/io/mac/mac_util.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -1239,9 +1239,19 @@ mac_hw_emul(mblk_t **mp_chain, mblk_t **otail, uint_t *ocount, mac_emul_t emul)
*/
mac_sw_lso(mp, emul, &tmphead, &tmptail,
&tmpcount);
+ if (tmphead == NULL) {
+ /* mac_sw_lso() freed the mp. */
+ mp = next;
+ continue;
+ }
count += tmpcount;
} else if ((flags & HCK_NEEDED) && (emul & MAC_HWCKSUM_EMULS)) {
tmp = mac_sw_cksum(mp, emul);
+ if (tmp == NULL) {
+ /* mac_sw_cksum() freed the mp. */
+ mp = next;
+ continue;
+ }
tmphead = tmp;
tmptail = tmp;
count++;
diff --git a/usr/src/uts/common/io/mii/mii.c b/usr/src/uts/common/io/mii/mii.c
index b024899783..c2d8e5ad51 100644
--- a/usr/src/uts/common/io/mii/mii.c
+++ b/usr/src/uts/common/io/mii/mii.c
@@ -24,6 +24,10 @@
*/
/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
+/*
* mii - MII/PHY support for MAC drivers
*
* Utility module to provide a consistent interface to a MAC driver accross
@@ -1519,7 +1523,7 @@ debounce:
* gigabit modes cannot use legacy parallel detection.
*/
- if ((ph->phy_type == XCVR_1000T) &
+ if ((ph->phy_type == XCVR_1000T) &&
(anexp & MII_AN_EXP_LPCANAN)) {
/* check for gige */
diff --git a/usr/src/uts/common/io/mr_sas/mr_sas.c b/usr/src/uts/common/io/mr_sas/mr_sas.c
index 41aab85c68..fba65e5e07 100644
--- a/usr/src/uts/common/io/mr_sas/mr_sas.c
+++ b/usr/src/uts/common/io/mr_sas/mr_sas.c
@@ -98,7 +98,7 @@ static void *mrsas_state = NULL;
static volatile boolean_t mrsas_relaxed_ordering = B_TRUE;
volatile int debug_level_g = CL_NONE;
static volatile int msi_enable = 1;
-static volatile int ctio_enable = 1;
+static volatile int ctio_enable = 1;
/* Default Timeout value to issue online controller reset */
volatile int debug_timeout_g = 0xF0; /* 0xB4; */
@@ -143,7 +143,7 @@ static void mrsas_tran_dmafree(struct scsi_address *, struct scsi_pkt *);
static void mrsas_tran_sync_pkt(struct scsi_address *, struct scsi_pkt *);
static int mrsas_tran_quiesce(dev_info_t *dip);
static int mrsas_tran_unquiesce(dev_info_t *dip);
-static uint_t mrsas_isr();
+static uint_t mrsas_isr(caddr_t, caddr_t);
static uint_t mrsas_softintr();
static void mrsas_undo_resources(dev_info_t *, struct mrsas_instance *);
@@ -2289,7 +2289,7 @@ mrsas_tran_unquiesce(dev_info_t *dip)
/*
- * mrsas_isr(caddr_t)
+ * mrsas_isr(caddr_t, caddr_t)
*
* The Interrupt Service Routine
*
@@ -2297,8 +2297,9 @@ mrsas_tran_unquiesce(dev_info_t *dip)
*
*/
static uint_t
-mrsas_isr(struct mrsas_instance *instance)
+mrsas_isr(caddr_t arg1, caddr_t arg2 __unused)
{
+ struct mrsas_instance *instance = (struct mrsas_instance *)arg1;
int need_softintr;
uint32_t producer;
uint32_t consumer;
@@ -7352,8 +7353,7 @@ mrsas_add_intrs(struct mrsas_instance *instance, int intr_type)
/* Call ddi_intr_add_handler() */
for (i = 0; i < actual; i++) {
ret = ddi_intr_add_handler(instance->intr_htable[i],
- (ddi_intr_handler_t *)mrsas_isr, (caddr_t)instance,
- (caddr_t)(uintptr_t)i);
+ mrsas_isr, (caddr_t)instance, (caddr_t)(uintptr_t)i);
if (ret != DDI_SUCCESS) {
con_log(CL_ANN, (CE_WARN, "mrsas_add_intrs:"
diff --git a/usr/src/uts/common/io/nxge/nxge_mac.c b/usr/src/uts/common/io/nxge/nxge_mac.c
index ab325f3443..291272536d 100644
--- a/usr/src/uts/common/io/nxge/nxge_mac.c
+++ b/usr/src/uts/common/io/nxge/nxge_mac.c
@@ -2876,7 +2876,7 @@ fail:
static int
nxge_nlp2020_i2c_read(p_nxge_t nxgep, uint8_t ctrl_port, uint16_t address,
- uint16_t reg, uint8_t *data)
+ uint16_t reg, uint8_t *data)
{
int phy_dev, phy_reg;
uint16_t phy_data = 0;
@@ -3953,7 +3953,7 @@ nxge_tn1010_xcvr_init(p_nxge_t nxgep)
/*
* The following 4 lines actually overwrites what ever the ndd command
* has set. For example, by command
- * ndd -set /dev/nxge1 adv_autoneg_cap n (n = 0 or 1)
+ * ndd -set /dev/nxge1 adv_autoneg_cap n (n = 0 or 1)
* we could set param_arr[param_autoneg].value to n. However, because
* here we assign constants to these parameters, whatever we set with
* the "ndd -set" command will be replaced. So command
@@ -4314,8 +4314,8 @@ nxge_rx_mac_init(p_nxge_t nxgep)
uint8_t portn;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
- uint16_t *addr16p;
- uint16_t addr0, addr1, addr2;
+ uint16_t *addr16p;
+ uint16_t addr0, addr1, addr2;
xmac_rx_config_t xconfig;
bmac_rx_config_t bconfig;
@@ -4505,7 +4505,7 @@ nxge_status_t
nxge_rx_mac_enable(p_nxge_t nxgep)
{
npi_handle_t handle;
- uint8_t portn;
+ uint8_t portn;
npi_status_t rs = NPI_SUCCESS;
nxge_status_t status = NXGE_OK;
@@ -5443,7 +5443,7 @@ fail:
nxge_status_t
nxge_mii_read(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t xcvr_reg,
- uint16_t *value)
+ uint16_t *value)
{
npi_status_t rs = NPI_SUCCESS;
@@ -5482,7 +5482,7 @@ fail:
nxge_status_t
nxge_mii_write(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t xcvr_reg,
- uint16_t value)
+ uint16_t value)
{
npi_status_t rs = NPI_SUCCESS;
@@ -5521,10 +5521,10 @@ fail:
/*
* Perform write to Clause45 serdes / transceiver device
* Arguments:
- * xcvr_portn: The IEEE 802.3 Clause45 PHYAD, it is the same as port
+ * xcvr_portn: The IEEE 802.3 Clause45 PHYAD, it is the same as port
* number if nxge_mdio_write is used for accessing the
* internal LSIL serdes. Otherwise PHYAD is different
- * for different platforms.
+ * for different platforms.
* device: With each PHYAD, the driver can use MDIO to control
* multiple devices inside the PHY, here "device" is an
* MMD (MDIO managable device).
@@ -5534,7 +5534,7 @@ fail:
*/
nxge_status_t
nxge_mdio_read(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t device,
- uint16_t xcvr_reg, uint16_t *value)
+ uint16_t xcvr_reg, uint16_t *value)
{
npi_status_t rs = NPI_SUCCESS;
@@ -5565,7 +5565,7 @@ fail:
nxge_status_t
nxge_mdio_write(p_nxge_t nxgep, uint8_t xcvr_portn, uint8_t device,
- uint16_t xcvr_reg, uint16_t value)
+ uint16_t xcvr_reg, uint16_t value)
{
npi_status_t rs = NPI_SUCCESS;
@@ -5597,7 +5597,7 @@ fail:
nxge_status_t
nxge_mii_check(p_nxge_t nxgep, mii_bmsr_t bmsr, mii_bmsr_t bmsr_ints,
- nxge_link_state_t *link_up)
+ nxge_link_state_t *link_up)
{
p_nxge_param_t param_arr;
p_nxge_stats_t statsp;
@@ -6679,8 +6679,8 @@ nxge_link_monitor(p_nxge_t nxgep, link_mon_enable_t enable)
* argument to the check_link function.
*/
if (nxgep->xcvr.check_link) {
- timerid = timeout(
- (fptrv_t)(nxgep->xcvr.check_link),
+ timerid = timeout((fptrv_t)(uintptr_t)
+ (nxgep->xcvr.check_link),
nxgep,
drv_usectohz(LINK_MONITOR_PERIOD));
MUTEX_ENTER(&nxgep->poll_lock);
@@ -8105,7 +8105,7 @@ nxge_scan_ports_phy(p_nxge_t nxgep, p_nxge_hw_list_t hw_p)
goto error_exit;
}
break;
- case 1: /* Only one clause45 port */
+ case 1: /* Only one clause45 port */
switch (total_phy_fd) { /* Number of clause22 ports */
case 3:
/*
@@ -8465,7 +8465,8 @@ nxge_is_valid_local_mac(ether_addr_st mac_addr)
}
static void
-nxge_bcm5464_link_led_off(p_nxge_t nxgep) {
+nxge_bcm5464_link_led_off(p_nxge_t nxgep)
+{
npi_status_t rs = NPI_SUCCESS;
uint8_t xcvr_portn;
@@ -8635,7 +8636,7 @@ nxge_get_num_of_xaui(uint32_t *port_pma_pmd_dev_id,
*num_xaui = 0;
if ((port_pma_pmd_dev_id[0] == PHY_BCM8704_FAMILY &&
- port_pcs_dev_id[0] == PHY_BCM8704_FAMILY) ||
+ port_pcs_dev_id[0] == PHY_BCM8704_FAMILY) ||
(((port_pma_pmd_dev_id[0] & TN1010_DEV_ID_MASK)
== TN1010_DEV_ID) &&
((port_pcs_dev_id[0] & TN1010_DEV_ID_MASK)
@@ -8748,8 +8749,8 @@ fail:
* Teranetics TN1010 PHY chip supports both 1G and 10G modes, this function
* figures out the speed of the PHY determined by the autonegotiation
* process and sets the following 3 parameters,
- * nxgep->mac.portmode
- * nxgep->statsp->mac_stats.link_speed
+ * nxgep->mac.portmode
+ * nxgep->statsp->mac_stats.link_speed
* nxgep->statsp->mac_stats.xcvr_inuse
*/
static nxge_status_t
diff --git a/usr/src/uts/common/io/ppp/sppp/sppp.c b/usr/src/uts/common/io/ppp/sppp/sppp.c
index 1b12b6406b..4cf02abe2e 100644
--- a/usr/src/uts/common/io/ppp/sppp/sppp.c
+++ b/usr/src/uts/common/io/ppp/sppp/sppp.c
@@ -98,7 +98,7 @@ static void sppp_recv_nondata(queue_t *, mblk_t *, spppstr_t *);
static queue_t *sppp_outpkt(queue_t *, mblk_t **, int, spppstr_t *);
static spppstr_t *sppp_inpkt(queue_t *, mblk_t *, spppstr_t *);
static int sppp_kstat_update(kstat_t *, int);
-static void sppp_release_pkts(sppa_t *, uint16_t);
+static void sppp_release_pkts(sppa_t *, uint16_t);
/*
* sps_list contains the list of active per-stream instance state structures
@@ -697,7 +697,7 @@ sppp_ioctl(struct queue *q, mblk_t *mp)
* Description:
* Upper write-side put procedure. Messages from above arrive here.
*/
-void
+int
sppp_uwput(queue_t *q, mblk_t *mp)
{
queue_t *nextq;
@@ -739,7 +739,7 @@ sppp_uwput(queue_t *q, mblk_t *mp)
}
} else {
(void) sppp_mproto(q, mp, sps);
- return;
+ return (0);
}
break;
case M_DATA:
@@ -762,12 +762,12 @@ sppp_uwput(queue_t *q, mblk_t *mp)
case PPPIO_BLOCKNP:
case PPPIO_UNBLOCKNP:
qwriter(q, mp, sppp_inner_ioctl, PERIM_INNER);
- return;
+ return (0);
case I_LINK:
case I_UNLINK:
case PPPIO_NEWPPA:
qwriter(q, mp, sppp_outer_ioctl, PERIM_OUTER);
- return;
+ return (0);
case PPPIO_NPMODE:
case PPPIO_GIDLE:
case PPPIO_GTYPE:
@@ -779,7 +779,7 @@ sppp_uwput(queue_t *q, mblk_t *mp)
* they're moved off to a separate function.
*/
sppp_ioctl(q, mp);
- return;
+ return (0);
case PPPIO_GETSTAT:
break; /* 32 bit interface gone */
default:
@@ -802,7 +802,7 @@ sppp_uwput(queue_t *q, mblk_t *mp)
error = EAGAIN;
break;
}
- return;
+ return (0);
} else {
ppa->ppa_ioctlsfwd++;
/*
@@ -815,7 +815,7 @@ sppp_uwput(queue_t *q, mblk_t *mp)
mutex_exit(&ppa->ppa_sta_lock);
}
putnext(ppa->ppa_lower_wq, mp);
- return; /* don't ack or nak the request */
+ return (0); /* don't ack or nak the request */
}
/* Failure; send error back upstream. */
miocnak(q, mp, 0, error);
@@ -835,6 +835,7 @@ sppp_uwput(queue_t *q, mblk_t *mp)
freemsg(mp);
break;
}
+ return (0);
}
/*
@@ -851,7 +852,7 @@ sppp_uwput(queue_t *q, mblk_t *mp)
* the write-side queue. Therefore, this procedure gets called when
* the lower write service procedure qenable() the upper write stream queue.
*/
-void
+int
sppp_uwsrv(queue_t *q)
{
spppstr_t *sps;
@@ -900,6 +901,7 @@ sppp_uwsrv(queue_t *q)
putnext(nextq, mp);
}
}
+ return (0);
}
void
@@ -1759,7 +1761,7 @@ sppp_outpkt(queue_t *q, mblk_t **mpp, int msize, spppstr_t *sps)
* the write queue here, this just back-enables all upper write side
* service procedures.
*/
-void
+int
sppp_lwsrv(queue_t *q)
{
sppa_t *ppa;
@@ -1780,6 +1782,7 @@ sppp_lwsrv(queue_t *q)
}
}
rw_exit(&ppa->ppa_sib_lock);
+ return (0);
}
/*
@@ -1799,7 +1802,7 @@ sppp_lwsrv(queue_t *q)
* In this case, the only thing above us is passthru, and we might as well
* discard.
*/
-void
+int
sppp_lrput(queue_t *q, mblk_t *mp)
{
sppa_t *ppa;
@@ -1807,7 +1810,7 @@ sppp_lrput(queue_t *q, mblk_t *mp)
if ((ppa = q->q_ptr) == NULL) {
freemsg(mp);
- return;
+ return (0);
}
sps = ppa->ppa_ctl;
@@ -1819,6 +1822,7 @@ sppp_lrput(queue_t *q, mblk_t *mp)
} else if ((q = sppp_recv(q, &mp, sps)) != NULL) {
putnext(q, mp);
}
+ return (0);
}
/*
@@ -1832,13 +1836,14 @@ sppp_lrput(queue_t *q, mblk_t *mp)
* occurs in order to clean up any packets that came in while we were
* transferring in the lower stream. Otherwise, it's not used.
*/
-void
+int
sppp_lrsrv(queue_t *q)
{
mblk_t *mp;
while ((mp = getq(q)) != NULL)
sppp_lrput(q, mp);
+ return (0);
}
/*
diff --git a/usr/src/uts/common/io/ppp/sppp/sppp.h b/usr/src/uts/common/io/ppp/sppp/sppp.h
index 71911c231e..63108a25e9 100644
--- a/usr/src/uts/common/io/ppp/sppp/sppp.h
+++ b/usr/src/uts/common/io/ppp/sppp/sppp.h
@@ -322,8 +322,8 @@ typedef struct sppa {
spppstr_t *ppa_ip6_cache; /* ptr to PPP_IPV6 upper stream */
kmutex_t ppa_npmutex; /* protects the 2 fields below */
- uint32_t ppa_npflag; /* network protocols blocked */
- uint32_t ppa_holdpkts[3]; /* # of packets blocked per np */
+ uint32_t ppa_npflag; /* network protocols blocked */
+ uint32_t ppa_holdpkts[3]; /* # of packets blocked per np */
zoneid_t ppa_zoneid; /* zone where PPA is in use */
} sppa_t;
@@ -363,13 +363,13 @@ extern int sppp_close(queue_t *, int, cred_t *);
extern mblk_t *sppp_dladdud(spppstr_t *, mblk_t *, t_scalar_t, boolean_t);
extern void sppp_dlpi_pinfoinit(void);
extern void sppp_dlprsendup(spppstr_t *, mblk_t *, t_scalar_t, boolean_t);
-extern void sppp_lrput(queue_t *, mblk_t *);
-extern void sppp_lrsrv(queue_t *);
-extern void sppp_lwsrv(queue_t *);
+extern int sppp_lrput(queue_t *, mblk_t *);
+extern int sppp_lrsrv(queue_t *);
+extern int sppp_lwsrv(queue_t *);
extern int sppp_mproto(queue_t *, mblk_t *, spppstr_t *);
extern int sppp_open(queue_t *, dev_t *, int, int, cred_t *);
-extern void sppp_uwput(queue_t *, mblk_t *);
-extern void sppp_uwsrv(queue_t *);
+extern int sppp_uwput(queue_t *, mblk_t *);
+extern int sppp_uwsrv(queue_t *);
extern void sppp_remove_ppa(spppstr_t *sps);
extern sppa_t *sppp_find_ppa(uint32_t ppa_id);
extern sppa_t *sppp_create_ppa(uint32_t ppa_id, zoneid_t zoneid);
diff --git a/usr/src/uts/common/io/ppp/sppp/sppp_mod.c b/usr/src/uts/common/io/ppp/sppp/sppp_mod.c
index 168cf17f49..6948032309 100644
--- a/usr/src/uts/common/io/ppp/sppp/sppp_mod.c
+++ b/usr/src/uts/common/io/ppp/sppp/sppp_mod.c
@@ -93,8 +93,8 @@ static struct qinit sppp_urinit = {
};
static struct qinit sppp_uwinit = {
- (int (*)())sppp_uwput, /* qi_putp */
- (int (*)())sppp_uwsrv, /* qi_srvp */
+ sppp_uwput, /* qi_putp */
+ sppp_uwsrv, /* qi_srvp */
NULL, /* qi_qopen */
NULL, /* qi_qclose */
NULL, /* qi_qadmin */
@@ -103,8 +103,8 @@ static struct qinit sppp_uwinit = {
};
static struct qinit sppp_lrinit = {
- (int (*)())sppp_lrput, /* qi_putp */
- (int (*)())sppp_lrsrv, /* qi_srvp */
+ sppp_lrput, /* qi_putp */
+ sppp_lrsrv, /* qi_srvp */
NULL, /* qi_qopen */
NULL, /* qi_qclose */
NULL, /* qi_qadmin */
@@ -114,7 +114,7 @@ static struct qinit sppp_lrinit = {
static struct qinit sppp_lwinit = {
NULL, /* qi_putp */
- (int (*)())sppp_lwsrv, /* qi_srvp */
+ sppp_lwsrv, /* qi_srvp */
NULL, /* qi_qopen */
NULL, /* qi_qclose */
NULL, /* qi_qadmin */
@@ -162,10 +162,10 @@ static struct streamtab sppp_tab = {
* the system's stability and performance.
*/
DDI_DEFINE_STREAM_OPS(sppp_ops, \
- nulldev, nulldev, \
- _mi_driver_attach, _mi_driver_detach, nodev, _mi_driver_info, \
- D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL | D_MTPUTSHARED, \
- &sppp_tab, ddi_quiesce_not_supported);
+ nulldev, nulldev, \
+ _mi_driver_attach, _mi_driver_detach, nodev, _mi_driver_info, \
+ D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL | D_MTPUTSHARED, \
+ &sppp_tab, ddi_quiesce_not_supported);
static struct modldrv modldrv = {
&mod_driverops, /* drv_modops */
diff --git a/usr/src/uts/common/io/ptm.c b/usr/src/uts/common/io/ptm.c
index dc6c4e64ad..54bcee88bc 100644
--- a/usr/src/uts/common/io/ptm.c
+++ b/usr/src/uts/common/io/ptm.c
@@ -22,7 +22,7 @@
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
@@ -146,9 +146,9 @@ int ptm_debug = 0;
static int ptmopen(queue_t *, dev_t *, int, int, cred_t *);
static int ptmclose(queue_t *, int, cred_t *);
-static void ptmwput(queue_t *, mblk_t *);
-static void ptmrsrv(queue_t *);
-static void ptmwsrv(queue_t *);
+static int ptmwput(queue_t *, mblk_t *);
+static int ptmrsrv(queue_t *);
+static int ptmwsrv(queue_t *);
/*
* Master Stream Pseudo Terminal Module: stream data structure definitions
@@ -165,7 +165,7 @@ static struct module_info ptm_info = {
static struct qinit ptmrint = {
NULL,
- (int (*)()) ptmrsrv,
+ ptmrsrv,
ptmopen,
ptmclose,
NULL,
@@ -174,8 +174,8 @@ static struct qinit ptmrint = {
};
static struct qinit ptmwint = {
- (int (*)()) ptmwput,
- (int (*)()) ptmwsrv,
+ ptmwput,
+ ptmwsrv,
NULL,
NULL,
NULL,
@@ -462,7 +462,7 @@ ptmptsopencb(ptmptsopencb_arg_t arg)
/*
* The wput procedure will only handle ioctl and flush messages.
*/
-static void
+static int
ptmwput(queue_t *qp, mblk_t *mp)
{
struct pt_ttys *ptmp;
@@ -520,7 +520,7 @@ ptmwput(queue_t *qp, mblk_t *mp)
DBG(("got M_IOCTL but no slave\n"));
miocnak(qp, mp, 0, EINVAL);
PT_EXIT_READ(ptmp);
- return;
+ return (0);
}
(void) putq(qp, mp);
break;
@@ -642,7 +642,7 @@ ptmwput(queue_t *qp, mblk_t *mp)
qreply(qp, mp);
}
PT_EXIT_READ(ptmp);
- return;
+ return (0);
}
DBG(("put msg on master's write queue\n"));
(void) putq(qp, mp);
@@ -650,6 +650,7 @@ ptmwput(queue_t *qp, mblk_t *mp)
}
DBG(("return from ptmwput()\n"));
PT_EXIT_READ(ptmp);
+ return (0);
}
@@ -658,7 +659,7 @@ ptmwput(queue_t *qp, mblk_t *mp)
* slave to send any messages queued on its write side to
* the read side of this master.
*/
-static void
+static int
ptmrsrv(queue_t *qp)
{
struct pt_ttys *ptmp;
@@ -673,6 +674,7 @@ ptmrsrv(queue_t *qp)
}
PT_EXIT_READ(ptmp);
DBG(("leaving ptmrsrv\n"));
+ return (0);
}
@@ -682,11 +684,11 @@ ptmrsrv(queue_t *qp)
* cannot be sent, leave them on this queue. If priority
* messages on this queue, send them to slave no matter what.
*/
-static void
+static int
ptmwsrv(queue_t *qp)
{
struct pt_ttys *ptmp;
- mblk_t *mp;
+ mblk_t *mp;
DBG(("entering ptmwsrv\n"));
ASSERT(qp->q_ptr);
@@ -696,7 +698,7 @@ ptmwsrv(queue_t *qp)
if ((mp = getq(qp)) == NULL) {
/* If there are no messages there's nothing to do. */
DBG(("leaving ptmwsrv (no messages)\n"));
- return;
+ return (0);
}
PT_ENTER_READ(ptmp);
@@ -723,7 +725,7 @@ ptmwsrv(queue_t *qp)
qreply(qp, mp);
}
PT_EXIT_READ(ptmp);
- return;
+ return (0);
}
/*
* while there are messages on this write queue...
@@ -748,4 +750,5 @@ ptmwsrv(queue_t *qp)
} while ((mp = getq(qp)) != NULL);
DBG(("leaving ptmwsrv\n"));
PT_EXIT_READ(ptmp);
+ return (0);
}
diff --git a/usr/src/uts/common/io/pts.c b/usr/src/uts/common/io/pts.c
index 1bcdc2bcef..d67beb255a 100644
--- a/usr/src/uts/common/io/pts.c
+++ b/usr/src/uts/common/io/pts.c
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
@@ -128,9 +128,9 @@ int pts_debug = 0;
static int ptsopen(queue_t *, dev_t *, int, int, cred_t *);
static int ptsclose(queue_t *, int, cred_t *);
-static void ptswput(queue_t *, mblk_t *);
-static void ptsrsrv(queue_t *);
-static void ptswsrv(queue_t *);
+static int ptswput(queue_t *, mblk_t *);
+static int ptsrsrv(queue_t *);
+static int ptswsrv(queue_t *);
/*
* Slave Stream Pseudo Terminal Module: stream data structure definitions
@@ -146,7 +146,7 @@ static struct module_info pts_info = {
static struct qinit ptsrint = {
NULL,
- (int (*)()) ptsrsrv,
+ ptsrsrv,
ptsopen,
ptsclose,
NULL,
@@ -155,8 +155,8 @@ static struct qinit ptsrint = {
};
static struct qinit ptswint = {
- (int (*)()) ptswput,
- (int (*)()) ptswsrv,
+ ptswput,
+ ptswsrv,
NULL,
NULL,
NULL,
@@ -504,7 +504,7 @@ ptsclose(queue_t *rqp, int flag, cred_t *credp)
* All other messages are queued and the write side
* service procedure sends them off to the master side.
*/
-static void
+static int
ptswput(queue_t *qp, mblk_t *mp)
{
struct pt_ttys *ptsp;
@@ -530,7 +530,7 @@ ptswput(queue_t *qp, mblk_t *mp)
} else
freemsg(mp);
PT_EXIT_READ(ptsp);
- return;
+ return (0);
}
if (type >= QPCTL) {
@@ -606,7 +606,7 @@ ptswput(queue_t *qp, mblk_t *mp)
break;
}
PT_EXIT_READ(ptsp);
- return;
+ return (0);
}
switch (type) {
@@ -637,9 +637,9 @@ ptswput(queue_t *qp, mblk_t *mp)
iocp->ioc_count = 0;
qreply(qp, mp);
PT_EXIT_READ(ptsp);
- return;
+ return (0);
}
-
+ /* FALLTHROUGH */
default:
/*
* send other messages to the master
@@ -651,6 +651,7 @@ ptswput(queue_t *qp, mblk_t *mp)
PT_EXIT_READ(ptsp);
DBG(("return from ptswput()\n"));
+ return (0);
}
@@ -659,7 +660,7 @@ ptswput(queue_t *qp, mblk_t *mp)
* master to send any messages queued on its write side to
* the read side of this slave.
*/
-static void
+static int
ptsrsrv(queue_t *qp)
{
struct pt_ttys *ptsp;
@@ -672,11 +673,12 @@ ptsrsrv(queue_t *qp)
if (ptsp->ptm_rdq == NULL) {
DBG(("in read srv proc but no master\n"));
PT_EXIT_READ(ptsp);
- return;
+ return (0);
}
qenable(WR(ptsp->ptm_rdq));
PT_EXIT_READ(ptsp);
DBG(("leaving ptsrsrv\n"));
+ return (0);
}
/*
@@ -685,7 +687,7 @@ ptsrsrv(queue_t *qp)
* cannot be sent, leave them on this queue. If priority
* messages on this queue, send them to master no matter what.
*/
-static void
+static int
ptswsrv(queue_t *qp)
{
struct pt_ttys *ptsp;
@@ -715,7 +717,7 @@ ptswsrv(queue_t *qp)
freemsg(mp);
}
PT_EXIT_READ(ptsp);
- return;
+ return (0);
} else {
ptm_rdq = ptsp->ptm_rdq;
}
@@ -743,4 +745,5 @@ ptswsrv(queue_t *qp)
}
DBG(("leaving ptswsrv\n"));
PT_EXIT_READ(ptsp);
+ return (0);
}
diff --git a/usr/src/uts/common/io/rwn/rt2860.c b/usr/src/uts/common/io/rwn/rt2860.c
index e3df2a765c..5aaeebb4ac 100644
--- a/usr/src/uts/common/io/rwn/rt2860.c
+++ b/usr/src/uts/common/io/rwn/rt2860.c
@@ -2,6 +2,7 @@
* Copyright 2017 Gary Mills
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -900,11 +901,10 @@ rt2860_free_rx_ring(struct rt2860_softc *sc, struct rt2860_rx_ring *ring)
rt2860_free_dma_mem(&ring->rxdesc_dma);
count = RT2860_RX_RING_COUNT;
- if (ring->data != NULL) {
- for (i = 0; i < count; i++) {
- data = &ring->data[i];
- rt2860_free_dma_mem(&data->rxbuf_dma);
- }
+
+ for (i = 0; i < count; i++) {
+ data = &ring->data[i];
+ rt2860_free_dma_mem(&data->rxbuf_dma);
}
}
diff --git a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
index 34172df72c..0e4fb433cf 100644
--- a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
+++ b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
@@ -82,6 +82,7 @@
*/
#include <sys/note.h>
+#include <sys/debug.h>
#include <sys/scsi/scsi.h>
#include <sys/pci.h>
#include <sys/disp.h>
@@ -6169,9 +6170,6 @@ ahci_alloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
ahci_portp->ahciport_event_args->ahciea_addrp =
kmem_zalloc(sizeof (ahci_addr_t), KM_SLEEP);
- if (ahci_portp->ahciport_event_args == NULL)
- goto err_case4;
-
/* Initialize the done queue */
ahci_portp->ahciport_doneq = NULL;
ahci_portp->ahciport_doneqtail = &ahci_portp->ahciport_doneq;
@@ -6181,9 +6179,6 @@ ahci_alloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
return (AHCI_SUCCESS);
-err_case4:
- ddi_taskq_destroy(ahci_portp->ahciport_event_taskq);
-
err_case3:
ahci_dealloc_cmd_list(ahci_ctlp, ahci_portp);
@@ -7932,7 +7927,7 @@ ahci_intr_fatal_error(ahci_ctl_t *ahci_ctlp,
(spkt->satapkt_cmd.satacmd_cmd_reg ==
SATAC_ID_DEVICE) &&
(task_abort_flag == 1))
- goto out1;
+ goto out1;
/*
* Won't emit the error message if it is an ATAPI PACKET
@@ -10845,22 +10840,19 @@ static void
ahci_em_quiesce(ahci_ctl_t *ahci_ctlp)
{
ASSERT(ahci_ctlp->ahcictl_em_flags & AHCI_EM_PRESENT);
+ VERIFY(mutex_owned(&ahci_ctlp->ahcictl_mutex));
- mutex_enter(&ahci_ctlp->ahcictl_mutex);
ahci_ctlp->ahcictl_em_flags |= AHCI_EM_QUIESCE;
- mutex_exit(&ahci_ctlp->ahcictl_mutex);
-
ddi_taskq_wait(ahci_ctlp->ahcictl_em_taskq);
}
static void
ahci_em_suspend(ahci_ctl_t *ahci_ctlp)
{
- ahci_em_quiesce(ahci_ctlp);
+ VERIFY(mutex_owned(&ahci_ctlp->ahcictl_mutex));
- mutex_enter(&ahci_ctlp->ahcictl_mutex);
+ ahci_em_quiesce(ahci_ctlp);
ahci_ctlp->ahcictl_em_flags &= ~AHCI_EM_READY;
- mutex_exit(&ahci_ctlp->ahcictl_mutex);
}
static void
@@ -10881,7 +10873,10 @@ ahci_em_fini(ahci_ctl_t *ahci_ctlp)
return;
}
+ mutex_enter(&ahci_ctlp->ahcictl_mutex);
ahci_em_quiesce(ahci_ctlp);
+ mutex_exit(&ahci_ctlp->ahcictl_mutex);
+
ddi_taskq_destroy(ahci_ctlp->ahcictl_em_taskq);
ahci_ctlp->ahcictl_em_taskq = NULL;
}
diff --git a/usr/src/uts/common/io/scsi/targets/st.c b/usr/src/uts/common/io/scsi/targets/st.c
index ea3283c93c..36768a9bde 100644
--- a/usr/src/uts/common/io/scsi/targets/st.c
+++ b/usr/src/uts/common/io/scsi/targets/st.c
@@ -48,7 +48,7 @@
* stats maintained only for reads/writes as commands
* like rewind etc skew the wait/busy times
*/
-#define IS_RW(bp) ((bp)->b_bcount > 0)
+#define IS_RW(bp) ((bp)->b_bcount > 0)
#define ST_DO_KSTATS(bp, kstat_function) \
if ((bp != un->un_sbufp) && un->un_stats && IS_RW(bp)) { \
kstat_function(IOSP); \
@@ -61,7 +61,7 @@
stp->x.value.ul++; \
}
-#define FILL_SCSI1_LUN(devp, pkt) \
+#define FILL_SCSI1_LUN(devp, pkt) \
if ((devp)->sd_inq->inq_ansi == 0x1) { \
int _lun; \
_lun = ddi_prop_get_int(DDI_DEV_T_ANY, (devp)->sd_dev, \
@@ -85,19 +85,19 @@
struct contig_mem *tmp_cp = NULL; \
for ((cp) = (un)->un_contig_mem; \
(cp) != NULL; \
- tmp_cp = (cp), (cp) = (cp)->cm_next) { \
- if (((cp)->cm_len >= (len)) || \
- (!(big_enough) && ((cp)->cm_next == NULL))) { \
- if (tmp_cp == NULL) { \
- (un)->un_contig_mem = (cp)->cm_next; \
- } else { \
- tmp_cp->cm_next = (cp)->cm_next; \
- } \
- (cp)->cm_next = NULL; \
- (un)->un_contig_mem_available_num--; \
- break; \
- } \
- } \
+ tmp_cp = (cp), (cp) = (cp)->cm_next) { \
+ if (((cp)->cm_len >= (len)) || \
+ (!(big_enough) && ((cp)->cm_next == NULL))) { \
+ if (tmp_cp == NULL) { \
+ (un)->un_contig_mem = (cp)->cm_next; \
+ } else { \
+ tmp_cp->cm_next = (cp)->cm_next; \
+ } \
+ (cp)->cm_next = NULL; \
+ (un)->un_contig_mem_available_num--; \
+ break; \
+ } \
+ } \
}
#define ST_NUM_MEMBERS(array) (sizeof (array) / sizeof (array[0]))
@@ -454,7 +454,7 @@ static struct cb_ops st_cb_ops = {
D_64BIT | D_MP | D_NEW | D_HOTPLUG |
D_OPEN_RETURNS_EINTR, /* cb_flag */
CB_REV, /* cb_rev */
- st_aread, /* async I/O read entry point */
+ st_aread, /* async I/O read entry point */
st_awrite /* async I/O write entry point */
};
@@ -690,7 +690,7 @@ _NOTE(DATA_READABLE_WITHOUT_LOCK(st_drivetype scsi_address))
static struct modldrv modldrv = {
&mod_driverops, /* Type of module. This one is a driver */
- "SCSI tape Driver", /* Name of the module. */
+ "SCSI tape Driver", /* Name of the module. */
&st_ops /* driver ops */
};
@@ -863,9 +863,9 @@ st_probe(dev_info_t *devi)
static int
st_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
- int instance;
+ int instance;
int wide;
- int dev_instance;
+ int dev_instance;
int ret_status;
struct scsi_device *devp;
int node_ix;
@@ -3433,7 +3433,7 @@ st_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
(flag & FREAD) && /* reading or at least asked to */
(un->un_mediastate == MTIO_INSERTED) && /* tape loaded */
(un->un_pos.pmode != invalid) && /* XXX position known */
- ((un->un_pos.blkno != 0) && /* inside a file */
+ ((un->un_pos.blkno != 0) && /* inside a file */
(un->un_lastop != ST_OP_WRITE) && /* Didn't just write */
(un->un_lastop != ST_OP_WEOF))) { /* or write filemarks */
switch (un->un_pos.eof) {
@@ -4968,7 +4968,7 @@ check_commands:
* 64 bit ioctl
*/
struct mtget32 mtg_local32;
- struct mtget32 *mtget_32 = &mtg_local32;
+ struct mtget32 *mtget_32 = &mtg_local32;
#endif /* _MULTI_DATAMODEL */
/* Get tape status */
@@ -5073,14 +5073,14 @@ check_commands:
* Convert 64 bit back to 32 bit before doing
* copyout. This is what the ILP32 app expects.
*/
- mtget_32->mt_erreg = mtget->mt_erreg;
- mtget_32->mt_resid = mtget->mt_resid;
- mtget_32->mt_dsreg = mtget->mt_dsreg;
- mtget_32->mt_fileno = (daddr32_t)mtget->mt_fileno;
- mtget_32->mt_blkno = (daddr32_t)mtget->mt_blkno;
- mtget_32->mt_type = mtget->mt_type;
- mtget_32->mt_flags = mtget->mt_flags;
- mtget_32->mt_bf = mtget->mt_bf;
+ mtget_32->mt_erreg = mtget->mt_erreg;
+ mtget_32->mt_resid = mtget->mt_resid;
+ mtget_32->mt_dsreg = mtget->mt_dsreg;
+ mtget_32->mt_fileno = (daddr32_t)mtget->mt_fileno;
+ mtget_32->mt_blkno = (daddr32_t)mtget->mt_blkno;
+ mtget_32->mt_type = mtget->mt_type;
+ mtget_32->mt_flags = mtget->mt_flags;
+ mtget_32->mt_bf = mtget->mt_bf;
if (ddi_copyout(mtget_32, (void *)arg,
sizeof (struct mtget32), flag)) {
@@ -6490,7 +6490,7 @@ st_start(struct scsi_tape *un)
un->un_throttle, un->un_ncmds);
if (un->un_ncmds == 0) {
typedef void (*func)();
- func fnc = (func)st_runout;
+ func fnc = (func)(uintptr_t)st_runout;
scsi_log(ST_DEVINFO, st_label, SCSI_DEBUG,
"Sending delayed start to st_runout()\n");
@@ -10120,7 +10120,7 @@ reset_target:
*/
static int
st_handle_intr_busy(struct scsi_tape *un, struct buf *bp,
- clock_t timeout_interval)
+ clock_t timeout_interval)
{
int queued;
@@ -10394,9 +10394,8 @@ ret:
*/
static void
-st_update_error_stack(struct scsi_tape *un,
- struct scsi_pkt *pkt,
- struct scsi_arq_status *cmd)
+st_update_error_stack(struct scsi_tape *un, struct scsi_pkt *pkt,
+ struct scsi_arq_status *cmd)
{
struct mterror_entry_stack *err_entry_tmp;
uchar_t *cdbp = (uchar_t *)pkt->pkt_cdbp;
@@ -12311,7 +12310,7 @@ st_clean_print(dev_info_t *dev, char *label, uint_t level,
char *title, char *data, int len)
{
int i;
- int c;
+ int c;
char *format;
char buf[256];
uchar_t byte;
@@ -13775,9 +13774,9 @@ st_check_sense_clean_bit(struct scsi_tape *un)
/*
* st_clear_unit_attention
*
- * run test unit ready's to clear out outstanding
- * unit attentions.
- * returns zero for SUCCESS or the errno from st_cmd call
+ * run test unit ready's to clear out outstanding
+ * unit attentions.
+ * returns zero for SUCCESS or the errno from st_cmd call
*/
static int
st_clear_unit_attentions(dev_t dev_instance, int max_trys)
@@ -16369,7 +16368,7 @@ static const char *mode[] = {
static void
st_print_position(dev_info_t *dev, char *label, uint_t level,
-const char *comment, tapepos_t *pos)
+ const char *comment, tapepos_t *pos)
{
ST_FUNC(dev, st_print_position);
diff --git a/usr/src/uts/common/io/softmac/softmac_dev.c b/usr/src/uts/common/io/softmac/softmac_dev.c
index bbb3e9ad3e..3b9c76a7e2 100644
--- a/usr/src/uts/common/io/softmac/softmac_dev.c
+++ b/usr/src/uts/common/io/softmac/softmac_dev.c
@@ -45,9 +45,9 @@ static int softmac_cmn_open(queue_t *, dev_t *, int, int, cred_t *);
* the softmac module.
*/
static int softmac_mod_close(queue_t *, int, cred_t *);
-static void softmac_mod_rput(queue_t *, mblk_t *);
-static void softmac_mod_wput(queue_t *, mblk_t *);
-static void softmac_mod_wsrv(queue_t *);
+static int softmac_mod_rput(queue_t *, mblk_t *);
+static int softmac_mod_wput(queue_t *, mblk_t *);
+static int softmac_mod_wsrv(queue_t *);
/*
* The following softmac_drv_xxx() functions are (9E) entry point functions for
@@ -55,8 +55,8 @@ static void softmac_mod_wsrv(queue_t *);
*/
static int softmac_drv_open(queue_t *, dev_t *, int, int, cred_t *);
static int softmac_drv_close(queue_t *, int, cred_t *);
-static void softmac_drv_wput(queue_t *, mblk_t *);
-static void softmac_drv_wsrv(queue_t *);
+static int softmac_drv_wput(queue_t *, mblk_t *);
+static int softmac_drv_wsrv(queue_t *);
static int softmac_attach(dev_info_t *, ddi_attach_cmd_t);
static int softmac_detach(dev_info_t *, ddi_detach_cmd_t);
@@ -85,8 +85,8 @@ static struct module_info softmac_dld_modinfo = {
};
static struct qinit softmac_urinit = {
- (pfi_t)softmac_mod_rput, /* qi_putp */
- (pfi_t)NULL, /* qi_srvp */
+ softmac_mod_rput, /* qi_putp */
+ NULL, /* qi_srvp */
softmac_cmn_open, /* qi_qopen */
softmac_mod_close, /* qi_qclose */
NULL, /* qi_qadmin */
@@ -94,8 +94,8 @@ static struct qinit softmac_urinit = {
};
static struct qinit softmac_uwinit = {
- (pfi_t)softmac_mod_wput, /* qi_putp */
- (pfi_t)softmac_mod_wsrv, /* qi_srvp */
+ softmac_mod_wput, /* qi_putp */
+ softmac_mod_wsrv, /* qi_srvp */
NULL, /* qi_qopen */
NULL, /* qi_qclose */
NULL, /* qi_qadmin */
@@ -117,7 +117,7 @@ static struct qinit softmac_dld_r_qinit = {
};
static struct qinit softmac_dld_w_qinit = {
- (pfi_t)softmac_drv_wput, (pfi_t)softmac_drv_wsrv, NULL, NULL, NULL,
+ softmac_drv_wput, softmac_drv_wsrv, NULL, NULL, NULL,
&softmac_dld_modinfo
};
@@ -304,7 +304,7 @@ softmac_mod_close(queue_t *rq, int flags __unused, cred_t *credp __unused)
return (0);
}
-static void
+static int
softmac_mod_rput(queue_t *rq, mblk_t *mp)
{
softmac_lower_t *slp = rq->q_ptr;
@@ -336,7 +336,7 @@ softmac_mod_rput(queue_t *rq, mblk_t *mp)
*/
if (slp->sl_softmac == NULL) {
freemsg(mp);
- return;
+ return (0);
}
/*
@@ -346,7 +346,7 @@ softmac_mod_rput(queue_t *rq, mblk_t *mp)
*/
if (mp->b_flag & MSGNOLOOP) {
freemsg(mp);
- return;
+ return (0);
}
/*
@@ -355,7 +355,7 @@ softmac_mod_rput(queue_t *rq, mblk_t *mp)
if (DB_REF(mp) == 1) {
ASSERT(slp->sl_softmac != NULL);
mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
- return;
+ return (0);
} else {
softmac_rput_process_data(slp, mp);
}
@@ -386,9 +386,10 @@ softmac_mod_rput(queue_t *rq, mblk_t *mp)
softmac_rput_process_notdata(rq, slp->sl_sup, mp);
break;
}
+ return (0);
}
-static void
+static int
softmac_mod_wput(queue_t *wq, mblk_t *mp)
{
/*
@@ -430,9 +431,10 @@ softmac_mod_wput(queue_t *wq, mblk_t *mp)
freemsg(mp);
break;
}
+ return (0);
}
-static void
+static int
softmac_mod_wsrv(queue_t *wq)
{
softmac_lower_t *slp = wq->q_ptr;
@@ -450,6 +452,7 @@ softmac_mod_wsrv(queue_t *wq)
qenable(slp->sl_sup->su_wq);
else if (slp->sl_softmac != NULL)
mac_tx_update(slp->sl_softmac->smac_mh);
+ return (0);
}
static int
@@ -609,7 +612,7 @@ softmac_drv_close(queue_t *rq, int flags __unused, cred_t *credp __unused)
return (dld_str_close(rq));
}
-static void
+static int
softmac_drv_wput(queue_t *wq, mblk_t *mp)
{
softmac_upper_t *sup = dld_str_private(wq);
@@ -627,13 +630,13 @@ softmac_drv_wput(queue_t *wq, mblk_t *mp)
if (MBLKL(mp) < sizeof (t_uscalar_t)) {
freemsg(mp);
- return;
+ return (0);
}
prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
if (prim == DL_UNITDATA_REQ) {
softmac_wput_data(sup, mp);
- return;
+ return (0);
}
softmac_wput_nondata(sup, mp);
@@ -642,9 +645,10 @@ softmac_drv_wput(queue_t *wq, mblk_t *mp)
softmac_wput_nondata(sup, mp);
break;
}
+ return (0);
}
-static void
+static int
softmac_drv_wsrv(queue_t *wq)
{
softmac_upper_t *sup = dld_str_private(wq);
@@ -684,4 +688,5 @@ softmac_drv_wsrv(queue_t *wq)
sup->su_tx_busy = B_FALSE;
}
mutex_exit(&sup->su_mutex);
+ return (0);
}
diff --git a/usr/src/uts/common/io/tem.c b/usr/src/uts/common/io/tem.c
index eeda8f375f..b00908c683 100644
--- a/usr/src/uts/common/io/tem.c
+++ b/usr/src/uts/common/io/tem.c
@@ -376,7 +376,7 @@ tems_failed(cred_t *credp, boolean_t finish_ioctl)
(void) ldi_ioctl(tems.ts_hdl, VIS_DEVFINI, 0,
FWRITE|FKIOCTL, credp, &lyr_rval);
- (void) ldi_close(tems.ts_hdl, NULL, credp);
+ (void) ldi_close(tems.ts_hdl, 0, credp);
tems.ts_hdl = NULL;
return (ENXIO);
}
diff --git a/usr/src/uts/common/io/tty_pts.c b/usr/src/uts/common/io/tty_pts.c
index 1ea7fed353..57f7a22978 100644
--- a/usr/src/uts/common/io/tty_pts.c
+++ b/usr/src/uts/common/io/tty_pts.c
@@ -76,7 +76,7 @@ static int ptslrserv(queue_t *);
* from this function, it is defined as void here. Kind of icky, but...
*/
-static void ptslwput(queue_t *q, mblk_t *mp);
+static int ptslwput(queue_t *q, mblk_t *mp);
static struct module_info ptslm_info = {
0,
@@ -98,7 +98,7 @@ static struct qinit ptslrinit = {
};
static struct qinit ptslwinit = {
- (int (*)())ptslwput,
+ ptslwput,
NULL,
NULL,
NULL,
@@ -384,7 +384,7 @@ ptslclose(queue_t *q, int flag, cred_t *cred)
* queue up M_DATA messages for processing by the controller "read"
* routine; discard everything else.
*/
-static void
+static int
ptslwput(queue_t *q, mblk_t *mp)
{
struct pty *pty;
@@ -449,7 +449,7 @@ ptslwput(queue_t *q, mblk_t *mp)
flushq(RD(q), FLUSHDATA);
mutex_exit(&pty->ptc_lock);
qreply(q, mp); /* give the read queues a crack at it */
- return;
+ return (0);
} else
freemsg(mp);
break;
@@ -466,7 +466,8 @@ ptslwput(queue_t *q, mblk_t *mp)
freeb(bp);
if (mp == NULL) {
mutex_exit(&pty->ptc_lock);
- return; /* damp squib of a message */
+ /* damp squib of a message */
+ return (0);
}
bp = mp;
}
@@ -499,6 +500,7 @@ ptslwput(queue_t *q, mblk_t *mp)
break;
}
mutex_exit(&pty->ptc_lock);
+ return (0);
}
/*
diff --git a/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c b/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c
index 1fa790d4e9..0242c3782a 100644
--- a/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c
+++ b/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c
@@ -83,8 +83,8 @@ static int usbkbm_get_vid_pid(usbkbm_state_t *);
/* stream qinit functions defined here */
static int usbkbm_open(queue_t *, dev_t *, int, int, cred_t *);
static int usbkbm_close(queue_t *, int, cred_t *);
-static void usbkbm_wput(queue_t *, mblk_t *);
-static void usbkbm_rput(queue_t *, mblk_t *);
+static int usbkbm_wput(queue_t *, mblk_t *);
+static int usbkbm_rput(queue_t *, mblk_t *);
static ushort_t usbkbm_get_state(usbkbm_state_t *);
static void usbkbm_get_scancode(usbkbm_state_t *, int *, enum keystate *);
@@ -345,21 +345,21 @@ static struct module_info usbkbm_minfo = {
/* read side for key data and ioctl replies */
static struct qinit usbkbm_rinit = {
- (int (*)())usbkbm_rput,
- (int (*)())NULL, /* service not used */
+ usbkbm_rput,
+ NULL, /* service not used */
usbkbm_open,
usbkbm_close,
- (int (*)())NULL,
+ NULL,
&usbkbm_minfo
};
/* write side for ioctls */
static struct qinit usbkbm_winit = {
- (int (*)())usbkbm_wput,
- (int (*)())NULL,
+ usbkbm_wput,
+ NULL,
usbkbm_open,
usbkbm_close,
- (int (*)())NULL,
+ NULL,
&usbkbm_minfo
};
@@ -620,7 +620,7 @@ usbkbm_close(register queue_t *q, int flag, cred_t *crp)
* usb keyboard module output queue put procedure: handles M_IOCTL
* messages.
*/
-static void
+static int
usbkbm_wput(register queue_t *q, register mblk_t *mp)
{
usbkbm_state_t *usbkbmd;
@@ -639,7 +639,7 @@ usbkbm_wput(register queue_t *q, register mblk_t *mp)
USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
"usbkbm_wput exiting:2");
- return;
+ return (0);
}
/* kbtrans didn't handle the message. Try to handle it here */
@@ -665,7 +665,7 @@ usbkbm_wput(register queue_t *q, register mblk_t *mp)
USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
"usbkbm_wput exiting:1");
- return;
+ return (0);
}
default:
break;
@@ -679,6 +679,7 @@ usbkbm_wput(register queue_t *q, register mblk_t *mp)
USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
"usbkbm_wput exiting:3");
+ return (0);
}
/*
@@ -946,7 +947,7 @@ allocfailure:
*/
static int
usbkbm_kioccmd(usbkbm_state_t *usbkbmd, register mblk_t *mp,
- char command, size_t *ioctlrepsize)
+ char command, size_t *ioctlrepsize)
{
register mblk_t *datap;
register struct iocblk *iocp;
@@ -1026,7 +1027,7 @@ usbkbm_kioccmd(usbkbm_state_t *usbkbmd, register mblk_t *mp,
* usbkbm_rput :
* Put procedure for input from driver end of stream (read queue).
*/
-static void
+static int
usbkbm_rput(register queue_t *q, register mblk_t *mp)
{
usbkbm_state_t *usbkbmd;
@@ -1039,7 +1040,7 @@ usbkbm_rput(register queue_t *q, register mblk_t *mp)
if (usbkbmd == 0) {
freemsg(mp); /* nobody's listening */
- return;
+ return (0);
}
switch (mp->b_datap->db_type) {
@@ -1052,7 +1053,7 @@ usbkbm_rput(register queue_t *q, register mblk_t *mp)
freemsg(mp);
- return;
+ return (0);
case M_BREAK:
/*
* Will get M_BREAK only if this is not the system
@@ -1061,19 +1062,19 @@ usbkbm_rput(register queue_t *q, register mblk_t *mp)
*/
freemsg(mp);
- return;
+ return (0);
case M_DATA:
if (!(usbkbmd->usbkbm_flags & USBKBM_OPEN)) {
freemsg(mp); /* not ready to listen */
- return;
+ return (0);
}
break;
case M_CTL:
usbkbm_mctl_receive(q, mp);
- return;
+ return (0);
case M_ERROR:
usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
if (*mp->b_rptr == ENODEV) {
@@ -1082,16 +1083,16 @@ usbkbm_rput(register queue_t *q, register mblk_t *mp)
freemsg(mp);
}
- return;
+ return (0);
case M_IOCACK:
case M_IOCNAK:
putnext(q, mp);
- return;
+ return (0);
default:
putnext(q, mp);
- return;
+ return (0);
}
/*
@@ -1106,7 +1107,7 @@ usbkbm_rput(register queue_t *q, register mblk_t *mp)
usbkbmd->usbkbm_report_format.keyid) {
freemsg(mp);
- return;
+ return (0);
} else {
/* We skip the report id prefix */
mp->b_rptr++;
@@ -1117,6 +1118,7 @@ usbkbm_rput(register queue_t *q, register mblk_t *mp)
}
freemsg(mp);
+ return (0);
}
/*
@@ -1346,7 +1348,7 @@ usbkbm_streams_setled(struct kbtrans_hardware *kbtrans_hw, int state)
*/
static boolean_t
usbkbm_polled_keycheck(struct kbtrans_hardware *hw,
- int *key, enum keystate *state)
+ int *key, enum keystate *state)
{
usbkbm_state_t *usbkbmd;
uchar_t *buffer;
@@ -1674,7 +1676,7 @@ usbkbm_polled_exit(cons_polledio_arg_t arg)
*/
static void
usbkbm_unpack_usb_packet(usbkbm_state_t *usbkbmd, process_key_callback_t func,
- uchar_t *usbpacket)
+ uchar_t *usbpacket)
{
uchar_t mkb;
uchar_t lastmkb;
diff --git a/usr/src/uts/common/io/usb/clients/usbser/usbftdi/uftdi_dsd.c b/usr/src/uts/common/io/usb/clients/usbser/usbftdi/uftdi_dsd.c
index 670926b6a2..50aae77e95 100644
--- a/usr/src/uts/common/io/usb/clients/usbser/usbftdi/uftdi_dsd.c
+++ b/usr/src/uts/common/io/usb/clients/usbser/usbftdi/uftdi_dsd.c
@@ -290,7 +290,7 @@ uftdi_attach(ds_attach_info_t *aip)
break;
case USB_VENDOR_MARVELL:
switch (dd->idProduct) {
- case USB_PRODUCT_MARVELL_SHEEVAPLUG_JTAG:
+ case USB_PRODUCT_MARVELL_SHEEVAPLUG:
break;
default:
recognized = B_FALSE;
diff --git a/usr/src/uts/common/io/usb/usbdevs b/usr/src/uts/common/io/usb/usbdevs
index ba22bd81e2..882e5168aa 100644
--- a/usr/src/uts/common/io/usb/usbdevs
+++ b/usr/src/uts/common/io/usb/usbdevs
@@ -1,36 +1,7 @@
-SRC/uts/common/io/usb/usbdevs
-
-/* $FreeBSD: usbdevs,v 1.383 2008/11/12 13:58:59 keramida Exp $ */
-
+$FreeBSD: head/sys/dev/usb/usbdevs 344959 2019-03-09 03:15:09Z bz $
/* $NetBSD: usbdevs,v 1.392 2004/12/29 08:38:44 imp Exp $ */
-/*
- * 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 (c) 1998-2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
@@ -46,13 +17,6 @@ SRC/uts/common/io/usb/usbdevs
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -70,10 +34,17 @@ SRC/uts/common/io/usb/usbdevs
/*
* List of known USB vendors
*
+ * USB.org publishes a VID list of USB-IF member companies at
+ * http://www.usb.org/developers/tools
+ * Note that it does not show companies that have obtained a Vendor ID
+ * without becoming full members.
+ *
* Please note that these IDs do not do anything. Adding an ID here and
- * regenerating usbdevs.h only makes a symbolic name
+ * regenerating the usbdevs.h and usbdevs_data.h only makes a symbolic name
* available to the source code and does not change any functionality, nor
* does it make your device available to a specific driver.
+ * It will however make the descriptive string available if a device does not
+ * provide the string itself.
*
* After adding a vendor ID VNDR and a product ID PRDCT you will have the
* following extra defines:
@@ -82,15 +53,14 @@ SRC/uts/common/io/usb/usbdevs
*
* You may have to add these defines to the respective probe routines to
* make the device recognised by the appropriate device driver.
- *
- * You may have to add these definitions to the driver aliases mechanism
- * for the device to be discovered by the driver.
*/
vendor UNKNOWN1 0x0053 Unknown vendor
vendor UNKNOWN2 0x0105 Unknown vendor
vendor EGALAX2 0x0123 eGalax, Inc.
+vendor CHIPSBANK 0x0204 Chipsbank Microelectronics Co.
vendor HUMAX 0x02ad HUMAX
+vendor QUAN 0x01e1 Quan
vendor LTS 0x0386 LTS
vendor BWCT 0x03da Bernd Walter Computer Technology
vendor AOX 0x03e8 AOX
@@ -122,7 +92,7 @@ vendor FUJITSU2 0x0407 Fujitsu Personal Systems
vendor QUANTA 0x0408 Quanta
vendor NEC 0x0409 NEC
vendor KODAK 0x040a Eastman Kodak
-vendor WELTREND 0x040b Weltrend
+vendor WELTREND 0x040b Weltrend Semiconductor
vendor VIA 0x040d VIA
vendor MCCI 0x040e MCCI
vendor MELCO 0x0411 Melco
@@ -133,7 +103,7 @@ vendor CREATIVE 0x041e Creative Labs
vendor NOKIA 0x0421 Nokia
vendor ADI 0x0422 ADI Systems
vendor CATC 0x0423 Computer Access Technology
-vendor SMC2 0x0424 Standard Microsystems
+vendor SMC2 0x0424 Microchip (Standard Microsystems)
vendor MOTOROLA_HK 0x0425 Motorola HK
vendor GRAVIS 0x0428 Advanced Gravis Computer
vendor CIRRUSLOGIC 0x0429 Cirrus Logic
@@ -165,17 +135,19 @@ vendor MEGATRENDS 0x046b American Megatrends
vendor LOGITECH 0x046d Logitech
vendor BTC 0x046e Behavior Tech. Computer
vendor PHILIPS 0x0471 Philips
-vendor SUN2 0x0472 Sun Microsystems (offical)
+vendor SUN2 0x0472 Sun Microsystems (official)
vendor SANYO 0x0474 Sanyo Electric
vendor SEAGATE 0x0477 Seagate
vendor CONNECTIX 0x0478 Connectix
vendor SEMTECH 0x047a Semtech
+vendor DELL2 0x047c Dell
vendor KENSINGTON 0x047d Kensington
vendor LUCENT 0x047e Lucent
vendor PLANTRONICS 0x047f Plantronics
vendor KYOCERA 0x0482 Kyocera Wireless Corp.
vendor STMICRO 0x0483 STMicroelectronics
-vendor FOXCONN 0x0489 Foxconn
+vendor FOXCONN 0x0489 Foxconn / Hon Hai
+vendor MEIZU 0x0492 Meizu Electronics
vendor YAMAHA 0x0499 YAMAHA
vendor COMPAQ 0x049f Compaq
vendor HITACHI 0x04a4 Hitachi
@@ -226,11 +198,11 @@ vendor TOKYOELECTRON 0x04ec Tokyo Electron
vendor ANNABOOKS 0x04ed Annabooks
vendor JVC 0x04f1 JVC
vendor CHICONY 0x04f2 Chicony Electronics
-vendor ELAN 0x04f3 Elan
+vendor ELAN 0x04f3 ELAN Microelectronics
vendor NEWNEX 0x04f7 Newnex
vendor BROTHER 0x04f9 Brother Industries
vendor DALLAS 0x04fa Dallas Semiconductor
-vendor SUNPLUS 0x04fc Sunplus
+vendor AIPTEK2 0x04fc AIPTEK International
vendor PFU 0x04fe PFU
vendor FUJIKURA 0x0501 Fujikura/DDK
vendor ACER 0x0502 Acer
@@ -283,6 +255,7 @@ vendor HAUPPAUGE 0x0573 Hauppauge Computer Works
vendor BAFO 0x0576 BAFO/Quality Computer Accessories
vendor YEDATA 0x057b Y-E Data
vendor AVM 0x057c AVM
+vendor NINTENDO 0x057e Nintendo
vendor QUICKSHOT 0x057f Quickshot
vendor ROLAND 0x0582 Roland
vendor ROCKFIRE 0x0583 Rockfire
@@ -301,6 +274,7 @@ vendor LACIE 0x059f LaCie
vendor FUJIFILM 0x05a2 Fuji Film
vendor ARC 0x05a3 ARC
vendor ORTEK 0x05a4 Ortek
+vendor CISCOLINKSYS3 0x05a6 Cisco-Linksys
vendor BOSE 0x05a7 Bose
vendor OMNIVISION 0x05a9 OmniVision
vendor INSYSTEM 0x05ab In-System Design
@@ -339,6 +313,7 @@ vendor AOC 0x05f6 AOC International
vendor CHIC 0x05fe Chic Technology
vendor BARCO 0x0600 Barco Display Systems
vendor BRIDGE 0x0607 Bridge Information
+vendor SMK 0x0609 SMK
vendor SOLIDYEAR 0x060b Solid Year
vendor BIORAD 0x0614 Bio-Rad Laboratories
vendor MACALLY 0x0618 Macally
@@ -346,12 +321,16 @@ vendor ACTLABS 0x061c Act Labs
vendor ALARIS 0x0620 Alaris
vendor APEX 0x0624 Apex
vendor CREATIVE3 0x062a Creative Labs
+vendor MICRON 0x0634 Micron Technology
vendor VIVITAR 0x0636 Vivitar
vendor GUNZE 0x0637 Gunze Electronics USA
vendor AVISION 0x0638 Avision
vendor TEAC 0x0644 TEAC
+vendor ACTON 0x0647 Acton Research Corp.
+vendor OPTO 0x065a Optoelectronics Co., Ltd
vendor SGI 0x065e Silicon Graphics
vendor SANWASUPPLY 0x0663 Sanwa Supply
+vendor MEGATEC 0x0665 Megatec
vendor LINKSYS 0x066b Linksys
vendor ACERSA 0x066e Acer Semiconductor America
vendor SIGMATEL 0x066f Sigmatel
@@ -372,8 +351,11 @@ vendor ALCATELT 0x06b9 Alcatel Telecom
vendor AGFA 0x06bd AGFA-Gevaert
vendor ASIAMD 0x06be Asia Microelectronic Development
vendor BIZLINK 0x06c4 Bizlink International
+vendor SYNAPTICS 0x06cb Synaptics, Inc.
vendor KEYSPAN 0x06cd Keyspan / InnoSys Inc.
+vendor CONTEC 0x06ce Contec products
vendor AASHIMA 0x06d6 Aashima Technology
+vendor LIEBERT 0x06da Liebert
vendor MULTITECH 0x06e0 MultiTech
vendor ADS 0x06e1 ADS Technologies
vendor ALCATELM 0x06e4 Alcatel Microelectronics
@@ -384,19 +366,23 @@ vendor SMC 0x0707 Standard Microsystems
vendor PUTERCOM 0x0708 Putercom
vendor MCT 0x0711 MCT
vendor IMATION 0x0718 Imation
+vendor TECLAST 0x071b Teclast
vendor SONYERICSSON 0x0731 Sony Ericsson
vendor EICON 0x0734 Eicon Networks
+vendor MADCATZ 0x0738 Mad Catz, Inc.
vendor SYNTECH 0x0745 Syntech Information
vendor DIGITALSTREAM 0x074e Digital Stream
vendor AUREAL 0x0755 Aureal Semiconductor
-vendor MIDIMAN 0x0763 Midiman
+vendor MAUDIO 0x0763 M-Audio
vendor CYBERPOWER 0x0764 Cyber Power Systems, Inc.
vendor SURECOM 0x0769 Surecom Technology
+vendor HIDGLOBAL 0x076b HID Global
vendor LINKSYS2 0x077b Linksys
vendor GRIFFIN 0x077d Griffin Technology
vendor SANDISK 0x0781 SanDisk
vendor JENOPTIK 0x0784 Jenoptik
vendor LOGITEC 0x0789 Logitec
+vendor NOKIA2 0x078b Nokia
vendor BRIMAX 0x078e Brimax
vendor AXIS 0x0792 Axis Communications
vendor ABL 0x0794 ABL Electronics
@@ -413,6 +399,7 @@ vendor MICROTECH 0x07af Microtech
vendor GENERALINSTMNTS 0x07b2 General Instruments (Motorola)
vendor OLYMPUS 0x07b4 Olympus
vendor ABOCOM 0x07b8 AboCom Systems
+vendor KINGSUN 0x07c0 KingSun
vendor KEISOKUGIKEN 0x07c1 Keisokugiken
vendor ONSPEC 0x07c4 OnSpec
vendor APG 0x07c5 APG Cash Drawer
@@ -426,9 +413,14 @@ vendor APTIO 0x07d2 Aptio Products
vendor ARASAN 0x07da Arasan Chip Systems
vendor ALLIEDCABLE 0x07e6 Allied Cable
vendor STSN 0x07ef STSN
+vendor BEWAN 0x07fa Bewan
vendor CENTURY 0x07f7 Century Corp
+vendor NEWLINK 0x07ff NEWlink
+vendor MAGTEK 0x0801 Mag-Tek
vendor ZOOM 0x0803 Zoom Telephonics
vendor PCS 0x0810 Personal Communication Systems
+vendor SYNET 0x0812 Synet Electronics
+vendor ALPHASMART 0x081e AlphaSmart, Inc.
vendor BROADLOGIC 0x0827 BroadLogic
vendor HANDSPRING 0x082d Handspring
vendor PALM 0x0830 Palm Computing
@@ -454,9 +446,12 @@ vendor BURRBROWN 0x08bb Burr-Brown Japan
vendor 2WIRE 0x08c8 2Wire
vendor AIPTEK 0x08ca AIPTEK International
vendor SMARTBRIDGES 0x08d1 SmartBridges
+vendor FUJITSUSIEMENS 0x08d4 Fujitsu-Siemens
vendor BILLIONTON 0x08dd Billionton Systems
+vendor GEMALTO 0x08e6 Gemalto SA
vendor EXTENDED 0x08e9 Extended Systems
vendor MSYSTEMS 0x08ec M-Systems
+vendor DIGIANSWER 0x08fd Digianswer
vendor AUTHENTEC 0x08ff AuthenTec
vendor AUDIOTECHNICA 0x0909 Audio-Technica
vendor TRUMPION 0x090a Trumpion Microelectronics
@@ -466,6 +461,7 @@ vendor GLOBESPAN 0x0915 Globespan
vendor CONCORDCAMERA 0x0919 Concord Camera
vendor GARMIN 0x091e Garmin International
vendor GOHUBS 0x0921 GoHubs
+vendor DYMO 0x0922 DYMO
vendor XEROX 0x0924 Xerox
vendor BIOMETRIC 0x0929 American Biometric Company
vendor TOSHIBA 0x0930 Toshiba
@@ -473,6 +469,7 @@ vendor PLEXTOR 0x093b Plextor
vendor INTREPIDCS 0x093c Intrepid
vendor YANO 0x094f Yano
vendor KINGSTON 0x0951 Kingston Technology
+vendor NVIDIA 0x0955 NVIDIA Corporation
vendor BLUEWATER 0x0956 BlueWater Systems
vendor AGILENT 0x0957 Agilent Technologies
vendor GUDE 0x0959 Gude ADS
@@ -481,8 +478,10 @@ vendor ACERW 0x0967 Acer
vendor ADIRONDACK 0x0976 Adirondack Wire & Cable
vendor BECKHOFF 0x0978 Beckhoff
vendor MINDSATWORK 0x097a Minds At Work
+vendor ZIPPY 0x099a Zippy Technology Corporation
vendor POINTCHIPS 0x09a6 PointChips
vendor INTERSIL 0x09aa Intersil
+vendor TRIPPLITE2 0x09ae Tripp Lite
vendor ALTIUS 0x09b3 Altius Solutions
vendor ARRIS 0x09c1 Arris Interactive
vendor ACTIVCARD 0x09c3 ACTIVCARD
@@ -501,13 +500,17 @@ vendor ASAHIOPTICAL 0x0a17 Asahi Optical
vendor BOCASYSTEMS 0x0a43 Boca Systems
vendor SHANTOU 0x0a46 ShanTou
vendor MEDIAGEAR 0x0a48 MediaGear
+vendor PLOYTEC 0x0a4a Ploytec GmbH
vendor BROADCOM 0x0a5c Broadcom
vendor GREENHOUSE 0x0a6b GREENHOUSE
+vendor MEDELI 0x0a67 Medeli
vendor GEOCAST 0x0a79 Geocast Network Systems
-vendor IDQUANTIQUE 0x0aba id Quantique
+vendor EGO 0x0a92 EGO systems
+vendor IDQUANTIQUE 0x0aba ID Quantique
+vendor IDTECH 0x0acd ID TECH
vendor ZYDAS 0x0ace Zydas Technology Corporation
vendor NEODIO 0x0aec Neodio
-vendor OPTION 0x0af0 Option N.V:
+vendor OPTION 0x0af0 Option N.V.
vendor ASUS 0x0b05 ASUSTeK Computer
vendor TODOS 0x0b0c Todos Data System
vendor SIIG2 0x0b39 SIIG
@@ -515,42 +518,60 @@ vendor TEKRAM 0x0b3b Tekram Technology
vendor HAL 0x0b41 HAL Corporation
vendor EMS 0x0b43 EMS Production
vendor NEC2 0x0b62 NEC
-vendor ATI2 0x0b6f ATI
+vendor ADLINK 0x0b63 ADLINK Technoligy, Inc.
+vendor ATI2 0x0b6f ATI Technologies
vendor ZEEVO 0x0b7a Zeevo, Inc.
vendor KURUSUGAWA 0x0b7e Kurusugawa Electronics, Inc.
+vendor SMART 0x0b8c Smart Technologies
vendor ASIX 0x0b95 ASIX Electronics
vendor O2MICRO 0x0b97 O2 Micro, Inc.
vendor USR 0x0baf U.S. Robotics
vendor AMBIT 0x0bb2 Ambit Microsystems
vendor HTC 0x0bb4 HTC
vendor REALTEK 0x0bda Realtek
+vendor ERICSSON2 0x0bdb Ericsson
+vendor MEI 0x0bed MEI
vendor ADDONICS2 0x0bf6 Addonics Technology
vendor FSC 0x0bf8 Fujitsu Siemens Computers
vendor AGATE 0x0c08 Agate Technologies
vendor DMI 0x0c0b DMI
-vendor MICRODIA 0x0c45 Chicony
+vendor CANYON 0x0c10 Canyon
+vendor ICOM 0x0c26 Icom Inc.
+vendor GNOTOMETRICS 0x0c33 GN Otometrics
+vendor CHICONY2 0x0c45 Chicony / Microdia / Sonix Technology Co., Ltd.
+vendor REINERSCT 0x0c4b Reiner-SCT
vendor SEALEVEL 0x0c52 Sealevel System
+vendor JETI 0x0c6c Jeti
vendor LUWEN 0x0c76 Luwen
+vendor ELEKTOR 0x0c7d ELEKTOR Electronics
vendor KYOCERA2 0x0c88 Kyocera Wireless Corp.
vendor ZCOM 0x0cde Z-Com
vendor ATHEROS2 0x0cf3 Atheros Communications
+vendor POSIFLEX 0x0d3a POSIFLEX
vendor TANGTOP 0x0d3d Tangtop
+vendor KOBIL 0x0d46 KOBIL
vendor SMC3 0x0d5c Standard Microsystems
vendor ADDON 0x0d7d Add-on Technology
vendor ACDC 0x0d7e American Computer & Digital Components
-vendor ABC 0x0d8c ABC
+vendor CMEDIA 0x0d8c CMEDIA
vendor CONCEPTRONIC 0x0d8e Conceptronic
vendor SKANHEX 0x0d96 Skanhex Technology, Inc.
+vendor POWERCOM 0x0d9f PowerCOM
vendor MSI 0x0db0 Micro Star International
vendor ELCON 0x0db7 ELCON Systemtechnik
+vendor UNKNOWN4 0x0dcd Unknown vendor
vendor NETAC 0x0dd8 Netac
vendor SITECOMEU 0x0df6 Sitecom Europe
vendor MOBILEACTION 0x0df7 Mobile Action
+vendor AMIGO 0x0e0b Amigo Technology
+vendor SMART2 0x0e39 Smart Modular Technologies
vendor SPEEDDRAGON 0x0e55 Speed Dragon Multimedia
vendor HAWKING 0x0e66 Hawking
vendor FOSSIL 0x0e67 Fossil, Inc
vendor GMATE 0x0e7e G.Mate, Inc
+vendor MEDIATEK 0x0e8d MediaTek, Inc.
vendor OTI 0x0ea0 Ours Technology
+vendor YISO 0x0eab Yiso Wireless Co.
vendor PILOTECH 0x0eaf Pilotech
vendor NOVATECH 0x0eb0 NovaTech
vendor ITEGNO 0x0eba iTegno
@@ -563,8 +584,19 @@ vendor VTECH 0x0f88 VTech
vendor FALCOM 0x0f94 Falcom Wireless Communications GmbH
vendor RIM 0x0fca Research In Motion
vendor DYNASTREAM 0x0fcf Dynastream Innovations
+vendor LARSENBRUSGAARD 0x0fd8 Larsen and Brusgaard
+vendor OWL 0x0fde OWL
+vendor KONTRON 0x0fe6 Kontron AG
+vendor DVICO 0x0fe9 DViCO
vendor QUALCOMM 0x1004 Qualcomm
+vendor APACER 0x1005 Apacer
+vendor MOTOROLA4 0x100d Motorola
+vendor HP3 0x103c Hewlett Packard
+vendor AIRPLUS 0x1011 Airplus
vendor DESKNOTE 0x1019 Desknote
+vendor AMD2 0x1022 Advanced Micro Devices
+vendor NEC3 0x1033 NEC
+vendor TTI 0x103e Thurlby Thandar Instruments
vendor GIGABYTE 0x1044 GIGABYTE
vendor WESTERN 0x1058 Western Digital
vendor MOTOROLA 0x1063 Motorola
@@ -572,9 +604,15 @@ vendor CCYU 0x1065 CCYU Technology
vendor CURITEL 0x106c Curitel Communications Inc
vendor SILABS2 0x10a6 SILABS2
vendor USI 0x10ab USI
+vendor HONEYWELL 0x10ac Honeywell
+vendor LIEBERT2 0x10af Liebert
vendor PLX 0x10b5 PLX
vendor ASANTE 0x10bd Asante
vendor SILABS 0x10c4 Silicon Labs
+vendor SILABS3 0x10c5 Silicon Labs
+vendor SILABS4 0x10ce Silicon Labs
+vendor ACTIONS 0x10d6 Actions
+vendor MOXA 0x110a Moxa
vendor ANALOG 0x1110 Analog Devices
vendor TENX 0x1130 Ten X Technology, Inc.
vendor ISSC 0x1131 Integrated System Solution Corp.
@@ -582,18 +620,23 @@ vendor JRC 0x1145 Japan Radio Company
vendor SPHAIRON 0x114b Sphairon Access Systems GmbH
vendor DELORME 0x1163 DeLorme
vendor SERVERWORKS 0x1166 ServerWorks
+vendor DLINK3 0x1186 Dlink
vendor ACERCM 0x1189 Acer Communications & Multimedia
vendor SIERRA 0x1199 Sierra Wireless
+vendor SANWA 0x11ad Sanwa Electric Instrument Co., Ltd.
vendor TOPFIELD 0x11db Topfield Co., Ltd
vendor SIEMENS3 0x11f5 Siemens
-vendor PROLIFIC2 0x11f6 Prolific
+vendor NETINDEX 0x11f6 NetIndex
vendor ALCATEL 0x11f7 Alcatel
+vendor INTERBIOMETRICS 0x1209 Interbiometrics
+vendor FUJITSU3 0x1221 Fujitsu Ltd.
vendor UNKNOWN3 0x1233 Unknown vendor
vendor TSUNAMI 0x1241 Tsunami
vendor PHEENET 0x124a Pheenet
vendor TARGUS 0x1267 Targus
vendor TWINMOS 0x126f TwinMOS
vendor TENDA 0x1286 Tenda
+vendor TESTO 0x128d Testo products
vendor CREATIVE2 0x1292 Creative Labs
vendor BELKIN2 0x1293 Belkin Components
vendor CYBERTAN 0x129b CyberTAN Technology
@@ -604,56 +647,144 @@ vendor AINCOMM 0x12fd Aincomm
vendor MOBILITY 0x1342 Mobility
vendor DICKSMITH 0x1371 Dick Smith Electronics
vendor NETGEAR3 0x1385 Netgear
+vendor VALIDITY 0x138a Validity Sensors, Inc.
vendor BALTECH 0x13ad Baltech
vendor CISCOLINKSYS 0x13b1 Cisco-Linksys
vendor SHARK 0x13d2 Shark
+vendor AZUREWAVE 0x13d3 AsureWave
+vendor INITIO 0x13fd Initio Corporation
+vendor EMTEC 0x13fe Emtec
vendor NOVATEL 0x1410 Novatel Wireless
+vendor OMNIVISION2 0x1415 OmniVision Technologies, Inc.
vendor MERLIN 0x1416 Merlin
+vendor REDOCTANE 0x1430 RedOctane
vendor WISTRONNEWEB 0x1435 Wistron NeWeb
vendor RADIOSHACK 0x1453 Radio Shack
+vendor FIC 0x1457 FIC / OpenMoko
vendor HUAWEI3COM 0x1472 Huawei-3Com
+vendor ABOCOM2 0x1482 AboCom Systems
vendor SILICOM 0x1485 Silicom
vendor RALINK 0x148f Ralink Technology
vendor IMAGINATION 0x149a Imagination Technologies
+vendor ATP 0x14af ATP Electronics
vendor CONCEPTRONIC2 0x14b2 Conceptronic
+vendor SUPERTOP 0x14cd Super Top
vendor PLANEX3 0x14ea Planex Communications
vendor SILICONPORTALS 0x1527 Silicon Portals
vendor UBIQUAM 0x1529 UBIQUAM Co., Ltd.
+vendor JMICRON 0x152d JMicron
vendor UBLOX 0x1546 U-blox
vendor PNY 0x154b PNY
+vendor OWEN 0x1555 Owen
vendor OQO 0x1557 OQO
vendor UMEDIA 0x157e U-MEDIA Communications
vendor FIBERLINE 0x1582 Fiberline
+vendor FREESCALE 0x15a2 Freescale Semiconductor, Inc.
+vendor AFATECH 0x15a4 Afatech Technologies, Inc.
vendor SPARKLAN 0x15a9 SparkLAN
+vendor OLIMEX 0x15ba Olimex
+vendor SOUNDGRAPH 0x15c2 Soundgraph, Inc.
+vendor AMIT2 0x15c5 AMIT
+vendor TEXTECH 0x15ca Textech International Ltd.
vendor SOHOWARE 0x15e8 SOHOware
+vendor ABIT 0x15eb ABIT Corporation
vendor UMAX 0x1606 UMAX Data Systems
vendor INSIDEOUT 0x1608 Inside Out Networks
+vendor AMOI 0x1614 Amoi Electronics
vendor GOODWAY 0x1631 Good Way Technology
vendor ENTREGA 0x1645 Entrega
vendor ACTIONTEC 0x1668 Actiontec Electronics
+vendor CLIPSAL 0x166a Clipsal
+vendor CISCOLINKSYS2 0x167b Cisco-Linksys
vendor ATHEROS 0x168c Atheros Communications
vendor GIGASET 0x1690 Gigaset
vendor GLOBALSUN 0x16ab Global Sun Technology
vendor ANYDATA 0x16d5 AnyDATA Corporation
vendor JABLOTRON 0x16d6 Jablotron
-vendor CMOTECH 0x16d8 CMOTECH Co., Ltd.
+vendor CMOTECH 0x16d8 C-motech
+vendor WIENERPLEINBAUS 0x16dc WIENER Plein & Baus GmbH.
vendor AXESSTEL 0x1726 Axesstel Co., Ltd.
vendor LINKSYS4 0x1737 Linksys
vendor SENAO 0x1740 Senao
+vendor ASUS2 0x1761 ASUS
+vendor SWEEX2 0x177f Sweex
vendor METAGEEK 0x1781 MetaGeek
+vendor KAMSTRUP 0x17a8 Kamstrup A/S
+vendor MISC 0x1781 Misc Vendors
+vendor DISPLAYLINK 0x17e9 DisplayLink
+vendor LENOVO 0x17ef Lenovo
+vendor WAVESENSE 0x17f4 WaveSense
+vendor VAISALA 0x1843 Vaisala
+vendor E3C 0x18b4 E3C Technologies
vendor AMIT 0x18c5 AMIT
+vendor GOOGLE 0x18d1 Google
vendor QCOM 0x18e8 Qcom
+vendor ELV 0x18ef ELV
vendor LINKSYS3 0x1915 Linksys
+vendor MEINBERG 0x1938 Meinberg Funkuhren
+vendor BECEEM 0x198f Beceem Communications
+vendor ZTE 0x19d2 ZTE
vendor QUALCOMMINC 0x19d2 Qualcomm, Incorporated
+vendor QUALCOMM3 0x19f5 Qualcomm, Inc.
+vendor QUANTA2 0x1a32 Quanta
+vendor TERMINUS 0x1a40 Terminus Technology
+vendor ABBOTT 0x1a61 Abbott Diabetics
+vendor BAYER 0x1a79 Bayer
+vendor WCH2 0x1a86 QinHeng Electronics
+vendor STELERA 0x1a8d Stelera Wireless
+vendor SEL 0x1adb Schweitzer Engineering Laboratories
+vendor CORSAIR 0x1b1c Corsair
+vendor ASM 0x1b21 ASMedia Technology
+vendor MATRIXORBITAL 0x1b3d Matrix Orbital
+vendor OVISLINK 0x1b75 OvisLink
+vendor TML 0x1b91 The Mobility Lab
+vendor TCTMOBILE 0x1bbb TCT Mobile
+vendor ALTI2 0x1bc9 Alti-2 products
+vendor SUNPLUS 0x1bcf Sunplus Innovation Technology Inc.
+vendor WAGO 0x1be3 WAGO Kontakttechnik GmbH.
+vendor TELIT 0x1bc7 Telit
+vendor IONICS 0x1c0c Ionics PlugComputer
+vendor LONGCHEER 0x1c9e Longcheer Holdings, Ltd.
+vendor MPMAN 0x1cae MpMan
+vendor DRESDENELEKTRONIK 0x1cf1 dresden elektronik
+vendor NEOTEL 0x1d09 Neotel
+vendor DREAMLINK 0x1d34 Dream Link
+vendor PEGATRON 0x1d4d Pegatron
+vendor QISDA 0x1da5 Qisda
+vendor METAGEEK2 0x1dd5 MetaGeek
+vendor ALINK 0x1e0e Alink
+vendor AIRTIES 0x1eda AirTies
+vendor FESTO 0x1e29 Festo
+vendor LAKESHORE 0x1fb9 Lake Shore Cryotronics, Inc.
+vendor VERTEX 0x1fe7 Vertex Wireless Co., Ltd.
vendor DLINK 0x2001 D-Link
vendor PLANEX2 0x2019 Planex Communications
+vendor HAUPPAUGE2 0x2040 Hauppauge Computer Works
+vendor TLAYTECH 0x20b9 Tlay Tech
+vendor ENCORE 0x203d Encore
+vendor QIHARDWARE 0x20b7 QI-hardware
+vendor PARA 0x20b8 PARA Industrial
+vendor SIMTEC 0x20df Simtec Electronics
+vendor TRENDNET 0x20f4 TRENDnet
+vendor RTSYSTEMS 0x2100 RT Systems
+vendor DLINK4 0x2101 D-Link
+vendor VIALABS 0x2109 VIA Labs
vendor ERICSSON 0x2282 Ericsson
vendor MOTOROLA2 0x22b8 Motorola
+vendor WETELECOM 0x22de WeTelecom
+vendor PINNACLE 0x2304 Pinnacle Systems
+vendor ARDUINO 0x2341 Arduino SA
+vendor TPLINK 0x2357 TP-Link
+vendor WESTMOUNTAIN 0x2405 West Mountain Radio
vendor TRIPPLITE 0x2478 Tripp-Lite
vendor HIROSE 0x2631 Hirose Electric
vendor NHJ 0x2770 NHJ
+vendor THINGM 0x27b8 ThingM
+vendor PERASO 0x2932 Peraso Technologies, Inc.
vendor PLANEX 0x2c02 Planex Communications
+vendor QUECTEL 0x2c7c Quectel Wireless Solutions
vendor VIDZMEDIA 0x3275 VidzMedia Pte Ltd
+vendor LINKINSTRUMENTS 0x3195 Link Instruments Inc.
vendor AEI 0x3334 AEI
vendor HANK 0x3353 Hank Connection
vendor PQI 0x3538 PQI
@@ -665,19 +796,34 @@ vendor IRIVER 0x4102 iRiver
vendor DELL 0x413c Dell
vendor WCH 0x4348 QinHeng Electronics
vendor ACEECA 0x4766 Aceeca
+vendor FEIXUN 0x4855 FeiXun Communication
+vendor PAPOUCH 0x5050 Papouch products
vendor AVERATEC 0x50c2 Averatec
vendor SWEEX 0x5173 Sweex
+vendor PROLIFIC2 0x5372 Prolific Technologies
vendor ONSPEC2 0x55aa OnSpec Electronic Inc.
vendor ZINWELL 0x5a57 Zinwell
+vendor INGENIC 0x601a Ingenic Semiconductor Ltd.
vendor SITECOM 0x6189 Sitecom
+vendor SPRINGERDESIGN 0x6400 Springer Design, Inc.
vendor ARKMICRO 0x6547 Arkmicro Technologies Inc.
vendor 3COM2 0x6891 3Com
+vendor EDIMAX 0x7392 Edimax
vendor INTEL 0x8086 Intel
+vendor INTEL2 0x8087 Intel
+vendor ALLWIN 0x8516 ALLWIN Tech
vendor SITECOM2 0x9016 Sitecom
vendor MOSCHIP 0x9710 MosChip Semiconductor
+vendor NETGEAR4 0x9846 Netgear
vendor MARVELL 0x9e88 Marvell Technology Group Ltd.
vendor 3COM3 0xa727 3Com
+vendor CACE 0xcace CACE Technologies
+vendor COMPARE 0xcdab Compare
+vendor DATAAPEX 0xdaae DataApex
+vendor EVOLUTION 0xdeee Evolution Robotics
+vendor EMPIA 0xeb1a eMPIA Technology
vendor HP2 0xf003 Hewlett Packard
+vendor LOGILINK 0xfc08 LogiLink
vendor USRP 0xfffe GNU Radio USRP
/*
@@ -685,7 +831,7 @@ vendor USRP 0xfffe GNU Radio USRP
*/
/* 3Com products */
-product 3COM HOMECONN 0x009d HomeConnect Camera
+product 3COM HOMECONN 0x009d HomeConnect USB Camera
product 3COM 3CREB96 0x00a0 Bluetooth USB Adapter
product 3COM 3C19250 0x03e8 3C19250 Ethernet Adapter
product 3COM 3CRSHEW696 0x0a01 3CRSHEW696 Wireless Adapter
@@ -702,9 +848,26 @@ product 3COMUSR USRISDN 0x008f 3Com U.S. Robotics Pro ISDN TA
product 3COMUSR HOMECONN 0x009d 3Com HomeConnect Camera
product 3COMUSR USR56K 0x3021 U.S. Robotics 56000 Voice FaxModem Pro
+/* Abbott Diabetics */
+product ABBOTT STEREO_PLUG 0x3410 Abbott Diabetics Stereo Plug
+product ABBOTT STRIP_PORT 0x3420 Abbott Diabetics Strip Port
+
+/* ABIT products */
+product ABIT AK_020 0x7d0e 3G modem
+
+product ACDC HUB 0x2315 USB Pen Drive HUB
+product ACDC SECWRITE 0x2316 USB Pen Drive Secure Write
+product ACDC PEN 0x2317 USB Pen Drive with Secure Write
+
/* AboCom products */
product ABOCOM XX1 0x110c XX1
product ABOCOM XX2 0x200c XX2
+product ABOCOM RT2770 0x2770 RT2770
+product ABOCOM RT2870 0x2870 RT2870
+product ABOCOM RT3070 0x3070 RT3070
+product ABOCOM RT3071 0x3071 RT3071
+product ABOCOM RT3072 0x3072 RT3072
+product ABOCOM2 RT2870_1 0x3c09 RT2870
product ABOCOM URE450 0x4000 URE450 Ethernet Adapter
product ABOCOM UFE1000 0x4002 UFE1000 Fast Ethernet Adapter
product ABOCOM DSB650TX_PNA 0x4003 1/10/100 Ethernet Adapter
@@ -723,16 +886,40 @@ product ABOCOM HWU54DM 0xb21b HWU54DM
product ABOCOM RT2573_2 0xb21c RT2573
product ABOCOM RT2573_3 0xb21d RT2573
product ABOCOM RT2573_4 0xb21e RT2573
+product ABOCOM RTL8188CU_1 0x8188 RTL8188CU
+product ABOCOM RTL8188CU_2 0x8189 RTL8188CU
+product ABOCOM RTL8192CU 0x8178 RTL8192CU
+product ABOCOM RTL8188EU 0x8179 RTL8188EU
product ABOCOM WUG2700 0xb21f WUG2700
+/* Acton Research Corp. */
+product ACTON SPECTRAPRO 0x0100 FTDI compatible adapter
+
/* Accton products */
product ACCTON USB320_EC 0x1046 USB320-EC Ethernet Adapter
product ACCTON 2664W 0x3501 2664W
product ACCTON 111 0x3503 T-Sinus 111 Wireless Adapter
-product ACCTON SMCWUSBG 0x4505 SMCWUSB-G
+product ACCTON SMCWUSBG_NF 0x4505 SMCWUSB-G (no firmware)
+product ACCTON SMCWUSBG 0x4506 SMCWUSB-G
+product ACCTON SMCWUSBTG2_NF 0x4507 SMCWUSBT-G2 (no firmware)
+product ACCTON SMCWUSBTG2 0x4508 SMCWUSBT-G2
product ACCTON PRISM_GT 0x4521 PrismGT USB 2.0 WLAN
product ACCTON SS1001 0x5046 SpeedStream Ethernet Adapter
+product ACCTON RT2870_2 0x6618 RT2870
+product ACCTON RT3070 0x7511 RT3070
+product ACCTON RT2770 0x7512 RT2770
+product ACCTON RT2870_3 0x7522 RT2870
+product ACCTON RT2870_5 0x8522 RT2870
+product ACCTON RT3070_4 0xa512 RT3070
+product ACCTON RT2870_4 0xa618 RT2870
+product ACCTON RT3070_1 0xa701 RT3070
+product ACCTON RT3070_2 0xa702 RT3070
+product ACCTON RT2870_1 0xb522 RT2870
+product ACCTON RT3070_3 0xc522 RT3070
+product ACCTON RT3070_5 0xd522 RT3070
+product ACCTON RTL8192SU 0xc512 RTL8192SU
product ACCTON ZD1211B 0xe501 ZD1211B
+product ACCTON WN7512 0xf522 WN7512
/* Aceeca products */
product ACEECA MEZ1000 0x0001 MEZ1000 RDA
@@ -751,6 +938,8 @@ product ACERP ACERSCAN_620U 0x2060 Acerscan 620U
product ACERP ACERSCAN_4300U 0x20b0 Benq 3300U/4300U
product ACERP ACERSCAN_640BT 0x20be Acerscan 640BT
product ACERP ACERSCAN_1240U 0x20c0 Acerscan 1240U
+product ACERP S81 0x4027 BenQ S81 phone
+product ACERP H10 0x4068 AWL400 Wireless Adapter
product ACERP ATAPI 0x6003 ATA/ATAPI Adapter
product ACERP AWL300 0x9000 AWL300 Wireless Adapter
product ACERP AWL400 0x9001 AWL400 Wireless Adapter
@@ -758,6 +947,9 @@ product ACERP AWL400 0x9001 AWL400 Wireless Adapter
/* Acer Warp products */
product ACERW WARPLINK 0x0204 Warplink
+/* Actions products */
+product ACTIONS MP4 0x1101 Actions MP4 Player
+
/* Actiontec, Inc. products */
product ACTIONTEC PRISM_25 0x0408 Prism2.5 Wireless Adapter
product ACTIONTEC PRISM_25A 0x0421 Prism2.5 Wireless Adapter A
@@ -774,9 +966,15 @@ product ACTIVEWIRE IOBOARD_FW1 0x0101 I/O Board, rev. 1 firmware
/* Adaptec products */
product ADAPTEC AWN8020 0x0020 AWN-8020 WLAN
+/* Addonics products */
+product ADDONICS2 205 0xa001 Cable 205
+
/* Addtron products */
product ADDTRON AWU120 0xff31 AWU-120
+/* ADLINK Texhnology products */
+product ADLINK ND6530 0x6530 ND-6530 USB-Serial
+
/* ADMtek products */
product ADMTEK PEGASUSII_4 0x07c2 AN986A Ethernet
product ADMTEK PEGASUS 0x0986 AN986 Ethernet
@@ -801,6 +999,9 @@ product ADS UBS10BTX 0x0009 UBS-10BT Ethernet
/* AEI products */
product AEI FASTETHERNET 0x1701 Fast Ethernet
+/* Afatech Technologies, Inc. */
+product AFATECH AFATECH1336 0x1336 Flash Card Reader
+
/* Agate Technologies products */
product AGATE QDRIVE 0x0378 Q-Drive
@@ -822,29 +1023,75 @@ product AINCOMM AWU2000B 0x1001 AWU2000B Wireless Adapter
/* AIPTEK products */
product AIPTEK POCKETCAM3M 0x2011 PocketCAM 3Mega
product AIPTEK2 PENCAM_MEGA_1_3 0x504a PenCam Mega 1.3
+product AIPTEK2 SUNPLUS_TECH 0x0c15 Sunplus Technology Inc.
+
+/* AirPlis products */
+product AIRPLUS MCD650 0x3198 MCD650 modem
/* AirPrime products */
product AIRPRIME PC5220 0x0112 CDMA Wireless PC Card
+product AIRPRIME USB308 0x68A3 USB308 HSPA+ USB Modem
+product AIRPRIME AC313U 0x68aa Sierra Wireless AirCard 313U
+
+/* AirTies products */
+product AIRTIES RT3070 0x2310 RT3070
/* AKS products */
product AKS USBHASP 0x0001 USB-HASP 0.06
+/* Alcatel products */
+product ALCATEL OT535 0x02df One Touch 535/735
+
/* Alcor Micro, Inc. products */
product ALCOR2 KBD_HUB 0x2802 Kbd Hub
+product ALCOR DUMMY 0x0000 Dummy product
+product ALCOR SDCR_6335 0x6335 SD/MMC Card Reader
+product ALCOR SDCR_6362 0x6362 SD/MMC Card Reader
+product ALCOR SDCR_6366 0x6366 SD/MMC Card Reader
+product ALCOR TRANSCEND 0x6387 Transcend JetFlash Drive
product ALCOR MA_KBD_HUB 0x9213 MacAlly Kbd Hub
product ALCOR AU9814 0x9215 AU9814 Hub
product ALCOR UMCR_9361 0x9361 USB Multimedia Card Reader
product ALCOR SM_KBD 0x9410 MicroConnectors/StrongMan Keyboard
product ALCOR NEC_KBD_HUB 0x9472 NEC Kbd Hub
+product ALCOR AU9720 0x9720 USB2 - RS-232
+product ALCOR AU6390 0x6390 AU6390 USB-IDE converter
+
+/* Alink products */
+product ALINK DWM652U5 0xce16 DWM-652
+product ALINK 3G 0x9000 3G modem
+product ALINK SIM7600E 0x9001 LTE modem
+product ALINK 3GU 0x9200 3G modem
/* Altec Lansing products */
product ALTEC ADA70 0x0070 ADA70 Speakers
product ALTEC ASC495 0xff05 ASC495 Speakers
+/* Alti-2 products */
+product ALTI2 N3 0x6001 FTDI compatible adapter
+
/* Allied Telesyn International products */
product ALLIEDTELESYN ATUSB100 0xb100 AT-USB100
+/* ALLWIN Tech products */
+product ALLWIN RT2070 0x2070 RT2070
+product ALLWIN RT2770 0x2770 RT2770
+product ALLWIN RT2870 0x2870 RT2870
+product ALLWIN RT3070 0x3070 RT3070
+product ALLWIN RT3071 0x3071 RT3071
+product ALLWIN RT3072 0x3072 RT3072
+product ALLWIN RT3572 0x3572 RT3572
+
+/* AlphaSmart, Inc. products */
+product ALPHASMART DANA_KB 0xdbac AlphaSmart Dana Keyboard
+product ALPHASMART DANA_SYNC 0xdf00 AlphaSmart Dana HotSync
+
+/* Amoi products */
+product AMOI H01 0x0800 H01 3G modem
+product AMOI H01A 0x7002 H01A 3G modem
+product AMOI H02 0x0802 H02 3G modem
+
/* American Power Conversion products */
product APC UPS 0x0002 Uninterruptible Power Supply
@@ -852,14 +1099,35 @@ product APC UPS 0x0002 Uninterruptible Power Supply
product AMBIT WLAN 0x0302 WLAN
product AMBIT NTL_250 0x6098 NTL 250 cable modem
+/* Apacer products */
+product APACER HT202 0xb113 USB 2.0 Flash Drive
+
+/* American Power Conversion products */
+product APC UPS 0x0002 Uninterruptible Power Supply
+
+/* Amigo Technology products */
+product AMIGO RT2870_1 0x9031 RT2870
+product AMIGO RT2870_2 0x9041 RT2870
+
/* AMIT products */
product AMIT CGWLUSB2GO 0x0002 CG-WLUSB2GO
+product AMIT CGWLUSB2GNR 0x0008 CG-WLUSB2GNR
+product AMIT RT2870_1 0x0012 RT2870
+
+/* AMIT(2) products */
+product AMIT2 RT2870 0x0008 RT2870
+
+/* Analog Devices products */
+product ANALOGDEVICES GNICE 0xf000 FTDI compatible adapter
+product ANALOGDEVICES GNICEPLUS 0xf001 FTDI compatible adapter
/* Anchor products */
+product ANCHOR SERIAL 0x2008 Serial
product ANCHOR EZUSB 0x2131 EZUSB
product ANCHOR EZLINK 0x2720 EZLINK
/* AnyData products */
+product ANYDATA ADU_620UW 0x6202 CDMA 2000 EV-DO USB Modem
product ANYDATA ADU_E100X 0x6501 CDMA 2000 1xRTT/EV-DO USB Modem
product ANYDATA ADU_500A 0x6502 CDMA 2000 EV-DO USB Modem
@@ -870,9 +1138,66 @@ product AOX USB101 0x0008 Ethernet
product APC UPS 0x0002 Uninterruptible Power Supply
/* Apple Computer products */
+product APPLE DUMMY 0x0000 Dummy product
+product APPLE IMAC_KBD 0x0201 USB iMac Keyboard
+product APPLE KBD 0x0202 USB Keyboard M2452
product APPLE EXT_KBD 0x020c Apple Extended USB Keyboard
+/* MacbookAir, aka wellspring */
+product APPLE WELLSPRING_ANSI 0x0223 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING_ISO 0x0224 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING_JIS 0x0225 Apple Internal Keyboard/Trackpad
+/* MacbookProPenryn, aka wellspring2 */
+product APPLE WELLSPRING2_ANSI 0x0230 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING2_ISO 0x0231 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING2_JIS 0x0232 Apple Internal Keyboard/Trackpad
+/* Macbook5,1 (unibody), aka wellspring3 */
+product APPLE WELLSPRING3_ANSI 0x0236 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING3_ISO 0x0237 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING3_JIS 0x0238 Apple Internal Keyboard/Trackpad
+/* MacbookAir3,2 (unibody), aka wellspring4 */
+product APPLE WELLSPRING4_ANSI 0x023f Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING4_ISO 0x0240 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING4_JIS 0x0241 Apple Internal Keyboard/Trackpad
+/* MacbookAir3,1 (unibody), aka wellspring4 */
+product APPLE WELLSPRING4A_ANSI 0x0242 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING4A_ISO 0x0243 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING4A_JIS 0x0244 Apple Internal Keyboard/Trackpad
+/* Macbook8 (unibody, March 2011) */
+product APPLE WELLSPRING5_ANSI 0x0245 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING5_ISO 0x0246 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING5_JIS 0x0247 Apple Internal Keyboard/Trackpad
+/* MacbookAir4,1 (unibody, July 2011) */
+product APPLE WELLSPRING6A_ANSI 0x0249 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING6A_ISO 0x024a Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING6A_JIS 0x024b Apple Internal Keyboard/Trackpad
+/* MacbookAir4,2 (unibody, July 2011) */
+product APPLE WELLSPRING6_ANSI 0x024c Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING6_ISO 0x024d Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING6_JIS 0x024e Apple Internal Keyboard/Trackpad
+/* Macbook8,2 (unibody) */
+product APPLE WELLSPRING5A_ANSI 0x0252 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING5A_ISO 0x0253 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING5A_JIS 0x0254 Apple Internal Keyboard/Trackpad
+/* MacbookPro10,1 (unibody, June 2012) */
+product APPLE WELLSPRING7_ANSI 0x0262 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING7_ISO 0x0263 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING7_JIS 0x0264 Apple Internal Keyboard/Trackpad
+/* MacbookPro10,2 (unibody, October 2012) */
+product APPLE WELLSPRING7A_ANSI 0x0259 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING7A_ISO 0x025a Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING7A_JIS 0x025b Apple Internal Keyboard/Trackpad
+/* MacbookAir6,2 (unibody, June 2013) */
+product APPLE WELLSPRING8_ANSI 0x0290 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING8_ISO 0x0291 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING8_JIS 0x0292 Apple Internal Keyboard/Trackpad
+/* MacbookPro12,1 */
+product APPLE WELLSPRING9_ANSI 0x0272 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING9_ISO 0x0273 Apple Internal Keyboard/Trackpad
+product APPLE WELLSPRING9_JIS 0x0274 Apple Internal Keyboard/Trackpad
+product APPLE MOUSE 0x0301 Mouse M4848
product APPLE OPTMOUSE 0x0302 Optical mouse
product APPLE MIGHTYMOUSE 0x0304 Mighty Mouse
+product APPLE KBD_HUB 0x1001 Hub in Apple USB Keyboard
product APPLE EXT_KBD_HUB 0x1003 Hub in Apple Extended USB Keyboard
product APPLE SPEAKERS 0x1101 Speakers
product APPLE IPOD 0x1201 iPod
@@ -886,7 +1211,13 @@ product APPLE IPOD_08 0x1208 iPod '08'
product APPLE IPODVIDEO 0x1209 iPod Video
product APPLE IPODNANO 0x120a iPod Nano
product APPLE IPHONE 0x1290 iPhone
+product APPLE IPOD_TOUCH 0x1291 iPod Touch
product APPLE IPHONE_3G 0x1292 iPhone 3G
+product APPLE IPHONE_3GS 0x1294 iPhone 3GS
+product APPLE IPHONE_4 0x1297 iPhone 4
+product APPLE IPHONE_4S 0x12a0 iPhone 4S
+product APPLE IPHONE_5 0x12a8 iPhone 5
+product APPLE IPAD 0x129a iPad
product APPLE ETHERNET 0x1402 Ethernet A1277
/* Arkmicro Technologies */
@@ -902,16 +1233,41 @@ product ASANTE EA 0x1427 Ethernet
/* ASIX Electronics products */
product ASIX AX88172 0x1720 10/100 Ethernet
product ASIX AX88178 0x1780 AX88178
+product ASIX AX88178A 0x178a AX88178A USB 2.0 10/100/1000 Ethernet
+product ASIX AX88179 0x1790 AX88179 USB 3.0 10/100/1000 Ethernet
product ASIX AX88772 0x7720 AX88772
+product ASIX AX88772A 0x772a AX88772A USB 2.0 10/100 Ethernet
+product ASIX AX88772B 0x772b AX88772B USB 2.0 10/100 Ethernet
+product ASIX AX88772B_1 0x7e2b AX88772B USB 2.0 10/100 Ethernet
/* ASUS products */
+product ASUS2 USBN11 0x0b05 USB-N11
+product ASUS RT2570 0x1706 RT2500USB Wireless Adapter
product ASUS WL167G 0x1707 WL-167g Wireless Adapter
product ASUS WL159G 0x170c WL-159g
product ASUS A9T_WIFI 0x171b A9T wireless
+product ASUS P5B_WIFI 0x171d P5B wireless
product ASUS RT2573_1 0x1723 RT2573
product ASUS RT2573_2 0x1724 RT2573
product ASUS LCM 0x1726 LCM display
+product ASUS RT2870_1 0x1731 RT2870
+product ASUS RT2870_2 0x1732 RT2870
+product ASUS RT2870_3 0x1742 RT2870
+product ASUS RT2870_4 0x1760 RT2870
+product ASUS RT2870_5 0x1761 RT2870
+product ASUS USBN13 0x1784 USB-N13
+product ASUS USBN10 0x1786 USB-N10
+product ASUS RT3070_1 0x1790 RT3070
+product ASUS RTL8192SU 0x1791 RTL8192SU
+product ASUS USB_N53 0x179d ASUS Black Diamond Dual Band USB-N53
+product ASUS RTL8192CU 0x17ab RTL8192CU
+product ASUS USBN66 0x17ad USB-N66
+product ASUS USBN10NANO 0x17ba USB-N10 Nano
+product ASUS USBAC51 0x17d1 USB-AC51
+product ASUS USBAC56 0x17d2 USB-AC56
+product ASUS A730W 0x4202 ASUS MyPal A730W
product ASUS P535 0x420f ASUS P535 PDA
+product ASUS GMSC 0x422f ASUS Generic Mass Storage
/* ATen products */
product ATEN UC1284 0x2001 Parallel printer
@@ -921,6 +1277,9 @@ product ATEN UC232A 0x2008 Serial
product ATEN UC210T 0x2009 UC-210T Ethernet
product ATEN DSB650C 0x4000 DSB-650C
+/* ATP Electronics products */
+product ATP EUSB 0xaf01 ATP IG eUSB SSD
+
/* Atheros Communications products */
product ATHEROS AR5523 0x0001 AR5523
product ATHEROS AR5523_NF 0x0002 AR5523 (no firmware)
@@ -930,28 +1289,74 @@ product ATHEROS2 AR5523_2 0x0003 AR5523
product ATHEROS2 AR5523_2_NF 0x0004 AR5523 (no firmware)
product ATHEROS2 AR5523_3 0x0005 AR5523
product ATHEROS2 AR5523_3_NF 0x0006 AR5523 (no firmware)
+product ATHEROS2 TG121N 0x1001 TG121N
+product ATHEROS2 WN821NV2 0x1002 WN821NV2
+product ATHEROS2 3CRUSBN275 0x1010 3CRUSBN275
+product ATHEROS2 WN612 0x1011 WN612
+product ATHEROS2 AR9170 0x9170 AR9170
/* Atmel Comp. products */
-product ATMEL UHB124 0x3301 UHB124 hub
+product ATMEL STK541 0x2109 Zigbee Controller
+product ATMEL UHB124 0x3301 AT43301 USB 1.1 Hub
product ATMEL DWL120 0x7603 DWL-120 Wireless Adapter
product ATMEL BW002 0x7605 BW002 Wireless Adapter
product ATMEL WL1130USB 0x7613 WL-1130 USB
product ATMEL AT76C505A 0x7614 AT76c505a Wireless Adapter
+/* AuthenTec products */
+product AUTHENTEC AES1610 0x1600 AES1610 Fingerprint Sensor
+
/* Avision products */
product AVISION 1200U 0x0268 1200U scanner
+/* AVM products */
+product AVM FRITZWLAN 0x8401 FRITZ!WLAN N
+
/* Axesstel products */
product AXESSTEL DATAMODEM 0x1000 Data Modem
+/* AsureWave products */
+product AZUREWAVE RT2870_1 0x3247 RT2870
+product AZUREWAVE RT2870_2 0x3262 RT2870
+product AZUREWAVE RT3070_1 0x3273 RT3070
+product AZUREWAVE RT3070_2 0x3284 RT3070
+product AZUREWAVE RT3070_3 0x3305 RT3070
+product AZUREWAVE RTL8188CU 0x3357 RTL8188CU
+product AZUREWAVE RTL8188CE_1 0x3358 RTL8188CE
+product AZUREWAVE RTL8188CE_2 0x3359 RTL8188CE
+product AZUREWAVE RTL8192SU_1 0x3306 RTL8192SU
+product AZUREWAVE RTL8192SU_2 0x3309 RTL8192SU
+product AZUREWAVE RTL8192SU_3 0x3310 RTL8192SU
+product AZUREWAVE RTL8192SU_4 0x3311 RTL8192SU
+product AZUREWAVE RTL8192SU_5 0x3325 RTL8192SU
+
/* Baltech products */
product BALTECH CARDREADER 0x9999 Card reader
+/* Bayer products */
+product BAYER CONTOUR_CABLE 0x6001 FTDI compatible adapter
+
/* B&B Electronics products */
product BBELECTRONICS USOTL4 0xAC01 RS-422/485
+product BBELECTRONICS 232USB9M 0xac27 FTDI compatible adapter
+product BBELECTRONICS 485USB9F_2W 0xac25 FTDI compatible adapter
+product BBELECTRONICS 485USB9F_4W 0xac26 FTDI compatible adapter
+product BBELECTRONICS 485USBTB_2W 0xac33 FTDI compatible adapter
+product BBELECTRONICS 485USBTB_4W 0xac34 FTDI compatible adapter
+product BBELECTRONICS TTL3USB9M 0xac50 FTDI compatible adapter
+product BBELECTRONICS TTL5USB9M 0xac49 FTDI compatible adapter
+product BBELECTRONICS USO9ML2 0xac03 FTDI compatible adapter
+product BBELECTRONICS USO9ML2DR 0xac17 FTDI compatible adapter
+product BBELECTRONICS USO9ML2DR_2 0xac16 FTDI compatible adapter
+product BBELECTRONICS USOPTL4 0xac11 FTDI compatible adapter
+product BBELECTRONICS USOPTL4DR 0xac19 FTDI compatible adapter
+product BBELECTRONICS USOPTL4DR2 0xac18 FTDI compatible adapter
+product BBELECTRONICS USPTL4 0xac12 FTDI compatible adapter
+product BBELECTRONICS USTL4 0xac02 FTDI compatible adapter
+product BBELECTRONICS ZZ_PROG1_USB 0xba02 FTDI compatible adapter
/* Belkin products */
-/* product BELKIN F5U111 0x???? F5U111 Ethernet */
+/*product BELKIN F5U111 0x???? F5U111 Ethernet*/
product BELKIN F5D6050 0x0050 F5D6050 802.11b Wireless Adapter
product BELKIN FBT001V 0x0081 FBT001v2 Bluetooth
product BELKIN FBT003V 0x0084 FBT003v2 Bluetooth
@@ -963,9 +1368,22 @@ product BELKIN USB2LAN 0x0121 USB to LAN
product BELKIN F5U208 0x0208 F5U208 VideoBus II
product BELKIN F5U237 0x0237 F5U237 USB 2.0 7-Port Hub
product BELKIN F5U257 0x0257 F5U257 Serial
+product BELKIN F6H375USB 0x0375 F6H375-USB
product BELKIN F5U409 0x0409 F5U409 Serial
product BELKIN F6C550AVR 0x0551 F6C550-AVR UPS
+product BELKIN F6C1250TWRK 0x0750 F6C1250-TW-RK
+product BELKIN F6C1500TWRK 0x0751 F6C1500-TW-RK
+product BELKIN F6C900UNV 0x0900 F6C900-UNV
+product BELKIN F6C100UNV 0x0910 F6C100-UNV
+product BELKIN F6C120UNV 0x0912 F6C120-UNV UPS
+product BELKIN F6C800UNV 0x0980 F6C800-UNV
+product BELKIN F6C1100UNV 0x1100 F6C1100-UNV, F6C1200-UNV
product BELKIN F5U120 0x1203 F5U120-PC Hub
+product BELKIN RTL8188CU 0x1102 RTL8188CU Wireless Adapter
+product BELKIN F9L1103 0x1103 F9L1103 Wireless Adapter
+product BELKIN RTL8192CU 0x2102 RTL8192CU Wireless Adapter
+product BELKIN F7D2102 0x2103 F7D2102 Wireless Adapter
+product BELKIN F5U258 0x258A F5U258 Host to Host cable
product BELKIN ZD1211B 0x4050 ZD1211B
product BELKIN F5D5055 0x5055 F5D5055
product BELKIN F5D7050 0x7050 F5D7050 Wireless Adapter
@@ -973,8 +1391,19 @@ product BELKIN F5D7051 0x7051 F5D7051 54g USB Network Adapter
product BELKIN F5D7050A 0x705a F5D7050A Wireless Adapter
/* Also sold as 'Ativa 802.11g wireless card' */
product BELKIN F5D7050_V4000 0x705c F5D7050 v4000 Wireless Adapter
+product BELKIN F5D7050E 0x705e F5D7050E Wireless Adapter
+product BELKIN RT2870_1 0x8053 RT2870
+product BELKIN RT2870_2 0x805c RT2870
+product BELKIN F5D8053V3 0x815c F5D8053 v3
+product BELKIN RTL8192SU_1 0x815f RTL8192SU
+product BELKIN RTL8192SU_2 0x845a RTL8192SU
+product BELKIN RTL8192SU_3 0x945a RTL8192SU
+product BELKIN F5D8055 0x825a F5D8055
+product BELKIN F5D8055V2 0x825b F5D8055 v2
product BELKIN F5D9050V3 0x905b F5D9050 ver 3 Wireless Adapter
product BELKIN2 F5U002 0x0002 F5U002 Parallel printer
+product BELKIN F6D4050V1 0x935a F6D4050 v1
+product BELKIN F6D4050V2 0x935b F6D4050 v2
/* Billionton products */
product BILLIONTON USB100 0x0986 USB100N 10/100 FastEthernet
@@ -988,10 +1417,15 @@ product BROADCOM BCM2033 0x2033 BCM2033 Bluetooth USB dongle
/* Brother Industries products */
product BROTHER HL1050 0x0002 HL-1050 laser printer
+product BROTHER MFC8600_9650 0x0100 MFC8600/9650 multifunction device
/* Behavior Technology Computer products */
+product BTC BTC6100 0x5550 6100C Keyboard
product BTC BTC7932 0x6782 Keyboard with mouse port
+/* CACE Technologies products */
+product CACE AIRPCAPNX 0x0300 AirPcap NX
+
/* Canon, Inc. products */
product CANON N656U 0x2206 CanoScan N656U
product CANON N1220U 0x2207 CanoScan N1220U
@@ -1021,6 +1455,7 @@ product CCYU ED1064 0x2136 EasyDisk ED1064
/* Century products */
product CENTURY EX35QUAT 0x011e Century USB Disk Enclosure
+product CENTURY EX35SW4_SB4 0x011f Century USB Disk Enclosure
/* Cherry products */
product CHERRY MY3000KBD 0x0001 My3000 keyboard
@@ -1033,6 +1468,14 @@ product CHIC CYPRESS 0x0003 Cypress USB Mouse
/* Chicony products */
product CHICONY KB8933 0x0001 KB-8933 keyboard
+product CHICONY KU0325 0x0116 KU-0325 keyboard
+product CHICONY CNF7129 0xb071 Notebook Web Camera
+product CHICONY HDUVCCAM 0xb40a HD UVC WebCam
+product CHICONY RTL8188CUS_1 0xaff7 RTL8188CUS
+product CHICONY RTL8188CUS_2 0xaff8 RTL8188CUS
+product CHICONY RTL8188CUS_3 0xaff9 RTL8188CUS
+product CHICONY RTL8188CUS_4 0xaffa RTL8188CUS
+product CHICONY RTL8188CUS_5 0xaffa RTL8188CUS
product CHICONY2 TWINKLECAM 0x600d TwinkleCam USB camera
/* CH Products */
@@ -1042,6 +1485,7 @@ product CHPRODUCTS FIGHTERSTICK 0x00f3 Fighterstick
product CHPRODUCTS FLIGHTYOKE 0x00ff Flight Sim Yoke
/* Cisco-Linksys products */
+product CISCOLINKSYS WUSB54AG 0x000c WUSB54AG Wireless Adapter
product CISCOLINKSYS WUSB54G 0x000d WUSB54G Wireless Adapter
product CISCOLINKSYS WUSB54GP 0x0011 WUSB54GP Wireless Adapter
product CISCOLINKSYS USB200MV2 0x0018 USB200M v2
@@ -1049,11 +1493,30 @@ product CISCOLINKSYS HU200TS 0x001a HU200TS Wireless Adapter
product CISCOLINKSYS WUSB54GC 0x0020 WUSB54GC
product CISCOLINKSYS WUSB54GR 0x0023 WUSB54GR
product CISCOLINKSYS WUSBF54G 0x0024 WUSBF54G
+product CISCOLINKSYS AE1000 0x002f AE1000
+product CISCOLINKSYS WUSB6300 0x003f WUSB6300
+product CISCOLINKSYS USB3GIGV1 0x0041 USB3GIGV1 USB Ethernet Adapter
+product CISCOLINKSYS2 RT3070 0x4001 RT3070
+product CISCOLINKSYS3 RT3070 0x0101 RT3070
+
+/* Clipsal products */
+product CLIPSAL 560884 0x0101 560884 C-Bus Audio Matrix Switch
+product CLIPSAL 5500PACA 0x0201 5500PACA C-Bus Pascal Automation Controller
+product CLIPSAL 5800PC 0x0301 5800PC C-Bus Wireless Interface
+product CLIPSAL 5500PCU 0x0303 5500PCU C-Bus Interface
+product CLIPSAL 5000CT2 0x0304 5000CT2 C-Bus Touch Screen
+product CLIPSAL C5000CT2 0x0305 C5000CT2 C-Bus Touch Screen
+product CLIPSAL L51xx 0x0401 L51xx C-Bus Dimmer
+
+/* C-Media products */
+product CMEDIA CM6206 0x0102 CM106 compatible sound device
/* CMOTECH products */
-product CMOTECH CNU510 0x5141 CMOTECH CDMA Technologies USB modem
+product CMOTECH CNU510 0x5141 CDMA Technologies USB modem
product CMOTECH CNU550 0x5543 CDMA 2000 1xRTT/1xEVDO USB modem
-product CMOTECH CDMA_MODEM1 0x6280 CMOTECH CDMA Technologies USB modem
+product CMOTECH CGU628 0x6006 CGU-628
+product CMOTECH CDMA_MODEM1 0x6280 CDMA Technologies USB modem
+product CMOTECH DISK 0xf000 disk mode
/* Compaq products */
product COMPAQ IPAQPOCKETPC 0x0003 iPAQ PocketPC
@@ -1071,12 +1534,29 @@ product CONCEPTRONIC AR5523_1 0x7801 AR5523
product CONCEPTRONIC AR5523_1_NF 0x7802 AR5523 (no firmware)
product CONCEPTRONIC AR5523_2 0x7811 AR5523
product CONCEPTRONIC AR5523_2_NF 0x7812 AR5523 (no firmware)
+product CONCEPTRONIC2 RTL8192SU_1 0x3300 RTL8192SU
+product CONCEPTRONIC2 RTL8192SU_2 0x3301 RTL8192SU
+product CONCEPTRONIC2 RTL8192SU_3 0x3302 RTL8192SU
product CONCEPTRONIC2 C54RU 0x3c02 C54RU WLAN
product CONCEPTRONIC2 C54RU2 0x3c22 C54RU
+product CONCEPTRONIC2 RT3070_1 0x3c08 RT3070
+product CONCEPTRONIC2 RT3070_2 0x3c11 RT3070
+product CONCEPTRONIC2 VIGORN61 0x3c25 VIGORN61
+product CONCEPTRONIC2 RT2870_1 0x3c06 RT2870
+product CONCEPTRONIC2 RT2870_2 0x3c07 RT2870
+product CONCEPTRONIC2 RT2870_7 0x3c09 RT2870
+product CONCEPTRONIC2 RT2870_8 0x3c12 RT2870
+product CONCEPTRONIC2 RT2870_3 0x3c23 RT2870
+product CONCEPTRONIC2 RT2870_4 0x3c25 RT2870
+product CONCEPTRONIC2 RT2870_5 0x3c27 RT2870
+product CONCEPTRONIC2 RT2870_6 0x3c28 RT2870
/* Connectix products */
product CONNECTIX QUICKCAM 0x0001 QuickCam
+/* Conect products */
+product CONTEC COM1USBH 0x8311 FTDI compatible adapter
+
/* Corega products */
product COREGA ETHER_USB_T 0x0001 Ether USB-T
product COREGA FETHER_USB_TX 0x0004 FEther USB-TX
@@ -1085,11 +1565,28 @@ product COREGA FETHER_USB_TXS 0x000d FEther USB-TXS
product COREGA WLANUSB 0x0012 Wireless LAN Stick-11
product COREGA FETHER_USB2_TX 0x0017 FEther USB2-TX
product COREGA WLUSB_11_KEY 0x001a ULUSB-11 Key
+product COREGA CGUSBRS232R 0x002a CG-USBRS232R
product COREGA CGWLUSB2GL 0x002d CG-WLUSB2GL
product COREGA CGWLUSB2GPX 0x002e CG-WLUSB2GPX
+product COREGA RT2870_1 0x002f RT2870
+product COREGA RT2870_2 0x003c RT2870
+product COREGA RT2870_3 0x003f RT2870
+product COREGA RT3070 0x0041 RT3070
+product COREGA CGWLUSB300GNM 0x0042 CG-WLUSB300GNM
+product COREGA RTL8192SU 0x0047 RTL8192SU
+product COREGA RTL8192CU 0x0056 RTL8192CU
+
product COREGA WLUSB_11_STICK 0x7613 WLAN USB Stick 11
product COREGA FETHER_USB_TXC 0x9601 FEther USB-TXC
+/* Corsair products */
+product CORSAIR K60 0x0a60 Corsair Vengeance K60 keyboard
+product CORSAIR K68 0x1b3f Corsair Gaming K68 keyboard
+product CORSAIR K70 0x1b09 Corsair Vengeance K70 keyboard
+product CORSAIR K70_RGB 0x1b13 Corsair K70 RGB Keyboard
+product CORSAIR STRAFE 0x1b15 Corsair STRAFE Gaming keyboard
+product CORSAIR STRAFE2 0x1b44 Corsair STRAFE Gaming keyboard
+
/* Creative products */
product CREATIVE NOMAD_II 0x1002 Nomad II MP3 player
product CREATIVE NOMAD_IIMG 0x4004 Nomad II MG
@@ -1101,6 +1598,10 @@ product CREATIVE3 OPTICAL_MOUSE 0x0001 Notebook Optical Mouse
product CSR BT_DONGLE 0x0001 Bluetooth USB dongle
product CSR CSRDFU 0xffff USB Bluetooth Device in DFU State
+/* Chipsbank Microelectronics Co., Ltd */
+product CHIPSBANK USBMEMSTICK 0x6025 CBM2080 Flash drive controller
+product CHIPSBANK USBMEMSTICK1 0x6026 CBM1180 Flash drive controller
+
/* CTX products */
product CTX EX1300 0x9999 Ex1300 hub
@@ -1108,12 +1609,17 @@ product CTX EX1300 0x9999 Ex1300 hub
product CURITEL HX550C 0x1101 CDMA 2000 1xRTT USB modem (HX-550C)
product CURITEL HX57XB 0x2101 CDMA 2000 1xRTT USB modem (HX-570/575B/PR-600)
product CURITEL PC5740 0x3701 Broadband Wireless modem
+product CURITEL UM150 0x3711 EVDO modem
+product CURITEL UM175 0x3714 EVDO modem
/* CyberPower products */
-product CYBERPOWER 1500CAVRLCD 0x0501 1500CAVRLCD
+product CYBERPOWER BC900D 0x0005 900AVR/BC900D, CP1200AVR/BC1200D
+product CYBERPOWER 1500CAVRLCD 0x0501 1500CAVRLCD
+product CYBERPOWER OR2200LCDRM2U 0x0601 OR2200LCDRM2U
/* CyberTAN Technology products */
product CYBERTAN TG54USB 0x1666 TG54USB
+product CYBERTAN RT2870 0x1828 RT2870
/* Cypress Semiconductor products */
product CYPRESS MOUSE 0x0001 mouse
@@ -1121,8 +1627,12 @@ product CYPRESS THERMO 0x0002 thermometer
product CYPRESS WISPY1A 0x0bad MetaGeek Wi-Spy
product CYPRESS KBDHUB 0x0101 Keyboard/Hub
product CYPRESS FMRADIO 0x1002 FM Radio
+product CYPRESS IKARILASER 0x121f Ikari Laser SteelSeries ApS
+
product CYPRESS USBRS232 0x5500 USB-RS232 Interface
product CYPRESS SLIM_HUB 0x6560 Slim Hub
+product CYPRESS XX6830XX 0x6830 PATA Storage Device
+product CYPRESS SILVERSHIELD 0xfd13 Gembird Silver Shield PM
/* Daisy Technology products */
product DAISY DMC 0x6901 USB MultiMedia Reader
@@ -1130,6 +1640,9 @@ product DAISY DMC 0x6901 USB MultiMedia Reader
/* Dallas Semiconductor products */
product DALLAS J6502 0x4201 J-6502 speakers
+/* DataApex products */
+product DATAAPEX MULTICOM 0xead6 MultiCom
+
/* Dell products */
product DELL PORT 0x0058 Port Replicator
product DELL AIO926 0x5115 Photo AIO Printer 926
@@ -1137,7 +1650,24 @@ product DELL BC02 0x8000 BC02 Bluetooth USB Adapter
product DELL PRISM_GT_1 0x8102 PrismGT USB 2.0 WLAN
product DELL TM350 0x8103 TrueMobile 350 Bluetooth USB Adapter
product DELL PRISM_GT_2 0x8104 PrismGT USB 2.0 WLAN
+product DELL U5700 0x8114 Dell 5700 3G
+product DELL U5500 0x8115 Dell 5500 3G
+product DELL U5505 0x8116 Dell 5505 3G
+product DELL U5700_2 0x8117 Dell 5700 3G
+product DELL U5510 0x8118 Dell 5510 3G
+product DELL U5700_3 0x8128 Dell 5700 3G
+product DELL U5700_4 0x8129 Dell 5700 3G
+product DELL U5720 0x8133 Dell 5720 3G
+product DELL U5720_2 0x8134 Dell 5720 3G
product DELL U740 0x8135 Dell U740 CDMA
+product DELL U5520 0x8136 Dell 5520 3G
+product DELL U5520_2 0x8137 Dell 5520 3G
+product DELL U5520_3 0x8138 Dell 5520 3G
+product DELL U5730 0x8180 Dell 5730 3G
+product DELL U5730_2 0x8181 Dell 5730 3G
+product DELL U5730_3 0x8182 Dell 5730 3G
+product DELL DW700 0x9500 Dell DW700 GPS
+product DELL2 VARIOUS_UPS 0xffff Various UPS Models
/* Delorme Paublishing products */
product DELORME EARTHMATE 0x0100 Earthmate GPS
@@ -1157,11 +1687,27 @@ product DIGI ACCELEPORT2 0x0002 AccelePort USB 2
product DIGI ACCELEPORT4 0x0004 AccelePort USB 4
product DIGI ACCELEPORT8 0x0008 AccelePort USB 8
+/* Digianswer A/S products */
+product DIGIANSWER ZIGBEE802154 0x000a ZigBee/802.15.4 MAC
+
/* D-Link products */
-/* product DLINK DSBS25 0x0100 DSB-S25 serial */
+/*product DLINK DSBS25 0x0100 DSB-S25 serial*/
product DLINK DUBE100 0x1a00 10/100 Ethernet
+product DLINK DUBE100C1 0x1a02 DUB-E100 rev C1
product DLINK DSB650TX4 0x200c 10/100 Ethernet
product DLINK DWL120E 0x3200 DWL-120 rev E
+product DLINK RTL8192CU_1 0x3307 RTL8192CU
+product DLINK RTL8188CU 0x3308 RTL8188CU
+product DLINK RTL8192CU_2 0x3309 RTL8192CU
+product DLINK RTL8192CU_3 0x330a RTL8192CU
+product DLINK DWA131B 0x330d DWA-131 rev B
+product DLINK DWA125D1 0x330f DWA-125 rev D1
+product DLINK DWA123D1 0x3310 DWA-123 rev D1
+product DLINK DWA171A1 0x3314 DWA-171 rev A1
+product DLINK DWA182C1 0x3315 DWA-182 rev C1
+product DLINK DWA180A1 0x3316 DWA-180 rev A1
+product DLINK DWA172A1 0x3318 DWA-172 rev A1
+product DLINK DWA131E1 0x3319 DWA-131 rev E1
product DLINK DWL122 0x3700 DWL-122
product DLINK DWLG120 0x3701 DWL-G120
product DLINK DWL120F 0x3702 DWL-120 rev F
@@ -1173,26 +1719,126 @@ product DLINK DWLAG122 0x3a04 DWL-AG122
product DLINK DWLAG122_NF 0x3a05 DWL-AG122 (no firmware)
product DLINK DWLG122 0x3c00 DWL-G122 b1 Wireless Adapter
product DLINK DUBE100B1 0x3c05 DUB-E100 rev B1
+product DLINK RT2870 0x3c09 RT2870
+product DLINK RT3072 0x3c0a RT3072
+product DLINK DWA140B3 0x3c15 DWA-140 rev B3
+product DLINK DWA125A3 0x3c19 DWA-125 rev A3
+product DLINK DWA160B2 0x3c1a DWA-160 rev B2
+product DLINK DWA127 0x3c1b DWA-127 Wireless Adapter
+product DLINK DWA162 0x3c1f DWA-162 Wireless Adapter
+product DLINK DWA140D1 0x3c20 DWA-140 rev D1
product DLINK DSB650C 0x4000 10Mbps Ethernet
product DLINK DSB650TX1 0x4001 10/100 Ethernet
product DLINK DSB650TX 0x4002 10/100 Ethernet
product DLINK DSB650TX_PNA 0x4003 1/10/100 Ethernet
product DLINK DSB650TX3 0x400b 10/100 Ethernet
product DLINK DSB650TX2 0x4102 10/100 Ethernet
+product DLINK DUB1312 0x4a00 10/100/1000 Ethernet
+product DLINK DWM157 0x7d02 DWM-157
+product DLINK DWR510 0x7e12 DWR-510
+product DLINK DWM222 0x7e35 DWM-222
+product DLINK DWM157_CD 0xa707 DWM-157 CD-ROM Mode
+product DLINK DWR510_CD 0xa805 DWR-510 CD-ROM Mode
+product DLINK DWM222_CD 0xab00 DWM-222 CD-ROM Mode
product DLINK DSB650 0xabc1 10/100 Ethernet
+product DLINK DUBH7 0xf103 DUB-H7 USB 2.0 7-Port Hub
+product DLINK2 RTL8192SU_1 0x3300 RTL8192SU
+product DLINK2 RTL8192SU_2 0x3302 RTL8192SU
+product DLINK2 DWA131A1 0x3303 DWA-131 A1
+product DLINK2 DWA160A2 0x3a09 DWA-160 A2
+product DLINK2 DWA120 0x3a0c DWA-120
+product DLINK2 DWA120_NF 0x3a0d DWA-120 (no firmware)
+product DLINK2 DWA130D1 0x3a0f DWA-130 D1
product DLINK2 DWLG122C1 0x3c03 DWL-G122 c1
product DLINK2 WUA1340 0x3c04 WUA-1340
product DLINK2 DWA111 0x3c06 DWA-111
product DLINK2 DWA110 0x3c07 DWA-110
+product DLINK2 RT2870_1 0x3c09 RT2870
+product DLINK2 RT3072 0x3c0a RT3072
+product DLINK2 RT3072_1 0x3c0b RT3072
+product DLINK2 RT3070_1 0x3c0d RT3070
+product DLINK2 RT3070_2 0x3c0e RT3070
+product DLINK2 RT3070_3 0x3c0f RT3070
+product DLINK2 DWA160A1 0x3c10 DWA-160 A1
+product DLINK2 RT2870_2 0x3c11 RT2870
+product DLINK2 DWA130 0x3c13 DWA-130
+product DLINK2 RT3070_4 0x3c15 RT3070
+product DLINK2 RT3070_5 0x3c16 RT3070
+product DLINK3 DWM652 0x3e04 DWM-652
+
+/* DisplayLink products */
+product DISPLAYLINK LCD4300U 0x01ba LCD-4300U
+product DISPLAYLINK LCD8000U 0x01bb LCD-8000U
+product DISPLAYLINK LD220 0x0100 Samsung LD220
+product DISPLAYLINK GUC2020 0x0059 IOGEAR DVI GUC2020
+product DISPLAYLINK VCUD60 0x0136 Rextron DVI
+product DISPLAYLINK CONV 0x0138 StarTech CONV-USB2DVI
+product DISPLAYLINK DLDVI 0x0141 DisplayLink DVI
+product DISPLAYLINK VGA10 0x015a CMP-USBVGA10
+product DISPLAYLINK WSDVI 0x0198 WS Tech DVI
+product DISPLAYLINK EC008 0x019b EasyCAP008 DVI
+product DISPLAYLINK HPDOCK 0x01d4 HP USB Docking
+product DISPLAYLINK NL571 0x01d7 HP USB DVI
+product DISPLAYLINK M01061 0x01e2 Lenovo DVI
+product DISPLAYLINK SWDVI 0x024c SUNWEIT DVI
+product DISPLAYLINK NBDOCK 0x0215 VideoHome NBdock1920
+product DISPLAYLINK LUM70 0x02a9 Lilliput UM-70
+product DISPLAYLINK UM7X0 0x401a nanovision MiMo
+product DISPLAYLINK LT1421 0x03e0 Lenovo ThinkVision LT1421
+product DISPLAYLINK POLARIS2 0x0117 Polaris2 USB dock
+product DISPLAYLINK PLUGABLE 0x0377 Plugable docking station
+product DISPLAYLINK ITEC 0x02e9 i-tec USB 2.0 Docking Station
/* DMI products */
product DMI CFSM_RW 0xa109 CF/SM Reader/Writer
+product DMI DISK 0x2bcf Generic Disk
/* DrayTek products */
product DRAYTEK VIGOR550 0x0550 Vigor550
+/* Dream Link products */
+product DREAMLINK DL100B 0x0004 USB Webmail Notifier
+
+/* dresden elektronik products */
+product DRESDENELEKTRONIK SENSORTERMINALBOARD 0x0001 SensorTerminalBoard
+product DRESDENELEKTRONIK WIRELESSHANDHELDTERMINAL 0x0004 Wireless Handheld Terminal
+product DRESDENELEKTRONIK DE_RFNODE 0x001c deRFnode
+product DRESDENELEKTRONIK LEVELSHIFTERSTICKLOWCOST 0x0022 Levelshifter Stick Low Cost
+
+/* DYMO */
+product DYMO LABELMANAGERPNP 0x1001 DYMO LabelManager PnP
+
/* Dynastream Innovations */
product DYNASTREAM ANTDEVBOARD 0x1003 ANT dev board
+product DYNASTREAM ANT2USB 0x1004 ANT2USB
+product DYNASTREAM ANTDEVBOARD2 0x1006 ANT dev board
+
+/* Edimax products */
+product EDIMAX EW7318USG 0x7318 USB Wireless dongle
+product EDIMAX RTL8192SU_1 0x7611 RTL8192SU
+product EDIMAX RTL8192SU_2 0x7612 RTL8192SU
+product EDIMAX EW7622UMN 0x7622 EW-7622UMn
+product EDIMAX RT2870_1 0x7711 RT2870
+product EDIMAX EW7717 0x7717 EW-7717
+product EDIMAX EW7718 0x7718 EW-7718
+product EDIMAX EW7733UND 0x7733 EW-7733UnD
+product EDIMAX EW7811UN 0x7811 EW-7811Un
+product EDIMAX RTL8192CU 0x7822 RTL8192CU
+product EDIMAX EW7811UTC_1 0xa811 EW-7811UTC
+product EDIMAX EW7811UTC_2 0xa812 EW-7811UTC
+product EDIMAX EW7822UAC 0xa822 EW-7822UAC
+
+/* eGalax Products */
+product EGALAX TPANEL 0x0001 Touch Panel
+product EGALAX TPANEL2 0x0002 Touch Panel
+product EGALAX2 TPANEL 0x0001 Touch Panel
+
+/* EGO Products */
+product EGO DUMMY 0x0000 Dummy Product
+product EGO M4U 0x1020 ESI M4U
+
+/* Eicon Networks */
+product EICON DIVA852 0x4905 Diva 852 ISDN TA
/* EIZO products */
product EIZO HUB 0x0000 hub
@@ -1206,19 +1852,34 @@ product ELECOM MOUSE29UO 0x0002 mouse 29UO
product ELECOM LDUSBTX0 0x200c LD-USB/TX
product ELECOM LDUSBTX1 0x4002 LD-USB/TX
product ELECOM LDUSBLTX 0x4005 LD-USBL/TX
+product ELECOM WDC150SU2M 0x4008 WDC-150SU2M
product ELECOM LDUSBTX2 0x400b LD-USB/TX
product ELECOM LDUSB20 0x4010 LD-USB20
product ELECOM UCSGT 0x5003 UC-SGT
product ELECOM UCSGT0 0x5004 UC-SGT
product ELECOM LDUSBTX3 0xabc1 LD-USB/TX
+/* Elektor products */
+product ELEKTOR FT323R 0x0005 FTDI compatible adapter
+
/* Elsa products */
product ELSA MODEM1 0x2265 ELSA Modem Board
product ELSA USB2ETHERNET 0x3000 Microlink USB2Ethernet
+/* ELV products */
+product ELV USBI2C 0xe00f USB-I2C interface
+
/* EMS products */
product EMS DUAL_SHOOTER 0x0003 PSX gun controller converter
+/* Emtec products */
+product EMTEC RUF2PS 0x2240 Flash Drive
+
+/* Encore products */
+product ENCORE RT3070_1 0x1480 RT3070
+product ENCORE RT3070_2 0x14a1 RT3070
+product ENCORE RT3070_3 0x14a9 RT3070
+
/* Entrega products */
product ENTREGA 1S 0x0001 1S serial
product ENTREGA 2S 0x0002 2S serial
@@ -1229,10 +1890,10 @@ product ENTREGA CENTRONICS 0x0006 Parallel Port
product ENTREGA XX1 0x0008 Ethernet
product ENTREGA 1S9 0x0093 1S9 serial
product ENTREGA EZUSB 0x8000 EZ-USB
-/* product ENTREGA SERIAL 0x8001 DB25 Serial */
+/*product ENTREGA SERIAL 0x8001 DB25 Serial*/
product ENTREGA 2U4S 0x8004 2U4S serial/usb hub
product ENTREGA XX2 0x8005 Ethernet
-/* product ENTREGA SERIAL_DB9 0x8093 DB9 Serial */
+/*product ENTREGA SERIAL_DB9 0x8093 DB9 Serial*/
/* Epson products */
product EPSON PRINTER1 0x0001 USB Printer
@@ -1258,52 +1919,103 @@ product EPSON 1270 0x0120 Perfection 1270 scanner
product EPSON 2480 0x0121 Perfection 2480 scanner
product EPSON 3590 0x0122 Perfection 3590 scanner
product EPSON 4990 0x012a Perfection 4990 Photo scanner
+product EPSON CRESSI_EDY 0x0521 Cressi Edy diving computer
+product EPSON N2ITION3 0x0522 Zeagle N2iTion3 diving computer
product EPSON STYLUS_875DC 0x0601 Stylus Photo 875DC Card Reader
product EPSON STYLUS_895 0x0602 Stylus Photo 895 Card Reader
product EPSON CX5400 0x0808 CX5400 scanner
product EPSON 3500 0x080e CX-3500/3600/3650 MFP
product EPSON RX425 0x080f Stylus Photo RX425 scanner
-product EPSON 4800 0x0819 CX4800 MP scanner
-product EPSON 4200 0x0820 CX4200 MP scanner
-product EPSON 5000 0x082b DX-50x0 MFP scanner
-product EPSON 6000 0x082e DX-60x0 MFP scanner
-product EPSON DX7400 0x0838 DX7400/CX7300 scanner
-product EPSON DX8400 0x0839 DX8400 scanner
+product EPSON DX3800 0x0818 CX3700/CX3800/DX38x0 MFP scanner
+product EPSON 4800 0x0819 CX4700/CX4800/DX48x0 MFP scanner
+product EPSON 4200 0x0820 CX4100/CX4200/DX4200 MFP scanner
+product EPSON 5000 0x082b CX4900/CX5000/DX50x0 MFP scanner
+product EPSON 6000 0x082e CX5900/CX6000/DX60x0 MFP scanner
+product EPSON DX4000 0x082f DX4000 MFP scanner
+product EPSON DX7400 0x0838 CX7300/CX7400/DX7400 MFP scanner
+product EPSON DX8400 0x0839 CX8300/CX8400/DX8400 MFP scanner
+product EPSON SX100 0x0841 SX100/NX100 MFP scanner
+product EPSON NX300 0x0848 NX300 MFP scanner
+product EPSON SX200 0x0849 SX200/SX205 MFP scanner
+product EPSON SX400 0x084a SX400/NX400/TX400 MFP scanner
/* e-TEK Labs products */
product ETEK 1COM 0x8007 Serial
+/* Evolution products */
+product EVOLUTION ER1 0x0300 FTDI compatible adapter
+product EVOLUTION HYBRID 0x0302 FTDI compatible adapter
+product EVOLUTION RCM4 0x0303 FTDI compatible adapter
+
/* Extended Systems products */
product EXTENDED XTNDACCESS 0x0100 XTNDAccess IrDA
+/* Falcom products */
+product FALCOM TWIST 0x0001 USB GSM/GPRS Modem
+product FALCOM SAMBA 0x0005 FTDI compatible adapter
+
/* FEIYA products */
+product FEIYA DUMMY 0x0000 Dummy product
product FEIYA 5IN1 0x1132 5-in-1 Card Reader
+product FEIYA ELANGO 0x6200 MicroSDHC Card Reader
+product FEIYA AC110 0x6300 AC-110 Card Reader
+
+/* FeiXun Communication products */
+product FEIXUN RTL8188CU 0x0090 RTL8188CU
+product FEIXUN RTL8192CU 0x0091 RTL8192CU
+
+/* Festo */
+product FESTO CPX_USB 0x0102 CPX-USB
+product FESTO CMSP 0x0501 CMSP
/* Fiberline */
product FIBERLINE WL430U 0x6003 WL-430U
+/* FIC / OpenMoko */
+product FIC NEO1973_DEBUG 0x5118 FTDI compatible adapter
+
/* Fossil, Inc products */
product FOSSIL WRISTPDA 0x0002 Wrist PDA
+/* Foxconn products */
+product FOXCONN TCOM_TC_300 0xe000 T-Com TC 300
+product FOXCONN PIRELLI_DP_L10 0xe003 Pirelli DP-L10
+
/* Freecom products */
product FREECOM DVD 0xfc01 DVD drive
+product FREECOM HDD 0xfc05 Classic SL Hard Drive
/* Fujitsu Siemens Computers products */
product FSC E5400 0x1009 PrismGT USB 2.0 WLAN
/* Future Technology Devices products */
+product FTDI SCX8_USB_PHOENIX 0x5259 SCx8 USB Phoenix interface
product FTDI SERIAL_8U100AX 0x8372 8U100AX Serial
product FTDI SERIAL_8U232AM 0x6001 8U232AM Serial
+product FTDI SERIAL_8U232AM4 0x6004 8U232AM Serial
+product FTDI SERIAL_232RL 0x6006 FT232RL Serial
product FTDI SERIAL_2232C 0x6010 FT2232C Dual port Serial
+product FTDI 232H 0x6014 FTDI compatible adapter
+product FTDI 232EX 0x6015 FTDI compatible adapter
+product FTDI SERIAL_2232D 0x9e90 FT2232D Dual port Serial
+product FTDI SERIAL_4232H 0x6011 FT4232H Quad port Serial
+product FTDI XDS100V2 0xa6d0 TI XDS100V1/V2 and early Beaglebones
+product FTDI XDS100V3 0xa6d1 TI XDS100V3
+product FTDI KTLINK 0xbbe2 KT-LINK Embedded Hackers Multitool
+product FTDI TURTELIZER2 0xbdc8 egnite Turtelizer 2 JTAG/RS232 Adapter
/* Gude Analog- und Digitalsysteme products also uses FTDI's id: */
product FTDI TACTRIX_OPENPORT_13M 0xcc48 OpenPort 1.3 Mitsubishi
product FTDI TACTRIX_OPENPORT_13S 0xcc49 OpenPort 1.3 Subaru
product FTDI TACTRIX_OPENPORT_13U 0xcc4a OpenPort 1.3 Universal
+product FTDI GAMMASCOUT 0xd678 Gamma-Scout
+product FTDI KBS 0xe6c8 Pyramid KBS USB LCD
product FTDI EISCOU 0xe888 Expert ISDN Control USB
product FTDI UOPTBR 0xe889 USB-RS232 OptoBridge
product FTDI EMCU2D 0xe88a Expert mouseCLOCK USB II
product FTDI PCMSFU 0xe88b Precision Clock MSF USB
product FTDI EMCU2H 0xe88c Expert mouseCLOCK USB II HBG
+product FTDI MAXSTREAM 0xee18 Maxstream PKG-U
+product FTDI USB_UIRT 0xf850 USB-UIRT
product FTDI USBSERIAL 0xfa00 Matrix Orbital USB Serial
product FTDI MX2_3 0xfa01 Matrix Orbital MX2 or MX3
product FTDI MX4_5 0xfa02 Matrix Orbital MX4 or MX5
@@ -1315,6 +2027,209 @@ product FTDI CFA_633 0xfc0b Crystalfontz CFA-633 USB LCD
product FTDI CFA_631 0xfc0c Crystalfontz CFA-631 USB LCD
product FTDI CFA_635 0xfc0d Crystalfontz CFA-635 USB LCD
product FTDI SEMC_DSS20 0xfc82 SEMC DSS-20 SyncStation
+/* Commerzielle und Technische Informationssysteme GmbH products */
+product FTDI CTI_USB_NANO_485 0xf60b CTI USB-Nano 485
+product FTDI CTI_USB_MINI_485 0xf608 CTI USB-Mini 485
+/* Other products */
+product FTDI 232RL 0xfbfa FTDI compatible adapter
+product FTDI 4N_GALAXY_DE_1 0xf3c0 FTDI compatible adapter
+product FTDI 4N_GALAXY_DE_2 0xf3c1 FTDI compatible adapter
+product FTDI 4N_GALAXY_DE_3 0xf3c2 FTDI compatible adapter
+product FTDI 8U232AM_ALT 0x6006 FTDI compatible adapter
+product FTDI ACCESSO 0xfad0 FTDI compatible adapter
+product FTDI ACG_HFDUAL 0xdd20 FTDI compatible adapter
+product FTDI ACTIVE_ROBOTS 0xe548 FTDI compatible adapter
+product FTDI ACTZWAVE 0xf2d0 FTDI compatible adapter
+product FTDI AMC232 0xff00 FTDI compatible adapter
+product FTDI ARTEMIS 0xdf28 FTDI compatible adapter
+product FTDI ASK_RDR400 0xc991 FTDI compatible adapter
+product FTDI ATIK_ATK16 0xdf30 FTDI compatible adapter
+product FTDI ATIK_ATK16C 0xdf32 FTDI compatible adapter
+product FTDI ATIK_ATK16HR 0xdf31 FTDI compatible adapter
+product FTDI ATIK_ATK16HRC 0xdf33 FTDI compatible adapter
+product FTDI ATIK_ATK16IC 0xdf35 FTDI compatible adapter
+product FTDI BCS_SE923 0xfb99 FTDI compatible adapter
+product FTDI CANDAPTER 0x9f80 FTDI compatible adapter
+product FTDI CANUSB 0xffa8 FTDI compatible adapter
+product FTDI CCSICDU20_0 0xf9d0 FTDI compatible adapter
+product FTDI CCSICDU40_1 0xf9d1 FTDI compatible adapter
+product FTDI CCSICDU64_4 0xf9d4 FTDI compatible adapter
+product FTDI CCSLOAD_N_GO_3 0xf9d3 FTDI compatible adapter
+product FTDI CCSMACHX_2 0xf9d2 FTDI compatible adapter
+product FTDI CCSPRIME8_5 0xf9d5 FTDI compatible adapter
+product FTDI CHAMSYS_24_MASTER_WING 0xdaf8 FTDI compatible adapter
+product FTDI CHAMSYS_MAXI_WING 0xdafd FTDI compatible adapter
+product FTDI CHAMSYS_MEDIA_WING 0xdafe FTDI compatible adapter
+product FTDI CHAMSYS_MIDI_TIMECODE 0xdafb FTDI compatible adapter
+product FTDI CHAMSYS_MINI_WING 0xdafc FTDI compatible adapter
+product FTDI CHAMSYS_PC_WING 0xdaf9 FTDI compatible adapter
+product FTDI CHAMSYS_USB_DMX 0xdafa FTDI compatible adapter
+product FTDI CHAMSYS_WING 0xdaff FTDI compatible adapter
+product FTDI COM4SM 0xd578 FTDI compatible adapter
+product FTDI CONVERTER_0 0xd388 FTDI compatible adapter
+product FTDI CONVERTER_1 0xd389 FTDI compatible adapter
+product FTDI CONVERTER_2 0xd38a FTDI compatible adapter
+product FTDI CONVERTER_3 0xd38b FTDI compatible adapter
+product FTDI CONVERTER_4 0xd38c FTDI compatible adapter
+product FTDI CONVERTER_5 0xd38d FTDI compatible adapter
+product FTDI CONVERTER_6 0xd38e FTDI compatible adapter
+product FTDI CONVERTER_7 0xd38f FTDI compatible adapter
+product FTDI DMX4ALL 0xc850 FTDI compatible adapter
+product FTDI DOMINTELL_DGQG 0xef50 FTDI compatible adapter
+product FTDI DOMINTELL_DUSB 0xef51 FTDI compatible adapter
+product FTDI DOTEC 0x9868 FTDI compatible adapter
+product FTDI ECLO_COM_1WIRE 0xea90 FTDI compatible adapter
+product FTDI ECO_PRO_CDS 0xe520 FTDI compatible adapter
+product FTDI ELSTER_UNICOM 0xe700 FTDI compatible adapter
+product FTDI ELV_ALC8500 0xf06e FTDI compatible adapter
+product FTDI ELV_CLI7000 0xfb59 FTDI compatible adapter
+product FTDI ELV_CSI8 0xe0f0 FTDI compatible adapter
+product FTDI ELV_EC3000 0xe006 FTDI compatible adapter
+product FTDI ELV_EM1000DL 0xe0f1 FTDI compatible adapter
+product FTDI ELV_EM1010PC 0xe0ef FTDI compatible adapter
+product FTDI ELV_FEM 0xe00a FTDI compatible adapter
+product FTDI ELV_FHZ1000PC 0xf06f FTDI compatible adapter
+product FTDI ELV_FHZ1300PC 0xe0e8 FTDI compatible adapter
+product FTDI ELV_FM3RX 0xe0ed FTDI compatible adapter
+product FTDI ELV_FS20SIG 0xe0f4 FTDI compatible adapter
+product FTDI ELV_HS485 0xe0ea FTDI compatible adapter
+product FTDI ELV_KL100 0xe002 FTDI compatible adapter
+product FTDI ELV_MSM1 0xe001 FTDI compatible adapter
+product FTDI ELV_PCD200 0xf06c FTDI compatible adapter
+product FTDI ELV_PCK100 0xe0f2 FTDI compatible adapter
+product FTDI ELV_PPS7330 0xfb5c FTDI compatible adapter
+product FTDI ELV_RFP500 0xe0f3 FTDI compatible adapter
+product FTDI ELV_T1100 0xf06b FTDI compatible adapter
+product FTDI ELV_TFD128 0xe0ec FTDI compatible adapter
+product FTDI ELV_TFM100 0xfb5d FTDI compatible adapter
+product FTDI ELV_TWS550 0xe009 FTDI compatible adapter
+product FTDI ELV_UAD8 0xf068 FTDI compatible adapter
+product FTDI ELV_UDA7 0xf069 FTDI compatible adapter
+product FTDI ELV_UDF77 0xfb5e FTDI compatible adapter
+product FTDI ELV_UIO88 0xfb5f FTDI compatible adapter
+product FTDI ELV_ULA200 0xf06d FTDI compatible adapter
+product FTDI ELV_UM100 0xfb5a FTDI compatible adapter
+product FTDI ELV_UMS100 0xe0eb FTDI compatible adapter
+product FTDI ELV_UO100 0xfb5b FTDI compatible adapter
+product FTDI ELV_UR100 0xfb58 FTDI compatible adapter
+product FTDI ELV_USI2 0xf06a FTDI compatible adapter
+product FTDI ELV_USR 0xe000 FTDI compatible adapter
+product FTDI ELV_UTP8 0xe0f5 FTDI compatible adapter
+product FTDI ELV_WS300PC 0xe0f6 FTDI compatible adapter
+product FTDI ELV_WS444PC 0xe0f7 FTDI compatible adapter
+product FTDI ELV_WS500 0xe0e9 FTDI compatible adapter
+product FTDI ELV_WS550 0xe004 FTDI compatible adapter
+product FTDI ELV_WS777 0xe0ee FTDI compatible adapter
+product FTDI ELV_WS888 0xe008 FTDI compatible adapter
+product FTDI FUTURE_0 0xf44a FTDI compatible adapter
+product FTDI FUTURE_1 0xf44b FTDI compatible adapter
+product FTDI FUTURE_2 0xf44c FTDI compatible adapter
+product FTDI GENERIC 0x9378 FTDI compatible adapter
+product FTDI GUDEADS_E808 0xe808 FTDI compatible adapter
+product FTDI GUDEADS_E809 0xe809 FTDI compatible adapter
+product FTDI GUDEADS_E80A 0xe80a FTDI compatible adapter
+product FTDI GUDEADS_E80B 0xe80b FTDI compatible adapter
+product FTDI GUDEADS_E80C 0xe80c FTDI compatible adapter
+product FTDI GUDEADS_E80D 0xe80d FTDI compatible adapter
+product FTDI GUDEADS_E80E 0xe80e FTDI compatible adapter
+product FTDI GUDEADS_E80F 0xe80f FTDI compatible adapter
+product FTDI GUDEADS_E88D 0xe88d FTDI compatible adapter
+product FTDI GUDEADS_E88E 0xe88e FTDI compatible adapter
+product FTDI GUDEADS_E88F 0xe88f FTDI compatible adapter
+product FTDI HD_RADIO 0x937c FTDI compatible adapter
+product FTDI HO720 0xed72 FTDI compatible adapter
+product FTDI HO730 0xed73 FTDI compatible adapter
+product FTDI HO820 0xed74 FTDI compatible adapter
+product FTDI HO870 0xed71 FTDI compatible adapter
+product FTDI IBS_APP70 0xff3d FTDI compatible adapter
+product FTDI IBS_PCMCIA 0xff3a FTDI compatible adapter
+product FTDI IBS_PEDO 0xff3e FTDI compatible adapter
+product FTDI IBS_PICPRO 0xff39 FTDI compatible adapter
+product FTDI IBS_PK1 0xff3b FTDI compatible adapter
+product FTDI IBS_PROD 0xff3f FTDI compatible adapter
+product FTDI IBS_RS232MON 0xff3c FTDI compatible adapter
+product FTDI IBS_US485 0xff38 FTDI compatible adapter
+product FTDI IPLUS 0xd070 FTDI compatible adapter
+product FTDI IPLUS2 0xd071 FTDI compatible adapter
+product FTDI IRTRANS 0xfc60 FTDI compatible adapter
+product FTDI LENZ_LIUSB 0xd780 FTDI compatible adapter
+product FTDI LM3S_DEVEL_BOARD 0xbcd8 FTDI compatible adapter
+product FTDI LM3S_EVAL_BOARD 0xbcd9 FTDI compatible adapter
+product FTDI LM3S_ICDI_B_BOARD 0xbcda FTDI compatible adapter
+product FTDI MASTERDEVEL2 0xf449 FTDI compatible adapter
+product FTDI MHAM_DB9 0xeeed FTDI compatible adapter
+product FTDI MHAM_IC 0xeeec FTDI compatible adapter
+product FTDI MHAM_KW 0xeee8 FTDI compatible adapter
+product FTDI MHAM_RS232 0xeeee FTDI compatible adapter
+product FTDI MHAM_Y6 0xeeea FTDI compatible adapter
+product FTDI MHAM_Y8 0xeeeb FTDI compatible adapter
+product FTDI MHAM_Y9 0xeeef FTDI compatible adapter
+product FTDI MHAM_YS 0xeee9 FTDI compatible adapter
+product FTDI MICRO_CHAMELEON 0xcaa0 FTDI compatible adapter
+product FTDI MTXORB_5 0xfa05 FTDI compatible adapter
+product FTDI MTXORB_6 0xfa06 FTDI compatible adapter
+product FTDI NXTCAM 0xabb8 FTDI compatible adapter
+product FTDI OCEANIC 0xf460 FTDI compatible adapter
+product FTDI OOCDLINK 0xbaf8 FTDI compatible adapter
+product FTDI OPENDCC 0xbfd8 FTDI compatible adapter
+product FTDI OPENDCC_GATEWAY 0xbfdb FTDI compatible adapter
+product FTDI OPENDCC_GBM 0xbfdc FTDI compatible adapter
+product FTDI OPENDCC_SNIFFER 0xbfd9 FTDI compatible adapter
+product FTDI OPENDCC_THROTTLE 0xbfda FTDI compatible adapter
+product FTDI PCDJ_DAC2 0xfa88 FTDI compatible adapter
+product FTDI PERLE_ULTRAPORT 0xf0c0 FTDI compatible adapter
+product FTDI PHI_FISCO 0xe40b FTDI compatible adapter
+product FTDI PIEGROUP 0xf208 FTDI compatible adapter
+product FTDI PROPOX_JTAGCABLEII 0xd738 FTDI compatible adapter
+product FTDI R2000KU_TRUE_RNG 0xfb80 FTDI compatible adapter
+product FTDI R2X0 0xfc71 FTDI compatible adapter
+product FTDI RELAIS 0xfa10 FTDI compatible adapter
+product FTDI REU_TINY 0xed22 FTDI compatible adapter
+product FTDI RMP200 0xe729 FTDI compatible adapter
+product FTDI RM_CANVIEW 0xfd60 FTDI compatible adapter
+product FTDI RRCIRKITS_LOCOBUFFER 0xc7d0 FTDI compatible adapter
+product FTDI SCIENCESCOPE_HS_LOGBOOK 0xff1d FTDI compatible adapter
+product FTDI SCIENCESCOPE_LOGBOOKML 0xff18 FTDI compatible adapter
+product FTDI SCIENCESCOPE_LS_LOGBOOK 0xff1c FTDI compatible adapter
+product FTDI SCS_DEVICE_0 0xd010 FTDI compatible adapter
+product FTDI SCS_DEVICE_1 0xd011 FTDI compatible adapter
+product FTDI SCS_DEVICE_2 0xd012 FTDI compatible adapter
+product FTDI SCS_DEVICE_3 0xd013 FTDI compatible adapter
+product FTDI SCS_DEVICE_4 0xd014 FTDI compatible adapter
+product FTDI SCS_DEVICE_5 0xd015 FTDI compatible adapter
+product FTDI SCS_DEVICE_6 0xd016 FTDI compatible adapter
+product FTDI SCS_DEVICE_7 0xd017 FTDI compatible adapter
+product FTDI SDMUSBQSS 0xf448 FTDI compatible adapter
+product FTDI SIGNALYZER_SH2 0xbca2 FTDI compatible adapter
+product FTDI SIGNALYZER_SH4 0xbca4 FTDI compatible adapter
+product FTDI SIGNALYZER_SLITE 0xbca1 FTDI compatible adapter
+product FTDI SIGNALYZER_ST 0xbca0 FTDI compatible adapter
+product FTDI SPECIAL_1 0xfc70 FTDI compatible adapter
+product FTDI SPECIAL_3 0xfc72 FTDI compatible adapter
+product FTDI SPECIAL_4 0xfc73 FTDI compatible adapter
+product FTDI SPROG_II 0xf0c8 FTDI compatible adapter
+product FTDI SR_RADIO 0x9379 FTDI compatible adapter
+product FTDI SUUNTO_SPORTS 0xf680 FTDI compatible adapter
+product FTDI TAVIR_STK500 0xfa33 FTDI compatible adapter
+product FTDI TERATRONIK_D2XX 0xec89 FTDI compatible adapter
+product FTDI TERATRONIK_VCP 0xec88 FTDI compatible adapter
+product FTDI THORLABS 0xfaf0 FTDI compatible adapter
+product FTDI TIAO 0x8a98 FTDI compatible adapter
+product FTDI TNC_X 0xebe0 FTDI compatible adapter
+product FTDI TTUSB 0xff20 FTDI compatible adapter
+product FTDI USBX_707 0xf857 FTDI compatible adapter
+product FTDI USINT_CAT 0xb810 FTDI compatible adapter
+product FTDI USINT_RS232 0xb812 FTDI compatible adapter
+product FTDI USINT_WKEY 0xb811 FTDI compatible adapter
+product FTDI VARDAAN 0xf070 FTDI compatible adapter
+product FTDI VNHCPCUSB_D 0xfe38 FTDI compatible adapter
+product FTDI WESTREX_MODEL_777 0xdc00 FTDI compatible adapter
+product FTDI WESTREX_MODEL_8900F 0xdc01 FTDI compatible adapter
+product FTDI XF_547 0xfc0a FTDI compatible adapter
+product FTDI XF_640 0xfc0e FTDI compatible adapter
+product FTDI XF_642 0xfc0f FTDI compatible adapter
+product FTDI XM_RADIO 0x937a FTDI compatible adapter
+product FTDI YEI_SERVOCENTER31 0xe050 FTDI compatible adapter
/* Fuji photo products */
product FUJIPHOTO MASS0100 0x0100 Mass Storage
@@ -1322,18 +2237,30 @@ product FUJIPHOTO MASS0100 0x0100 Mass Storage
/* Fujitsu protducts */
product FUJITSU AH_F401U 0x105b AH-F401U Air H device
+/* Fujitsu-Siemens protducts */
+product FUJITSUSIEMENS SCR 0x0009 Fujitsu-Siemens SCR USB Reader
+
/* Garmin products */
+product GARMIN FORERUNNER230 0x086d ForeRunner 230
product GARMIN IQUE_3600 0x0004 iQue 3600
+/* Gemalto products */
+product GEMALTO PROXPU 0x5501 Prox-PU/CU RFID Card Reader
+
/* General Instruments (Motorola) products */
product GENERALINSTMNTS SB5100 0x5100 SURFboard SB5100 Cable modem
/* Genesys Logic products */
product GENESYS GL620USB 0x0501 GL620USB Host-Host interface
-product GENESYS GL650 0x0604 GL650 Hub
+product GENESYS GL650 0x0604 GL650 HUB
+product GENESYS GL606 0x0606 GL606 USB 2.0 HUB
+product GENESYS GL850G 0x0608 GL850G USB 2.0 HUB
+product GENESYS GL3520_2 0x0610 GL3520 4-Port USB 2.0 DataPath
+product GENESYS GL3520_SS 0x0616 GL3520 4-Port USB 3.0 DataPath
product GENESYS GL641USB 0x0700 GL641USB CompactFlash Card Reader
product GENESYS GL641USB2IDE_2 0x0701 GL641USB USB-IDE Bridge No 2
product GENESYS GL641USB2IDE 0x0702 GL641USB USB-IDE Bridge
+product GENESYS GL3233 0x0743 GL3233 USB 3.0 AiO Card Reader
product GENESYS GL641USB_2 0x0760 GL641USB 6-in-1 Card Reader
/* GIGABYTE products */
@@ -1351,6 +2278,11 @@ product GIGASET SMCWUSBTG_NF 0x0711 SMCWUSBT-G (no firmware)
product GIGASET AR5523 0x0712 AR5523
product GIGASET AR5523_NF 0x0713 AR5523 (no firmware)
product GIGASET RT2573 0x0722 RT2573
+product GIGASET RT3070_1 0x0740 RT3070
+product GIGASET RT3070_2 0x0744 RT3070
+product GIGABYTE RT2870_1 0x800b RT2870
+product GIGABYTE GNWB31N 0x800c GN-WB31N
+product GIGABYTE GNWB32L 0x800d GN-WB32L
/* Global Sun Technology product */
product GLOBALSUN AR5523_1 0x7801 AR5523
@@ -1359,12 +2291,16 @@ product GLOBALSUN AR5523_2 0x7811 AR5523
product GLOBALSUN AR5523_2_NF 0x7812 AR5523 (no firmware)
/* Globespan products */
+product GLOBESPAN MODEM_1 0x1329 USB Modem
product GLOBESPAN PRISM_GT_1 0x2000 PrismGT USB 2.0 WLAN
product GLOBESPAN PRISM_GT_2 0x2002 PrismGT USB 2.0 WLAN
/* G.Mate, Inc products */
product GMATE YP3X00 0x1001 YP3X00 PDA
+/* GN Otometrics */
+product GNOTOMETRICS USB 0x0010 FTDI compatible adapter
+
/* GoHubs products */
product GOHUBS GOCOM232 0x1001 GoCOM232 Serial
@@ -1372,6 +2308,9 @@ product GOHUBS GOCOM232 0x1001 GoCOM232 Serial
product GOODWAY GWUSB2E 0x6200 GWUSB2E
product GOODWAY RT2573 0xc019 RT2573
+/* Google products */
+product GOOGLE NEXUSONE 0x4e11 Nexus One
+
/* Gravis products */
product GRAVIS GAMEPADPRO 0x4001 GamePad Pro
@@ -1386,6 +2325,10 @@ product GUILLEMOT DALEADER 0xa300 DA Leader
product GUILLEMOT HWGUSB254 0xe000 HWGUSB2-54 WLAN
product GUILLEMOT HWGUSB254LB 0xe010 HWGUSB2-54-LB
product GUILLEMOT HWGUSB254V2AP 0xe020 HWGUSB2-54V2-AP
+product GUILLEMOT HWNU300 0xe030 HWNU-300
+product GUILLEMOT HWNUM300 0xe031 HWNUm-300
+product GUILLEMOT HWGUN54 0xe032 HWGUn-54
+product GUILLEMOT HWNUP150 0xe033 HWNUP-150
/* Hagiwara products */
product HAGIWARA FGSM 0x0002 FlashGate SmartMedia Card Reader
@@ -1402,14 +2345,33 @@ product HANDSPRING TREO600 0x0300 Handspring Treo 600
/* Hauppauge Computer Works */
product HAUPPAUGE WINTV_USB_FM 0x4d12 WinTV USB FM
+product HAUPPAUGE2 NOVAT500 0x9580 NovaT 500Stick
/* Hawking Technologies products */
+product HAWKING RT2870_1 0x0001 RT2870
+product HAWKING RT2870_2 0x0003 RT2870
+product HAWKING HWUN2 0x0009 HWUN2
+product HAWKING RT3070 0x000b RT3070
+product HAWKING RTL8192CU 0x0019 RTL8192CU
product HAWKING UF100 0x400c 10/100 USB Ethernet
+product HAWKING RTL8192SU_1 0x0015 RTL8192SU
+product HAWKING RTL8192SU_2 0x0016 RTL8192SU
+product HAWKING HD65U 0x0023 HD65U
+
+/* HID Global GmbH products */
+product HIDGLOBAL CM2020 0x0596 Omnikey Cardman 2020
+product HIDGLOBAL CM6020 0x1784 Omnikey Cardman 6020
/* Hitachi, Ltd. products */
product HITACHI DVDCAM_DZ_MV100A 0x0004 DVD-CAM DZ-MV100A Camcorder
product HITACHI DVDCAM_USB 0x001e DVDCAM USB HS Interface
+/* Holtek products */
+product HOLTEK F85 0xa030 Holtek USB gaming keyboard
+
+/* Honeywell */
+product HONEYWELL HGI80 0x0102 Honeywell HGI80 Wireless USB Gateway
+
/* HP products */
product HP 895C 0x0004 DeskJet 895C
product HP 4100C 0x0101 Scanjet 4100C
@@ -1428,6 +2390,8 @@ product HP 3300C 0x0205 ScanJet 3300C
product HP CDW8200 0x0207 CD-Writer Plus 8200e
product HP MMKEYB 0x020c Multimedia keyboard
product HP 1220C 0x0212 DeskJet 1220C
+product HP UN2420_QDL 0x241d UN2420 QDL Firmware Loader
+product HP UN2420 0x251d UN2420 WWAN/GPS Module
product HP 810C 0x0304 DeskJet 810C/812C
product HP 4300C 0x0305 Scanjet 4300C
product HP CDW4E 0x0307 CD-Writer+ CD-4e
@@ -1441,6 +2405,7 @@ product HP 840C 0x0604 DeskJet 840c
product HP 2200C 0x0605 ScanJet 2200C
product HP 5300C 0x0701 Scanjet 5300C
product HP 4400C 0x0705 Scanjet 4400C
+product HP 4470C 0x0805 Scanjet 4470C
product HP 82x0C 0x0b01 Scanjet 82x0C
product HP 2300D 0x0b17 Laserjet 2300d
product HP 970CSE 0x1004 Deskjet 970Cse
@@ -1448,32 +2413,154 @@ product HP 5400C 0x1005 Scanjet 5400C
product HP 2215 0x1016 iPAQ 22xx/Jornada 548
product HP 568J 0x1116 Jornada 568
product HP 930C 0x1204 DeskJet 930c
+product HP3 RTL8188CU 0x1629 RTL8188CU
product HP P2000U 0x1801 Inkjet P-2000U
+product HP HS2300 0x1e1d HS2300 HSDPA (aka MC8775)
+product HP T500 0x1f01 T500
+product HP T750 0x1f02 T750
product HP 640C 0x2004 DeskJet 640c
product HP 4670V 0x3005 ScanJet 4670v
product HP P1100 0x3102 Photosmart P1100
+product HP LD220 0x3524 LD220 POS Display
product HP OJ4215 0x3d11 OfficeJet 4215
product HP HN210E 0x811c Ethernet HN210E
product HP2 C500 0x6002 PhotoSmart C500
+product HP EV2200 0x1b1d ev2200 HSDPA (aka MC5720)
+product HP HS2300 0x1e1d hs2300 HSDPA (aka MC8775)
/* HTC products */
product HTC WINMOBILE 0x00ce HTC USB Sync
product HTC PPC6700MODEM 0x00cf PPC6700 Modem
product HTC SMARTPHONE 0x0a51 SmartPhone USB Sync
+product HTC WIZARD 0x0bce HTC Wizard USB Sync
+product HTC LEGENDSYNC 0x0c97 HTC Legend USB Sync
+product HTC LEGEND 0x0ff9 HTC Legend
+product HTC LEGENDINTERNET 0x0ffe HTC Legend Internet Sharing
/* HUAWEI products */
product HUAWEI MOBILE 0x1001 Huawei Mobile
-product HUAWEI E220 0x1003 Huawei HSDPA modem
+product HUAWEI E220 0x1003 HSDPA modem
+product HUAWEI E220BIS 0x1004 HSDPA modem
+product HUAWEI E1401 0x1401 3G modem
+product HUAWEI E1402 0x1402 3G modem
+product HUAWEI E1403 0x1403 3G modem
+product HUAWEI E1404 0x1404 3G modem
+product HUAWEI E1405 0x1405 3G modem
+product HUAWEI E1406 0x1406 3G modem
+product HUAWEI E1407 0x1407 3G modem
+product HUAWEI E1408 0x1408 3G modem
+product HUAWEI E1409 0x1409 3G modem
+product HUAWEI E140A 0x140a 3G modem
+product HUAWEI E140B 0x140b 3G modem
+product HUAWEI E180V 0x140c E180V
+product HUAWEI E140D 0x140d 3G modem
+product HUAWEI E140E 0x140e 3G modem
+product HUAWEI E140F 0x140f 3G modem
+product HUAWEI E1410 0x1410 3G modem
+product HUAWEI E1411 0x1411 3G modem
+product HUAWEI E1412 0x1412 3G modem
+product HUAWEI E1413 0x1413 3G modem
+product HUAWEI E1414 0x1414 3G modem
+product HUAWEI E1415 0x1415 3G modem
+product HUAWEI E1416 0x1416 3G modem
+product HUAWEI E1417 0x1417 3G modem
+product HUAWEI E1418 0x1418 3G modem
+product HUAWEI E1419 0x1419 3G modem
+product HUAWEI E141A 0x141a 3G modem
+product HUAWEI E141B 0x141b 3G modem
+product HUAWEI E141C 0x141c 3G modem
+product HUAWEI E141D 0x141d 3G modem
+product HUAWEI E141E 0x141e 3G modem
+product HUAWEI E141F 0x141f 3G modem
+product HUAWEI E1420 0x1420 3G modem
+product HUAWEI E1421 0x1421 3G modem
+product HUAWEI E1422 0x1422 3G modem
+product HUAWEI E1423 0x1423 3G modem
+product HUAWEI E1424 0x1424 3G modem
+product HUAWEI E1425 0x1425 3G modem
+product HUAWEI E1426 0x1426 3G modem
+product HUAWEI E1427 0x1427 3G modem
+product HUAWEI E1428 0x1428 3G modem
+product HUAWEI E1429 0x1429 3G modem
+product HUAWEI E142A 0x142a 3G modem
+product HUAWEI E142B 0x142b 3G modem
+product HUAWEI E142C 0x142c 3G modem
+product HUAWEI E142D 0x142d 3G modem
+product HUAWEI E142E 0x142e 3G modem
+product HUAWEI E142F 0x142f 3G modem
+product HUAWEI E1430 0x1430 3G modem
+product HUAWEI E1431 0x1431 3G modem
+product HUAWEI E1432 0x1432 3G modem
+product HUAWEI E1433 0x1433 3G modem
+product HUAWEI E1434 0x1434 3G modem
+product HUAWEI E1435 0x1435 3G modem
+product HUAWEI E1436 0x1436 3G modem
+product HUAWEI E1437 0x1437 3G modem
+product HUAWEI E1438 0x1438 3G modem
+product HUAWEI E1439 0x1439 3G modem
+product HUAWEI E143A 0x143a 3G modem
+product HUAWEI E143B 0x143b 3G modem
+product HUAWEI E143C 0x143c 3G modem
+product HUAWEI E143D 0x143d 3G modem
+product HUAWEI E143E 0x143e 3G modem
+product HUAWEI E143F 0x143f 3G modem
+product HUAWEI E1752 0x1446 3G modem
+product HUAWEI K4505 0x1464 3G modem
+product HUAWEI K3765 0x1465 3G modem
+product HUAWEI E1820 0x14ac E1820 HSPA+ USB Slider
+product HUAWEI K3771_INIT 0x14c4 K3771 Initial
+product HUAWEI K3770 0x14c9 3G modem
+product HUAWEI K3771 0x14ca K3771
+product HUAWEI K3772 0x14cf K3772
+product HUAWEI K3770_INIT 0x14d1 K3770 Initial
+product HUAWEI E3131_INIT 0x14fe 3G modem initial
+product HUAWEI E392 0x1505 LTE modem
+product HUAWEI E3131 0x1506 3G modem
+product HUAWEI K3765_INIT 0x1520 K3765 Initial
+product HUAWEI K4505_INIT 0x1521 K4505 Initial
+product HUAWEI K3772_INIT 0x1526 K3772 Initial
+product HUAWEI E3272_INIT 0x155b LTE modem initial
+product HUAWEI ME909U 0x1573 LTE modem
+product HUAWEI R215_INIT 0x1582 LTE modem initial
+product HUAWEI R215 0x1588 LTE modem
+product HUAWEI ME909S 0x15c1 LTE modem
+product HUAWEI ETS2055 0x1803 CDMA modem
+product HUAWEI E173 0x1c05 3G modem
+product HUAWEI E173_INIT 0x1c0b 3G modem initial
+product HUAWEI E3272 0x1c1e LTE modem
/* HUAWEI 3com products */
product HUAWEI3COM WUB320G 0x0009 Aolynk WUB320g
/* IBM Corporation */
product IBM USBCDROMDRIVE 0x4427 USB CD-ROM Drive
+product IBM USB4543 0x4543 TI IBM USB 4543 Modem
+product IBM USB454B 0x454b TI IBM USB 454B Modem
+product IBM USB454C 0x454c TI IBM USB 454C Modem
+
+/* Icom products */
+product ICOM SP1 0x0004 FTDI compatible adapter
+product ICOM OPC_U_UC 0x0018 FTDI compatible adapter
+product ICOM RP2C1 0x0009 FTDI compatible adapter
+product ICOM RP2C2 0x000a FTDI compatible adapter
+product ICOM RP2D 0x000b FTDI compatible adapter
+product ICOM RP2KVR 0x0013 FTDI compatible adapter
+product ICOM RP2KVT 0x0012 FTDI compatible adapter
+product ICOM RP2VR 0x000d FTDI compatible adapter
+product ICOM RP2VT 0x000c FTDI compatible adapter
+product ICOM RP4KVR 0x0011 FTDI compatible adapter
+product ICOM RP4KVT 0x0010 FTDI compatible adapter
+
+/* ID-tech products */
+product IDTECH IDT1221U 0x0300 FTDI compatible adapter
/* Imagination Technologies products */
product IMAGINATION DBX1 0x2107 DBX1 DSP core
+/* Initio Corporation products */
+product INITIO DUMMY 0x0000 Dummy product
+product INITIO INIC_1610P 0x1e40 USB to SATA Bridge
+
/* Inside Out Networks products */
product INSIDEOUT EDGEPORT4 0x0001 EdgePort/4 serial ports
@@ -1488,6 +2575,19 @@ product INSYSTEM STORAGE_V2 0x5701 USB Storage Adapter V2
/* Intel products */
product INTEL EASYPC_CAMERA 0x0110 Easy PC Camera
product INTEL TESTBOARD 0x9890 82930 test board
+product INTEL2 IRMH 0x0020 Integrated Rate Matching Hub
+product INTEL2 IRMH2 0x0024 Integrated Rate Matching Hub
+product INTEL2 IRMH3 0x8000 Integrated Rate Matching Hub
+product INTEL2 IRMH4 0x8008 Integrated Rate Matching Hub
+product INTEL2 SNP 0x0a2b Stone Peak (7265) Bluetooth Module
+product INTEL2 SFP 0x0aa7 Sandy Peak (3168) Bluetooth Module
+product INTEL2 JFP 0x0aaa Jefferson Peak (9460/9560) Bluetooth Module
+product INTEL2 THP 0x0025 Thunder Peak (9160/9260) Bluetooth Module
+product INTEL2 HSP 0x0026 Harrison Peak (22560) Bluetooth Module
+
+/* Interbiometric products */
+product INTERBIOMETRICS IOBOARD 0x1002 FTDI compatible adapter
+product INTERBIOMETRICS MINI_IOBOARD 0x1006 FTDI compatible adapter
/* Intersil products */
product INTERSIL PRISM_GT 0x1000 PrismGT USB 2.0 WLAN
@@ -1508,15 +2608,33 @@ product IODATA USBETTXS 0x0913 USB ETTX
product IODATA USBWNB11A 0x0919 USB WN-B11
product IODATA USBWNB11 0x0922 USB Airport WN-B11
product IODATA ETGUS2 0x0930 ETG-US2
+product IODATA WNGDNUS2 0x093f WN-GDN/US2
+product IODATA RT3072_1 0x0944 RT3072
+product IODATA RT3072_2 0x0945 RT3072
+product IODATA RT3072_3 0x0947 RT3072
+product IODATA RT3072_4 0x0948 RT3072
+product IODATA WNAC867U 0x0952 WN-AC867U
product IODATA USBRSAQ 0x0a03 Serial USB-RSAQ1
+product IODATA USBRSAQ5 0x0a0e Serial USB-RSAQ5
product IODATA2 USB2SC 0x0a09 USB2.0-SCSI Bridge USB2-SC
/* Iomega products */
product IOMEGA ZIP100 0x0001 Zip 100
product IOMEGA ZIP250 0x0030 Zip 250
+/* Ionic products */
+product IONICS PLUGCOMPUTER 0x0102 FTDI compatible adapter
+
+/* Integrated System Solution Corp. products */
+product ISSC ISSCBTA 0x1001 Bluetooth USB Adapter
+
+/* iTegno products */
+product ITEGNO WM1080A 0x1080 WM1080A GSM/GPRS modem
+product ITEGNO WM2080A 0x2080 WM2080A CDMA modem
+
/* Ituner networks products */
product ITUNERNET USBLCD2X20 0x0002 USB-LCD 2x20
+product ITUNERNET USBLCD4X20 0xc001 USB-LCD 4x20
/* Jablotron products */
product JABLOTRON PC60B 0x0001 PC-60B
@@ -1524,6 +2642,15 @@ product JABLOTRON PC60B 0x0001 PC-60B
/* Jaton products */
product JATON EDA 0x5704 Ethernet
+/* Jeti products */
+product JETI SPC1201 0x04b2 FTDI compatible adapter
+
+/* JMicron products */
+product JMICRON JMS566 0x3569 USB to SATA 3.0Gb/s bridge
+product JMICRON JMS567 0x0567 USB to SATA 6.0Gb/s bridge
+product JMICRON JM20336 0x2336 USB to SATA Bridge
+product JMICRON JM20337 0x2338 USB to ATA/ATAPI Bridge
+
/* JVC products */
product JVC GR_DX95 0x000a GR-DX95
product JVC MP_PRX1 0x3008 MP-PRX1 Ethernet
@@ -1531,6 +2658,10 @@ product JVC MP_PRX1 0x3008 MP-PRX1 Ethernet
/* JRC products */
product JRC AH_J3001V_J3002V 0x0001 AirH PHONE AH-J3001V/J3002V
+/* Kamstrrup products */
+product KAMSTRUP OPTICALEYE 0x0001 Optical Eye/3-wire
+product KAMSTRUP MBUS_250D 0x0005 M-Bus Master MultiPort 250D
+
/* Kawatsu products */
product KAWATSU MH4000P 0x0003 MiniHub 4000P
@@ -1541,6 +2672,9 @@ product KEISOKUGIKEN USBDAQ 0x0068 HKS-0200 USBDAQ
product KENSINGTON ORBIT 0x1003 Orbit USB/PS2 trackball
product KENSINGTON TURBOBALL 0x1005 TurboBall
+/* Synaptics products */
+product SYNAPTICS FPR9A 0x009a Fingerprint Reader
+
/* Keyspan products */
product KEYSPAN USA28_NF 0x0101 USA-28 serial Adapter (no firmware)
product KEYSPAN USA28X_NF 0x0102 USA-28X serial Adapter (no firmware)
@@ -1574,11 +2708,16 @@ product KEYSPAN UIA11 0x0202 UIA-11 remote control
/* Kingston products */
product KINGSTON XX1 0x0008 Ethernet
product KINGSTON KNU101TX 0x000a KNU101TX USB Ethernet
+product KINGSTON HYPERX3_0 0x162b DT HyperX 3.0
/* Kawasaki products */
product KLSI DUH3E10BT 0x0008 USB Ethernet
product KLSI DUH3E10BTN 0x0009 USB Ethernet
+/* Kobil products */
+product KOBIL CONV_B1 0x2020 FTDI compatible adapter
+product KOBIL CONV_KAAN 0x2021 FTDI compatible adapter
+
/* Kodak products */
product KODAK DC220 0x0100 Digital Science DC220
product KODAK DC260 0x0110 Digital Science DC260
@@ -1587,6 +2726,10 @@ product KODAK DC290 0x0112 Digital Science DC290
product KODAK DC240 0x0120 Digital Science DC240
product KODAK DC280 0x0130 Digital Science DC280
+/* Kontron AG products */
+product KONTRON DM9601 0x8101 USB Ethernet
+product KONTRON JP1082 0x9700 USB Ethernet
+
/* Konica Corp. Products */
product KONICA CAMERA 0x0720 Digital Color Camera
@@ -1603,18 +2746,65 @@ product KYOCERA FINECAM_S5 0x0103 Finecam S5
product KYOCERA FINECAM_L3 0x0105 Finecam L3
product KYOCERA AHK3001V 0x0203 AH-K3001V
product KYOCERA2 CDMA_MSM_K 0x17da Qualcomm Kyocera CDMA Technologies MSM
+product KYOCERA2 KPC680 0x180a Qualcomm Kyocera CDMA Technologies MSM
/* LaCie products */
product LACIE HD 0xa601 Hard Disk
product LACIE CDRW 0xa602 CD R/W
+/* Lake Shore Cryotronics products */
+product LAKESHORE 121 0x0100 121 Current Source
+product LAKESHORE 218A 0x0200 218A Temperature Monitor
+product LAKESHORE 219 0x0201 219 Temperature Monitor
+product LAKESHORE 233 0x0202 233 Temperature Transmitter
+product LAKESHORE 235 0x0203 235 Temperature Transmitter
+product LAKESHORE 335 0x0300 335 Temperature Controller
+product LAKESHORE 336 0x0301 336 Temperature Controller
+product LAKESHORE 350 0x0302 350 Temperature Controller
+product LAKESHORE 371 0x0303 371 AC Bridge
+product LAKESHORE 411 0x0400 411 Handheld Gaussmeter
+product LAKESHORE 425 0x0401 425 Gaussmeter
+product LAKESHORE 455A 0x0402 455A DSP Gaussmeter
+product LAKESHORE 475A 0x0403 475A DSP Gaussmeter
+product LAKESHORE 465 0x0404 465 Gaussmeter
+product LAKESHORE 625A 0x0600 625A Magnet PSU
+product LAKESHORE 642A 0x0601 642A Magnet PSU
+product LAKESHORE 648 0x0602 648 Magnet PSU
+product LAKESHORE 737 0x0700 737 VSM Controller
+product LAKESHORE 776 0x0701 776 Matrix Switch
+
+/* Larsen and Brusgaard products */
+product LARSENBRUSGAARD ALTITRACK 0x0001 FTDI compatible adapter
+
+/* Leadtek products */
+product LEADTEK 9531 0x2101 9531 GPS
+
+/* Lenovo products */
+product LENOVO GIGALAN 0x304b USB 3.0 Ethernet
+product LENOVO ETHERNET 0x7203 USB 2.0 Ethernet
+product LENOVO RTL8153 0x7205 USB 3.0 Ethernet
+product LENOVO ONELINK 0x720a USB 3.0 Ethernet
+product LENOVO TBT3LAN 0x3069 LAN port in Thinkpad TB3 dock
+product LENOVO USBCLAN 0x3062 LAN port in Thinkpad USB-C dock
+
/* Lexar products */
product LEXAR JUMPSHOT 0x0001 jumpSHOT CompactFlash Reader
product LEXAR CF_READER 0xb002 USB CF Reader
+product LEXAR JUMPDRIVE 0xa833 USB Jumpdrive Flash Drive
/* Lexmark products */
product LEXMARK S2450 0x0009 Optra S 2450
+/* Liebert products */
+product LIEBERT POWERSURE_PXT 0xffff PowerSure Personal XT
+product LIEBERT2 POWERSURE_PSA 0x0001 PowerSure PSA UPS
+product LIEBERT2 PSI1000 0x0004 UPS PSI 1000 FW:08
+
+/* Link Instruments Inc. products */
+product LINKINSTRUMENTS MSO19 0xf190 Link Instruments MSO-19
+product LINKINSTRUMENTS MSO28 0xf280 Link Instruments MSO-28
+product LINKINSTRUMENTS MSO28_2 0xf281 Link Instruments MSO-28
+
/* Linksys products */
product LINKSYS MAUSB2 0x0105 Camedia MAUSB-2
product LINKSYS USB10TX1 0x200c USB10TX
@@ -1627,6 +2817,16 @@ product LINKSYS2 WUSB11 0x2219 WUSB11 Wireless Adapter
product LINKSYS2 USB200M 0x2226 USB 2.0 10/100 Ethernet
product LINKSYS3 WUSB11v28 0x2233 WUSB11 v2.8 Wireless Adapter
product LINKSYS4 USB1000 0x0039 USB1000
+product LINKSYS4 WUSB100 0x0070 WUSB100
+product LINKSYS4 WUSB600N 0x0071 WUSB600N
+product LINKSYS4 WUSB54GCV2 0x0073 WUSB54GC v2
+product LINKSYS4 WUSB54GCV3 0x0077 WUSB54GC v3
+product LINKSYS4 RT3070 0x0078 RT3070
+product LINKSYS4 WUSB600NV2 0x0079 WUSB600N v2
+
+/* Logilink products */
+product LOGILINK DUMMY 0x0000 Dummy product
+product LOGILINK U2M 0x0101 LogiLink USB MIDI Cable
/* Logitech products */
product LOGITECH M2452 0x0203 M2452 keyboard
@@ -1634,8 +2834,10 @@ product LOGITECH M4848 0x0301 M4848 mouse
product LOGITECH PAGESCAN 0x040f PageScan
product LOGITECH QUICKCAMWEB 0x0801 QuickCam Web
product LOGITECH QUICKCAMPRO 0x0810 QuickCam Pro
+product LOGITECH WEBCAMC100 0X0817 Webcam C100
product LOGITECH QUICKCAMEXP 0x0840 QuickCam Express
product LOGITECH QUICKCAM 0x0850 QuickCam
+product LOGITECH QUICKCAMPRO3 0x0990 QuickCam Pro 9000
product LOGITECH N43 0xc000 N43
product LOGITECH N48 0xc001 N48 mouse
product LOGITECH MBA47 0xc002 M-BA47 mouse
@@ -1645,16 +2847,32 @@ product LOGITECH UN58A 0xc030 iFeel Mouse
product LOGITECH UN53B 0xc032 iFeel MouseMan
product LOGITECH WMPAD 0xc208 WingMan GamePad Extreme
product LOGITECH WMRPAD 0xc20a WingMan RumblePad
+product LOGITECH G510S 0xc22d G510s Keyboard
product LOGITECH WMJOY 0xc281 WingMan Force joystick
product LOGITECH BB13 0xc401 USB-PS/2 Trackball
product LOGITECH RK53 0xc501 Cordless mouse
product LOGITECH RB6 0xc503 Cordless keyboard
product LOGITECH MX700 0xc506 Cordless optical mouse
+product LOGITECH UNIFYING 0xc52b Logitech Unifying Receiver
product LOGITECH QUICKCAMPRO2 0xd001 QuickCam Pro
/* Logitec Corp. products */
product LOGITEC LDR_H443SU2 0x0033 DVD Multi-plus unit LDR-H443SU2
product LOGITEC LDR_H443U2 0x00b3 DVD Multi-plus unit LDR-H443U2
+product LOGITEC LAN_GTJU2A 0x0160 LAN-GTJ/U2A Ethernet
+product LOGITEC RT2870_1 0x0162 RT2870
+product LOGITEC RT2870_2 0x0163 RT2870
+product LOGITEC RT2870_3 0x0164 RT2870
+product LOGITEC LANW300NU2 0x0166 LAN-W300N/U2
+product LOGITEC LANW150NU2 0x0168 LAN-W150N/U2
+product LOGITEC LANW300NU2S 0x0169 LAN-W300N/U2S
+
+/* Longcheer Holdings, Ltd. products */
+product LONGCHEER WM66 0x6061 Longcheer WM66 HSDPA
+product LONGCHEER W14 0x9603 Mobilcom W14
+product LONGCHEER DISK 0xf000 Driver disk
+product LONGCHEER XSSTICK 0x9605 4G Systems XSStick P14
+
/* Lucent products */
product LUCENT EVALKIT 0x1001 USS-720 evaluation kit
@@ -1665,8 +2883,262 @@ product LUWEN EASYDISK 0x0005 EasyDisc
/* Macally products */
product MACALLY MOUSE1 0x0101 mouse
+/* Mag-Tek products */
+product MAGTEK USBSWIPE 0x0002 USB Mag Stripe Swipe Reader
+
/* Marvell Technology Group, Ltd. products */
-product MARVELL SHEEVAPLUG_JTAG 0x9e8f SheevaPlug JTAGKey
+product MARVELL SHEEVAPLUG 0x9e8f SheevaPlug serial interface
+
+/* Matrix Orbital products */
+product MATRIXORBITAL FTDI_RANGE_0100 0x0100 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0101 0x0101 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0102 0x0102 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0103 0x0103 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0104 0x0104 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0105 0x0105 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0106 0x0106 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0107 0x0107 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0108 0x0108 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0109 0x0109 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_010A 0x010a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_010B 0x010b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_010C 0x010c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_010D 0x010d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_010E 0x010e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_010F 0x010f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0110 0x0110 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0111 0x0111 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0112 0x0112 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0113 0x0113 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0114 0x0114 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0115 0x0115 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0116 0x0116 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0117 0x0117 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0118 0x0118 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0119 0x0119 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_011A 0x011a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_011B 0x011b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_011C 0x011c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_011D 0x011d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_011E 0x011e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_011F 0x011f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0120 0x0120 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0121 0x0121 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0122 0x0122 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0123 0x0123 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0124 0x0124 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0125 0x0125 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0126 0x0126 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0128 0x0128 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0129 0x0129 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_012A 0x012a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_012B 0x012b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_012D 0x012d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_012E 0x012e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_012F 0x012f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0130 0x0130 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0131 0x0131 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0132 0x0132 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0133 0x0133 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0134 0x0134 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0135 0x0135 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0136 0x0136 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0137 0x0137 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0138 0x0138 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0139 0x0139 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_013A 0x013a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_013B 0x013b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_013C 0x013c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_013D 0x013d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_013E 0x013e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_013F 0x013f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0140 0x0140 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0141 0x0141 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0142 0x0142 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0143 0x0143 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0144 0x0144 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0145 0x0145 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0146 0x0146 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0147 0x0147 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0148 0x0148 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0149 0x0149 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_014A 0x014a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_014B 0x014b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_014C 0x014c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_014D 0x014d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_014E 0x014e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_014F 0x014f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0150 0x0150 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0151 0x0151 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0152 0x0152 FTDI compatible adapter
+product MATRIXORBITAL MOUA 0x0153 Martrix Orbital MOU-Axxxx LCD displays
+product MATRIXORBITAL FTDI_RANGE_0159 0x0159 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_015A 0x015a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_015B 0x015b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_015C 0x015c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_015D 0x015d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_015E 0x015e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_015F 0x015f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0160 0x0160 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0161 0x0161 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0162 0x0162 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0163 0x0163 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0164 0x0164 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0165 0x0165 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0166 0x0166 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0167 0x0167 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0168 0x0168 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0169 0x0169 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_016A 0x016a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_016B 0x016b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_016C 0x016c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_016D 0x016d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_016E 0x016e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_016F 0x016f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0170 0x0170 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0171 0x0171 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0172 0x0172 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0173 0x0173 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0174 0x0174 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0175 0x0175 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0176 0x0176 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0177 0x0177 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0178 0x0178 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0179 0x0179 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_017A 0x017a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_017B 0x017b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_017C 0x017c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_017D 0x017d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_017E 0x017e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_017F 0x017f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0180 0x0180 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0181 0x0181 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0182 0x0182 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0183 0x0183 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0184 0x0184 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0185 0x0185 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0186 0x0186 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0187 0x0187 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0188 0x0188 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0189 0x0189 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_018A 0x018a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_018B 0x018b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_018C 0x018c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_018D 0x018d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_018E 0x018e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_018F 0x018f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0190 0x0190 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0191 0x0191 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0192 0x0192 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0193 0x0193 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0194 0x0194 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0195 0x0195 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0196 0x0196 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0197 0x0197 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0198 0x0198 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_0199 0x0199 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_019A 0x019a FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_019B 0x019b FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_019C 0x019c FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_019D 0x019d FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_019E 0x019e FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_019F 0x019f FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A0 0x01a0 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A1 0x01a1 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A2 0x01a2 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A3 0x01a3 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A4 0x01a4 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A5 0x01a5 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A6 0x01a6 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A7 0x01a7 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A8 0x01a8 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01A9 0x01a9 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01AA 0x01aa FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01AB 0x01ab FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01AC 0x01ac FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01AD 0x01ad FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01AE 0x01ae FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01AF 0x01af FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B0 0x01b0 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B1 0x01b1 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B2 0x01b2 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B3 0x01b3 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B4 0x01b4 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B5 0x01b5 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B6 0x01b6 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B7 0x01b7 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B8 0x01b8 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01B9 0x01b9 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01BA 0x01ba FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01BB 0x01bb FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01BC 0x01bc FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01BD 0x01bd FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01BE 0x01be FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01BF 0x01bf FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C0 0x01c0 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C1 0x01c1 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C2 0x01c2 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C3 0x01c3 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C4 0x01c4 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C5 0x01c5 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C6 0x01c6 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C7 0x01c7 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C8 0x01c8 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01C9 0x01c9 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01CA 0x01ca FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01CB 0x01cb FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01CC 0x01cc FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01CD 0x01cd FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01CE 0x01ce FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01CF 0x01cf FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D0 0x01d0 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D1 0x01d1 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D2 0x01d2 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D3 0x01d3 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D4 0x01d4 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D5 0x01d5 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D6 0x01d6 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D7 0x01d7 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D8 0x01d8 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01D9 0x01d9 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01DA 0x01da FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01DB 0x01db FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01DC 0x01dc FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01DD 0x01dd FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01DE 0x01de FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01DF 0x01df FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E0 0x01e0 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E1 0x01e1 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E2 0x01e2 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E3 0x01e3 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E4 0x01e4 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E5 0x01e5 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E6 0x01e6 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E7 0x01e7 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E8 0x01e8 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01E9 0x01e9 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01EA 0x01ea FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01EB 0x01eb FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01EC 0x01ec FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01ED 0x01ed FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01EE 0x01ee FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01EF 0x01ef FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F0 0x01f0 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F1 0x01f1 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F2 0x01f2 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F3 0x01f3 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F4 0x01f4 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F5 0x01f5 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F6 0x01f6 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F7 0x01f7 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F8 0x01f8 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01F9 0x01f9 FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01FA 0x01fa FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01FB 0x01fb FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01FC 0x01fc FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01FD 0x01fd FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01FE 0x01fe FTDI compatible adapter
+product MATRIXORBITAL FTDI_RANGE_01FF 0x01ff FTDI compatible adapter
/* MCT Corp. */
product MCT HUB0100 0x0100 Hub
@@ -1674,28 +3146,55 @@ product MCT DU_H3SP_USB232 0x0200 D-Link DU-H3SP USB BAY Hub
product MCT USB232 0x0210 USB-232 Interface
product MCT SITECOM_USB232 0x0230 Sitecom USB-232 Products
+/* Medeli */
+product MEDELI DD305 0x5011 DD305 Digital Drum Set
+
+/* MediaTek, Inc. */
+product MEDIATEK MTK3329 0x3329 MTK II GPS Receiver
+
+/* Meizu Electronics */
+product MEIZU M6_SL 0x0140 MiniPlayer M6 (SL)
+
/* Melco, Inc products */
product MELCO LUATX1 0x0001 LUA-TX Ethernet
product MELCO LUATX5 0x0005 LUA-TX Ethernet
product MELCO LUA2TX5 0x0009 LUA2-TX Ethernet
product MELCO LUAKTX 0x0012 LUA-KTX Ethernet
-product MELCO DUBPXXG 0x001c USB-IDE Bridge: DUB-PxxG
+product MELCO DUBPXXG 0x001c DUB-PxxG
product MELCO LUAU2KTX 0x003d LUA-U2-KTX Ethernet
product MELCO KG54YB 0x005e WLI-U2-KG54-YB WLAN
product MELCO KG54 0x0066 WLI-U2-KG54 WLAN
product MELCO KG54AI 0x0067 WLI-U2-KG54-AI WLAN
+product MELCO LUA3U2AGT 0x006e LUA3-U2-AGT
product MELCO NINWIFI 0x008b Nintendo Wi-Fi
product MELCO PCOPRS1 0x00b3 PC-OP-RS1 RemoteStation
product MELCO SG54HP 0x00d8 WLI-U2-SG54HP
product MELCO G54HP 0x00d9 WLI-U2-G54HP
product MELCO KG54L 0x00da WLI-U2-KG54L
+product MELCO WLIUCG300N 0x00e8 WLI-UC-G300N
+product MELCO SG54HG 0x00f4 WLI-U2-SG54HG
+product MELCO WLRUCG 0x0116 WLR-UC-G
+product MELCO WLRUCGAOSS 0x0119 WLR-UC-G-AOSS
+product MELCO WLIUCAG300N 0x012e WLI-UC-AG300N
+product MELCO WLIUCG 0x0137 WLI-UC-G
+product MELCO WLIUCG300HP 0x0148 WLI-UC-G300HP
+product MELCO RT2870_2 0x0150 RT2870
+product MELCO WLIUCGN 0x015d WLI-UC-GN
+product MELCO WLIUCG301N 0x016f WLI-UC-G301N
+product MELCO WLIUCGNM 0x01a2 WLI-UC-GNM
+product MELCO WLIUCG300HPV1 0x01a8 WLI-UC-G300HP-V1
+product MELCO WLIUCGNM2 0x01ee WLI-UC-GNM2
+product MELCO WIU2433DM 0x0242 WI-U2-433DM
+product MELCO WIU3866D 0x025d WI-U3-866D
/* Merlin products */
product MERLIN V620 0x1110 Merlin V620
/* MetaGeek products */
+product METAGEEK TELLSTICK 0x0c30 FTDI compatible adapter
product METAGEEK WISPY1B 0x083e MetaGeek Wi-Spy
product METAGEEK WISPY24X 0x083f MetaGeek Wi-Spy 2.4x
+product METAGEEK2 WISPYDBX 0x5000 MetaGeek Wi-Spy DBx
/* Metricom products */
product METRICOM RICOCHET_GS 0x0001 Ricochet GS
@@ -1704,19 +3203,39 @@ product METRICOM RICOCHET_GS 0x0001 Ricochet GS
product MGE UPS1 0x0001 MGE UPS SYSTEMS PROTECTIONCENTER 1
product MGE UPS2 0xffff MGE UPS SYSTEMS PROTECTIONCENTER 2
+/* MEI products */
+product MEI CASHFLOW_SC 0x1100 Cashflow-SC Cash Acceptor
+product MEI S2000 0x1101 Series 2000 Combo Acceptor
+
+/* Microdia / Sonix Techonology Co., Ltd. products */
+product CHICONY2 YUREX 0x1010 YUREX
+product CHICONY2 CAM_1 0x62c0 CAM_1
+product CHICONY2 TEMPER 0x7401 TEMPer sensor
+
/* Micro Star International products */
product MSI BT_DONGLE 0x1967 Bluetooth USB dongle
+product MSI RT3070_1 0x3820 RT3070
+product MSI RT3070_2 0x3821 RT3070
+product MSI RT3070_8 0x3822 RT3070
+product MSI RT3070_3 0x3870 RT3070
+product MSI RT3070_9 0x3871 RT3070
product MSI UB11B 0x6823 UB11B
product MSI RT2570 0x6861 RT2570
product MSI RT2570_2 0x6865 RT2570
product MSI RT2570_3 0x6869 RT2570
product MSI RT2573_1 0x6874 RT2573
product MSI RT2573_2 0x6877 RT2573
+product MSI RT3070_4 0x6899 RT3070
+product MSI RT3070_5 0x821a RT3070
+product MSI RT3070_10 0x822a RT3070
+product MSI RT3070_6 0x870a RT3070
+product MSI RT3070_11 0x871a RT3070
+product MSI RT3070_7 0x899a RT3070
product MSI RT2573_3 0xa861 RT2573
product MSI RT2573_4 0xa874 RT2573
-/* Microdia products */
-product MICRODIA TWINKLECAM 0x600d TwinkleCam USB camera
+/* Micron products */
+product MICRON REALSSD 0x0655 Real SSD eUSB
/* Microsoft products */
product MICROSOFT SIDEPREC 0x0008 SideWinder Precision Pro
@@ -1728,14 +3247,17 @@ product MICROSOFT INETPRO 0x001c Internet Keyboard Pro
product MICROSOFT TBEXPLORER 0x0024 Trackball Explorer
product MICROSOFT INTELLIEYE 0x0025 IntelliEye mouse
product MICROSOFT INETPRO2 0x002b Internet Keyboard Pro
+product MICROSOFT INTELLIMOUSE5 0x0039 IntelliMouse 1.1 5-Button Mouse
+product MICROSOFT WHEELMOUSE 0x0040 Wheel Mouse Optical
product MICROSOFT MN510 0x006e MN510 Wireless
+product MICROSOFT 700WX 0x0079 Palm 700WX
product MICROSOFT MN110 0x007a 10/100 USB NIC
product MICROSOFT WLINTELLIMOUSE 0x008c Wireless Optical IntelliMouse
product MICROSOFT WLNOTEBOOK 0x00b9 Wireless Optical Mouse (Model 1023)
product MICROSOFT COMFORT3000 0x00d1 Comfort Optical Mouse 3000 (Model 1043)
-product MICROSOFT WLNOTEBOOK2 0x00e1 Wireless Optical Mouse 3000 (Model 1056)
product MICROSOFT WLNOTEBOOK3 0x00d2 Wireless Optical Mouse 3000 (Model 1049)
-product MICROSOFT WLUSBMOUSE 0x00b9 Wireless USB Mouse
+product MICROSOFT NATURAL4000 0x00db Natural Ergonomic Keyboard 4000
+product MICROSOFT WLNOTEBOOK2 0x00e1 Wireless Optical Mouse 3000 (Model 1056)
product MICROSOFT XBOX360 0x0292 XBOX 360 WLAN
/* Microtech products */
@@ -1757,7 +3279,9 @@ product MICROTEK V6UL 0x80ac ScanMaker V6UL
product MICROTUNE BT_DONGLE 0x1000 Bluetooth USB dongle
/* Midiman products */
-product MIDIMAN MIDISPORT2X2 0x1001 Midisport 2x2
+product MAUDIO MIDISPORT2X2 0x1001 Midisport 2x2
+product MAUDIO FASTTRACKULTRA 0x2080 Fast Track Ultra
+product MAUDIO FASTTRACKULTRA8R 0x2081 Fast Track Ultra 8R
/* MindsAtWork products */
product MINDSATWORK WALLET 0x0001 Digital Wallet
@@ -1775,24 +3299,55 @@ product MITSUMI CDRRW 0x0000 CD-R/RW Drive
product MITSUMI BT_DONGLE 0x641f Bluetooth USB dongle
product MITSUMI FDD 0x6901 USB FDD
+/* Mobile Action products */
+product MOBILEACTION MA620 0x0620 MA-620 Infrared Adapter
+
/* Mobility products */
+product MOBILITY USB_SERIAL 0x0202 FTDI compatible adapter
product MOBILITY EA 0x0204 Ethernet
product MOBILITY EASIDOCK 0x0304 EasiDock Ethernet
/* MosChip products */
product MOSCHIP MCS7703 0x7703 MCS7703 Serial Port Adapter
+product MOSCHIP MCS7730 0x7730 MCS7730 Ethernet
+product MOSCHIP MCS7820 0x7820 MCS7820 Serial Port Adapter
product MOSCHIP MCS7830 0x7830 MCS7830 Ethernet
+product MOSCHIP MCS7832 0x7832 MCS7832 Ethernet
+product MOSCHIP MCS7840 0x7840 MCS7840 Serial Port Adapter
/* Motorola products */
product MOTOROLA MC141555 0x1555 MC141555 hub controller
product MOTOROLA SB4100 0x4100 SB4100 USB Cable Modem
+product MOTOROLA2 T720C 0x2822 T720c
product MOTOROLA2 A41XV32X 0x2a22 A41x/V32x Mobile Phones
product MOTOROLA2 E398 0x4810 E398 Mobile Phone
product MOTOROLA2 USBLAN 0x600c USBLAN
product MOTOROLA2 USBLAN2 0x6027 USBLAN
+product MOTOROLA2 MB886 0x710f MB886 Mobile Phone (Atria HD)
+product MOTOROLA4 RT2770 0x9031 RT2770
+product MOTOROLA4 RT3070 0x9032 RT3070
+
+/* Moxa */
+product MOXA MXU1_1110 0x1110 Moxa Uport 1110
+product MOXA MXU1_1130 0x1130 Moxa Uport 1130
+product MOXA MXU1_1131 0x1131 Moxa Uport 1131
+product MOXA MXU1_1150 0x1150 Moxa Uport 1150
+product MOXA MXU1_1151 0x1151 Moxa Uport 1151
+
+/* MpMan products */
+product MPMAN MPF400_2 0x25a8 MPF400 Music Player 2Go
+product MPMAN MPF400_1 0x36d0 MPF400 Music Player 1Go
/* MultiTech products */
+product MULTITECH MT9234ZBA_2 0x0319 MT9234ZBA USB modem (alt)
product MULTITECH ATLAS 0xf101 MT5634ZBA-USB modem
+product MULTITECH GSM 0xf108 GSM USB Modem
+product MULTITECH CDMA 0xf109 CDMA USB Modem
+product MULTITECH CDMA_FW 0xf110 CDMA USB Modem firmware running
+product MULTITECH GSM_FW 0xf111 GSM USB Modem firmware running
+product MULTITECH EDGE 0xf112 Edge USB Modem
+product MULTITECH MT9234MU 0xf114 MT9234 MU
+product MULTITECH MT9234ZBA 0xf115 MT9234 ZBA
/* Mustek products */
product MUSTEK 1200CU 0x0001 1200 CU scanner
@@ -1802,6 +3357,7 @@ product MUSTEK 1200UB 0x0006 1200 UB scanner
product MUSTEK 1200USBPLUS 0x0007 1200 USB Plus scanner
product MUSTEK 1200CUPLUS 0x0008 1200 CU Plus scanner
product MUSTEK BEARPAW1200F 0x0010 BearPaw 1200F scanner
+product MUSTEK BEARPAW2400TA 0x0218 BearPaw 2400TA scanner
product MUSTEK BEARPAW1200TA 0x021e BearPaw 1200TA scanner
product MUSTEK 600USB 0x0873 600 USB scanner
product MUSTEK MDC800 0xa800 MDC-800 digital camera
@@ -1811,13 +3367,20 @@ product MSYSTEMS DISKONKEY 0x0010 DiskOnKey
product MSYSTEMS DISKONKEY2 0x0011 DiskOnKey
/* Myson products */
+product MYSON HEDEN_8813 0x8813 USB-IDE
product MYSON HEDEN 0x8818 USB-IDE
+product MYSON HUBREADER 0x8819 COMBO Card reader with USB HUB
+product MYSON STARREADER 0x9920 USB flash card adapter
/* National Semiconductor */
product NATIONAL BEARPAW1200 0x1000 BearPaw 1200
product NATIONAL BEARPAW2400 0x1001 BearPaw 2400
/* NEC products */
+product NEC HUB_0050 0x0050 USB 2.0 7-Port Hub
+product NEC HUB_005A 0x005a USB 2.0 4-Port Hub
+product NEC WL300NUG 0x0249 WL300NU-G
+product NEC WL900U 0x0408 Aterm WL900U
product NEC HUB 0x55aa hub
product NEC HUB_B 0x55ab hub
@@ -1825,6 +3388,9 @@ product NEC HUB_B 0x55ab hub
product NEODIO ND3260 0x3260 8-in-1 Multi-format Flash Controller
product NEODIO ND5010 0x5010 Multi-format Flash Controller
+/* Neotel products */
+product NEOTEL PRIME 0x4000 Prime USB modem
+
/* Netac products */
product NETAC CF_CARD 0x1060 USB-CF-Card
product NETAC ONLYDISK 0x0003 OnlyDisk
@@ -1832,22 +3398,43 @@ product NETAC ONLYDISK 0x0003 OnlyDisk
/* NetChip Technology Products */
product NETCHIP TURBOCONNECT 0x1080 Turbo-Connect
product NETCHIP CLIK_40 0xa140 USB Clik! 40
+product NETCHIP GADGETZERO 0xa4a0 Linux Gadget Zero
product NETCHIP ETHERNETGADGET 0xa4a2 Linux Ethernet/RNDIS gadget on pxa210/25x/26x
+product NETCHIP POCKETBOOK 0xa4a5 PocketBook
/* Netgear products */
product NETGEAR EA101 0x1001 Ethernet
product NETGEAR EA101X 0x1002 Ethernet
product NETGEAR FA101 0x1020 Ethernet 10/100, USB1.1
product NETGEAR FA120 0x1040 USB 2.0 Ethernet
-product NETGEAR WG111V2_2 0x4240 PrismGT USB 2.0 WLAN
+product NETGEAR M4100 0x1100 M4100/M5300/M7100 series switch
+product NETGEAR WG111V1_2 0x4240 PrismGT USB 2.0 WLAN
+product NETGEAR WG111V3 0x4260 WG111v3
product NETGEAR WG111U 0x4300 WG111U
product NETGEAR WG111U_NF 0x4301 WG111U (no firmware)
+product NETGEAR WG111V2 0x6a00 WG111V2
+product NETGEAR WN111V2 0x9001 WN111V2
+product NETGEAR WNDA3100 0x9010 WNDA3100
+product NETGEAR WNDA4100 0x9012 WNDA4100
+product NETGEAR WNDA3200 0x9018 WNDA3200
+product NETGEAR RTL8192CU 0x9021 RTL8192CU
+product NETGEAR WNA1000 0x9040 WNA1000
+product NETGEAR WNA1000M 0x9041 WNA1000M
+product NETGEAR A6100 0x9052 A6100
product NETGEAR2 MA101 0x4100 MA101
product NETGEAR2 MA101B 0x4102 MA101 Rev B
product NETGEAR3 WG111T 0x4250 WG111T
product NETGEAR3 WG111T_NF 0x4251 WG111T (no firmware)
product NETGEAR3 WPN111 0x5f00 WPN111
product NETGEAR3 WPN111_NF 0x5f01 WPN111 (no firmware)
+product NETGEAR3 WPN111_2 0x5f02 WPN111
+product NETGEAR4 RTL8188CU 0x9041 RTL8188CU
+
+/* NetIndex products */
+product NETINDEX WS002IN 0x2001 Willcom WS002IN
+
+/* NEWlink */
+product NEWLINK USB2IDEBRIDGE 0x00ff USB 2.0 Hard Drive Enclosure
/* Nikon products */
product NIKON E990 0x0102 Digital Camera E990
@@ -1857,6 +3444,11 @@ product NIKON D300 0x041a Digital Camera D300
/* NovaTech Products */
product NOVATECH NV902 0x9020 NovaTech NV-902W
product NOVATECH RT2573 0x9021 RT2573
+product NOVATECH RTL8188CU 0x9071 RTL8188CU
+
+/* Nokia products */
+product NOKIA N958GB 0x0070 Nokia N95 8GBc
+product NOKIA2 CA42 0x1234 CA-42 cable
/* Novatel Wireless products */
product NOVATEL V640 0x1100 Merlin V620
@@ -1869,16 +3461,42 @@ product NOVATEL U740_2 0x1410 Merlin U740
product NOVATEL U870 0x1420 Merlin U870
product NOVATEL XU870 0x1430 Merlin XU870
product NOVATEL X950D 0x1450 Merlin X950D
+product NOVATEL ES620 0x2100 Expedite ES620
+product NOVATEL E725 0x2120 Expedite E725
+product NOVATEL ES620_2 0x2130 Expedite ES620
product NOVATEL ES620 0x2100 ES620 CDMA
product NOVATEL U720 0x2110 Merlin U720
+product NOVATEL EU730 0x2400 Expedite EU730
+product NOVATEL EU740 0x2410 Expedite EU740
+product NOVATEL EU870D 0x2420 Expedite EU870D
product NOVATEL U727 0x4100 Merlin U727 CDMA
product NOVATEL MC950D 0x4400 Novatel MC950D HSUPA
+product NOVATEL MC990D 0x7001 Novatel MC990D
product NOVATEL ZEROCD 0x5010 Novatel ZeroCD
+product NOVATEL MIFI2200V 0x5020 Novatel MiFi 2200 CDMA Virgin Mobile
+product NOVATEL ZEROCD2 0x5030 Novatel ZeroCD
+product NOVATEL MIFI2200 0x5041 Novatel MiFi 2200 CDMA
+product NOVATEL U727_2 0x5100 Merlin U727 CDMA
+product NOVATEL U760 0x6000 Novatel U760
+product NOVATEL MC760 0x6002 Novatel MC760
+product NOVATEL MC547 0x7042 Novatel MC547
+product NOVATEL MC679 0x7031 Novatel MC679
product NOVATEL2 FLEXPACKGPS 0x0100 NovAtel FlexPack GPS receiver
+/* NVIDIA products */
+product NVIDIA RTL8153 0x09ff USB 3.0 Ethernet
+
/* Merlin products */
product MERLIN V620 0x1110 Merlin V620
+/* O2Micro products */
+product O2MICRO OZ776_HUB 0x7761 OZ776 hub
+product O2MICRO OZ776_CCID_SC 0x7772 OZ776 CCID SC Reader
+
+/* Olimex products */
+product OLIMEX ARM_USB_OCD 0x0003 FTDI compatible adapter
+product OLIMEX ARM_USB_OCD_H 0x002b FTDI compatible adapter
+
/* Olympus products */
product OLYMPUS C1 0x0102 C-1 Digital Camera
product OLYMPUS C700 0x0105 C-700 Ultra Zoom
@@ -1904,8 +3522,56 @@ product OPTION VODAFONEMC3G 0x5000 Vodafone Mobile Connect 3G datacard
product OPTION GT3G 0x6000 GlobeTrotter 3G datacard
product OPTION GT3GQUAD 0x6300 GlobeTrotter 3G QUAD datacard
product OPTION GT3GPLUS 0x6600 GlobeTrotter 3G+ datacard
+product OPTION GTICON322 0xd033 GlobeTrotter Icon322 storage
product OPTION GTMAX36 0x6701 GlobeTrotter Max 3.6 Modem
+product OPTION GTMAX72 0x6711 GlobeTrotter Max 7.2 HSDPA
+product OPTION GTHSDPA 0x6971 GlobeTrotter HSDPA
product OPTION GTMAXHSUPA 0x7001 GlobeTrotter HSUPA
+product OPTION GTMAXHSUPAE 0x6901 GlobeTrotter HSUPA PCIe
+product OPTION GTMAX380HSUPAE 0x7211 GlobeTrotter 380HSUPA PCIe
+product OPTION GT3G_1 0x6050 3G modem
+product OPTION GT3G_2 0x6100 3G modem
+product OPTION GT3G_3 0x6150 3G modem
+product OPTION GT3G_4 0x6200 3G modem
+product OPTION GT3G_5 0x6250 3G modem
+product OPTION GT3G_6 0x6350 3G modem
+product OPTION E6500 0x6500 3G modem
+product OPTION E6501 0x6501 3G modem
+product OPTION E6601 0x6601 3G modem
+product OPTION E6721 0x6721 3G modem
+product OPTION E6741 0x6741 3G modem
+product OPTION E6761 0x6761 3G modem
+product OPTION E6800 0x6800 3G modem
+product OPTION E7021 0x7021 3G modem
+product OPTION E7041 0x7041 3G modem
+product OPTION E7061 0x7061 3G modem
+product OPTION E7100 0x7100 3G modem
+product OPTION GTM380 0x7201 3G modem
+product OPTION GE40X 0x7601 Globetrotter HSUPA
+product OPTION GSICON72 0x6911 GlobeSurfer iCON
+product OPTION GSICONHSUPA 0x7251 Globetrotter HSUPA
+product OPTION ICON401 0x7401 GlobeSurfer iCON 401
+product OPTION GTHSUPA 0x7011 Globetrotter HSUPA
+product OPTION GMT382 0x7501 Globetrotter HSUPA
+product OPTION GE40X_1 0x7301 Globetrotter HSUPA
+product OPTION GE40X_2 0x7361 Globetrotter HSUPA
+product OPTION GE40X_3 0x7381 Globetrotter HSUPA
+product OPTION GTM661W 0x9000 GTM661W
+product OPTION ICONEDGE 0xc031 GlobeSurfer iCON EDGE
+product OPTION MODHSXPA 0xd013 Globetrotter HSUPA
+product OPTION ICON321 0xd031 Globetrotter HSUPA
+product OPTION ICON505 0xd055 Globetrotter iCON 505
+product OPTION ICON452 0x7901 Globetrotter iCON 452
+
+/* Optoelectronics Co., Ltd */
+product OPTO BARCODE 0x0001 Barcode Reader
+product OPTO OPTICONCODE 0x0009 Opticon Code Reader
+product OPTO BARCODE_1 0xa002 Barcode Reader
+product OPTO CRD7734 0xc000 USB Cradle CRD-7734-RU
+product OPTO CRD7734_1 0xc001 USB Cradle CRD-7734-RU
+
+/* OvisLink product */
+product OVISLINK RT3072 0x3072 RT3072
/* OQO */
product OQO WIFI01 0x0002 model 01 WiFi interface
@@ -1913,6 +3579,15 @@ product OQO BT01 0x0003 model 01 Bluetooth interface
product OQO ETHER01PLUS 0x7720 model 01+ Ethernet
product OQO ETHER01 0x8150 model 01 Ethernet interface
+/* Ours Technology Inc. */
+product OTI DKU5 0x6858 DKU-5 Serial
+
+/* Owen.ru products */
+product OWEN AC4 0x0004 AC4 USB-RS485 converter
+
+/* OWL producs */
+product OWL CM_160 0xca05 OWL CM-160 power monitor
+
/* Palm Computing, Inc. product */
product PALM SERIAL 0x0080 USB Serial
product PALM M500 0x0001 Palm m500
@@ -1933,6 +3608,49 @@ product PANASONIC KXLRW32AN 0x0d09 CD-R Drive KXL-RW32AN
product PANASONIC KXLCB20AN 0x0d0a CD-R Drive KXL-CB20AN
product PANASONIC KXLCB35AN 0x0d0e DVD-ROM & CD-R/RW
product PANASONIC SDCAAE 0x1b00 MultiMediaCard
+product PANASONIC TYTP50P6S 0x3900 TY-TP50P6-S 50in Touch Panel
+
+/* Papouch products */
+product PAPOUCH AD4USB 0x8003 FTDI compatible adapter
+product PAPOUCH AP485 0x0101 FTDI compatible adapter
+product PAPOUCH AP485_2 0x0104 FTDI compatible adapter
+product PAPOUCH DRAK5 0x0700 FTDI compatible adapter
+product PAPOUCH DRAK6 0x1000 FTDI compatible adapter
+product PAPOUCH GMSR 0x8005 FTDI compatible adapter
+product PAPOUCH GMUX 0x8004 FTDI compatible adapter
+product PAPOUCH IRAMP 0x0500 FTDI compatible adapter
+product PAPOUCH LEC 0x0300 FTDI compatible adapter
+product PAPOUCH MU 0x8001 FTDI compatible adapter
+product PAPOUCH QUIDO10X1 0x0b00 FTDI compatible adapter
+product PAPOUCH QUIDO2X16 0x0e00 FTDI compatible adapter
+product PAPOUCH QUIDO2X2 0x0a00 FTDI compatible adapter
+product PAPOUCH QUIDO30X3 0x0c00 FTDI compatible adapter
+product PAPOUCH QUIDO3X32 0x0f00 FTDI compatible adapter
+product PAPOUCH QUIDO4X4 0x0900 FTDI compatible adapter
+product PAPOUCH QUIDO60X3 0x0d00 FTDI compatible adapter
+product PAPOUCH QUIDO8X8 0x0800 FTDI compatible adapter
+product PAPOUCH SB232 0x0301 FTDI compatible adapter
+product PAPOUCH SB422 0x0102 FTDI compatible adapter
+product PAPOUCH SB422_2 0x0105 FTDI compatible adapter
+product PAPOUCH SB485 0x0100 FTDI compatible adapter
+product PAPOUCH SB485C 0x0107 FTDI compatible adapter
+product PAPOUCH SB485S 0x0106 FTDI compatible adapter
+product PAPOUCH SB485_2 0x0103 FTDI compatible adapter
+product PAPOUCH SIMUKEY 0x8002 FTDI compatible adapter
+product PAPOUCH TMU 0x0400 FTDI compatible adapter
+product PAPOUCH UPSUSB 0x8000 FTDI compatible adapter
+
+/* PARA Industrial products */
+product PARA RT3070 0x8888 RT3070
+
+/* Simtec Electronics products */
+product SIMTEC ENTROPYKEY 0x0001 Entropy Key
+
+/* Pegatron products */
+product PEGATRON RT2870 0x0002 RT2870
+product PEGATRON RT3070 0x000c RT3070
+product PEGATRON RT3070_2 0x000e RT3070
+product PEGATRON RT3070_3 0x0010 RT3070
/* Peracom products */
product PERACOM SERIAL1 0x0001 Serial
@@ -1940,42 +3658,78 @@ product PERACOM ENET 0x0002 Ethernet
product PERACOM ENET3 0x0003 At Home Ethernet
product PERACOM ENET2 0x0005 Ethernet
+/* Peraso Technologies, Inc products */
+product PERASO PRS4001 0x4001 PRS4001 WLAN
+
/* Philips products */
product PHILIPS DSS350 0x0101 DSS 350 Digital Speaker System
product PHILIPS DSS 0x0104 DSS XXX Digital Speaker System
product PHILIPS HUB 0x0201 hub
product PHILIPS PCA646VC 0x0303 PCA646VC PC Camera
product PHILIPS PCVC680K 0x0308 PCVC680K Vesta Pro PC Camera
+product PHILIPS SPC900NC 0x0329 SPC 900NC CCD PC Camera
product PHILIPS DSS150 0x0471 DSS 150 Digital Speaker System
+product PHILIPS ACE1001 0x066a AKTAKOM ACE-1001 cable
+product PHILIPS SPE3030CC 0x083a USB 2.0 External Disk
product PHILIPS SNU5600 0x1236 SNU5600
product PHILIPS UM10016 0x1552 ISP 1581 Hi-Speed USB MPEG2 Encoder Reference Kit
product PHILIPS DIVAUSB 0x1801 DIVA USB mp3 player
+product PHILIPS RT2870 0x200f RT2870
/* Philips Semiconductor products */
-product PHILIPSSEMI HUB1122 0x1122 hub
+product PHILIPSSEMI HUB1122 0x1122 HUB
+
+/* Megatec */
+product MEGATEC UPS 0x5161 Phoenixtec protocol based UPS
/* P.I. Engineering products */
product PIENGINEERING PS2USB 0x020b PS2 to Mac USB Adapter
/* Planex Communications products */
product PLANEX GW_US11H 0x14ea GW-US11H WLAN
+product PLANEX2 RTL8188CUS 0x1201 RTL8188CUS
product PLANEX2 GW_US11S 0x3220 GW-US11S WLAN
product PLANEX2 GW_US54GXS 0x5303 GW-US54GXS WLAN
+product PLANEX2 GW_US300 0x5304 GW-US300
+product PLANEX2 RTL8188CU_1 0xab2a RTL8188CU
+product PLANEX2 RTL8188CU_2 0xed17 RTL8188CU
+product PLANEX2 RTL8188CU_3 0x4902 RTL8188CU
+product PLANEX2 RTL8188CU_4 0xab2e RTL8188CU
+product PLANEX2 RTL8192CU 0xab2b RTL8192CU
product PLANEX2 GWUS54HP 0xab01 GW-US54HP
+product PLANEX2 GWUS300MINIS 0xab24 GW-US300MiniS
+product PLANEX2 RT3070 0xab25 RT3070
+product PLANEX2 MZKUE150N 0xab2f MZK-UE150N
+product PLANEX2 GW900D 0xab30 GW-900D
product PLANEX2 GWUS54MINI2 0xab50 GW-US54Mini2
product PLANEX2 GWUS54SG 0xc002 GW-US54SG
product PLANEX2 GWUS54GZL 0xc007 GW-US54GZL
product PLANEX2 GWUS54GD 0xed01 GW-US54GD
product PLANEX2 GWUSMM 0xed02 GW-USMM
+product PLANEX2 RT2870 0xed06 RT2870
+product PLANEX2 GWUSMICRON 0xed14 GW-USMicroN
+product PLANEX2 GWUSVALUEEZ 0xed17 GW-USValue-EZ
product PLANEX3 GWUS54GZ 0xab10 GW-US54GZ
product PLANEX3 GU1000T 0xab11 GU-1000T
product PLANEX3 GWUS54MINI 0xab13 GW-US54Mini
+product PLANEX2 GWUSNANO 0xab28 GW-USNano
/* Plextor Corp. */
product PLEXTOR 40_12_40U 0x0011 PlexWriter 40/12/40U
+/* Ploytec GmbH */
+product PLOYTEC SPL_CRIMSON_1 0xc150 SPL Crimson Revision 1
+
/* PLX products */
product PLX TESTBOARD 0x9060 test board
+product PLX CA42 0xac70 CA-42
+
+/* PowerCOM products */
+product POWERCOM IMPERIAL_SERIES 0x00a2 IMPERIAL Series
+product POWERCOM SMART_KING_PRO 0x00a3 Smart KING Pro
+product POWERCOM WOW 0x00a4 WOW
+product POWERCOM VANGUARD 0x00a5 Vanguard
+product POWERCOM BLACK_KNIGHT_PRO 0x00a6 Black Knight Pro
/* PNY products */
product PNY ATTACHE2 0x0010 USB 2.0 Flash Drive
@@ -1987,6 +3741,9 @@ product PORTGEAR EA9 0x0009 Ethernet
/* Portsmith products */
product PORTSMITH EEA 0x3003 Express Ethernet
+/* Posiflex products */
+product POSIFLEX PP7000 0x0300 FTDI compatible adapter
+
/* Primax products */
product PRIMAX G2X300 0x0300 G2-200 scanner
product PRIMAX G2E300 0x0301 G2E-300 scanner
@@ -2004,18 +3761,28 @@ product PRIMAX G2E600 0x0383 G2E-600 scanner
product PRIMAX COMFORT 0x4d01 Comfort
product PRIMAX MOUSEINABOX 0x4d02 Mouse-in-a-Box
product PRIMAX PCGAUMS1 0x4d04 Sony PCGA-UMS1
+product PRIMAX HP_RH304AA 0x4d17 HP RH304AA mouse
/* Prolific products */
product PROLIFIC PL2301 0x0000 PL2301 Host-Host interface
product PROLIFIC PL2302 0x0001 PL2302 Host-Host interface
+product PROLIFIC MOTOROLA 0x0307 Motorola Cable
product PROLIFIC RSAQ2 0x04bb PL2303 Serial (IODATA USB-RSAQ2)
+product PROLIFIC ALLTRONIX_GPRS 0x0609 Alltronix ACM003U00 modem
+product PROLIFIC ALDIGA_AL11U 0x0611 AlDiga AL-11U modem
+product PROLIFIC MICROMAX_610U 0x0612 Micromax 610U
+product PROLIFIC DCU11 0x1234 DCU-11 Phone Cable
+product PROLIFIC UIC_MSR206 0x206a UIC MSR206 Card Reader
product PROLIFIC PL2303 0x2303 PL2303 Serial (ATEN/IOGEAR UC232A)
product PROLIFIC PL2305 0x2305 Parallel printer
product PROLIFIC ATAPI4 0x2307 ATAPI-4 Controller
product PROLIFIC PL2501 0x2501 PL2501 Host-Host interface
+product PROLIFIC PL2506 0x2506 PL2506 USB to IDE Bridge
+product PROLIFIC PL27A1 0x27A1 PL27A1 USB 3.0 Host-Host interface
+product PROLIFIC HCR331 0x331a HCR331 Hybrid Card Reader
product PROLIFIC PHAROS 0xaaa0 Prolific Pharos
product PROLIFIC RSAQ3 0xaaa2 PL2303 Serial Adapter (IODATA USB-RSAQ3)
-product PROLIFIC2 WSIM 0x2001 Willcom WSIM
+product PROLIFIC2 PL2303 0x2303 PL2303 Serial Adapter
/* Putercom products */
product PUTERCOM UPA100 0x047e USB-1284 BRIDGE
@@ -2023,20 +3790,135 @@ product PUTERCOM UPA100 0x047e USB-1284 BRIDGE
/* Qcom products */
product QCOM RT2573 0x6196 RT2573
product QCOM RT2573_2 0x6229 RT2573
+product QCOM RT2573_3 0x6238 RT2573
+product QCOM RT2870 0x6259 RT2870
+
+/* QI-hardware */
+product QIHARDWARE JTAGSERIAL 0x0713 FTDI compatible adapter
+
+/* Qisda products */
+product QISDA H21_1 0x4512 3G modem
+product QISDA H21_2 0x4523 3G modem
+product QISDA H20_1 0x4515 3G modem
+product QISDA H20_2 0x4519 3G modem
/* Qualcomm products */
product QUALCOMM CDMA_MSM 0x6000 CDMA Technologies MSM phone
+product QUALCOMM NTT_L02C_MODEM 0x618f NTT DOCOMO L-02C
+product QUALCOMM NTT_L02C_STORAGE 0x61dd NTT DOCOMO L-02C
+product QUALCOMM2 MF330 0x6613 MF330
product QUALCOMM2 RWT_FCT 0x3100 RWT FCT-CDMA 2000 1xRTT modem
product QUALCOMM2 CDMA_MSM 0x3196 CDMA Technologies MSM modem
+product QUALCOMM2 AC8700 0x6000 AC8700
+product QUALCOMM2 VW110L 0x1000 Vertex Wireless 110L modem
+product QUALCOMM2 SIM5218 0x9000 SIM5218
+product QUALCOMM2 WM620 0x9002 Neoway WM620
+product QUALCOMM2 GOBI2000_QDL 0x9204 Qualcomm Gobi 2000 QDL
+product QUALCOMM2 GOBI2000 0x9205 Qualcomm Gobi 2000 modem
+product QUALCOMM2 VT80N 0x6500 Venus VT80N
+product QUALCOMM3 VFAST2 0x9909 Venus Fast2 modem
product QUALCOMMINC CDMA_MSM 0x0001 CDMA Technologies MSM modem
+product QUALCOMMINC E0002 0x0002 3G modem
+product QUALCOMMINC E0003 0x0003 3G modem
+product QUALCOMMINC E0004 0x0004 3G modem
+product QUALCOMMINC E0005 0x0005 3G modem
+product QUALCOMMINC E0006 0x0006 3G modem
+product QUALCOMMINC E0007 0x0007 3G modem
+product QUALCOMMINC E0008 0x0008 3G modem
+product QUALCOMMINC E0009 0x0009 3G modem
+product QUALCOMMINC E000A 0x000a 3G modem
+product QUALCOMMINC E000B 0x000b 3G modem
+product QUALCOMMINC E000C 0x000c 3G modem
+product QUALCOMMINC E000D 0x000d 3G modem
+product QUALCOMMINC E000E 0x000e 3G modem
+product QUALCOMMINC E000F 0x000f 3G modem
+product QUALCOMMINC E0010 0x0010 3G modem
+product QUALCOMMINC E0011 0x0011 3G modem
+product QUALCOMMINC E0012 0x0012 3G modem
+product QUALCOMMINC E0013 0x0013 3G modem
+product QUALCOMMINC E0014 0x0014 3G modem
+product QUALCOMMINC MF628 0x0015 3G modem
+product QUALCOMMINC MF633R 0x0016 ZTE WCDMA modem
+product QUALCOMMINC E0017 0x0017 3G modem
+product QUALCOMMINC E0018 0x0018 3G modem
+product QUALCOMMINC E0019 0x0019 3G modem
+product QUALCOMMINC E0020 0x0020 3G modem
+product QUALCOMMINC E0021 0x0021 3G modem
+product QUALCOMMINC E0022 0x0022 3G modem
+product QUALCOMMINC E0023 0x0023 3G modem
+product QUALCOMMINC E0024 0x0024 3G modem
+product QUALCOMMINC E0025 0x0025 3G modem
+product QUALCOMMINC E0026 0x0026 3G modem
+product QUALCOMMINC E0027 0x0027 3G modem
+product QUALCOMMINC E0028 0x0028 3G modem
+product QUALCOMMINC E0029 0x0029 3G modem
+product QUALCOMMINC E0030 0x0030 3G modem
+product QUALCOMMINC MF626 0x0031 3G modem
+product QUALCOMMINC E0032 0x0032 3G modem
+product QUALCOMMINC E0033 0x0033 3G modem
+product QUALCOMMINC E0037 0x0037 3G modem
+product QUALCOMMINC E0039 0x0039 3G modem
+product QUALCOMMINC E0042 0x0042 3G modem
+product QUALCOMMINC E0043 0x0043 3G modem
+product QUALCOMMINC E0048 0x0048 3G modem
+product QUALCOMMINC E0049 0x0049 3G modem
+product QUALCOMMINC E0051 0x0051 3G modem
+product QUALCOMMINC E0052 0x0052 3G modem
+product QUALCOMMINC ZTE_STOR2 0x0053 USB ZTE Storage
+product QUALCOMMINC E0054 0x0054 3G modem
+product QUALCOMMINC E0055 0x0055 3G modem
+product QUALCOMMINC E0057 0x0057 3G modem
+product QUALCOMMINC E0058 0x0058 3G modem
+product QUALCOMMINC E0059 0x0059 3G modem
+product QUALCOMMINC E0060 0x0060 3G modem
+product QUALCOMMINC E0061 0x0061 3G modem
+product QUALCOMMINC E0062 0x0062 3G modem
+product QUALCOMMINC E0063 0x0063 3G modem
+product QUALCOMMINC E0064 0x0064 3G modem
+product QUALCOMMINC E0066 0x0066 3G modem
+product QUALCOMMINC E0069 0x0069 3G modem
+product QUALCOMMINC E0070 0x0070 3G modem
+product QUALCOMMINC E0073 0x0073 3G modem
+product QUALCOMMINC E0076 0x0076 3G modem
+product QUALCOMMINC E0078 0x0078 3G modem
+product QUALCOMMINC E0082 0x0082 3G modem
+product QUALCOMMINC E0086 0x0086 3G modem
+product QUALCOMMINC MF112 0x0103 3G modem
+product QUALCOMMINC SURFSTICK 0x0117 1&1 Surf Stick
+product QUALCOMMINC K3772_Z_INIT 0x1179 K3772-Z Initial
+product QUALCOMMINC K3772_Z 0x1181 K3772-Z
+product QUALCOMMINC ZTE_MF730M 0x1420 3G modem
+product QUALCOMMINC MF195E_INIT 0x1514 MF195E initial
+product QUALCOMMINC MF195E 0x1516 MF195E
product QUALCOMMINC ZTE_STOR 0x2000 USB ZTE Storage
-
-/* Qtronix products */
-product QTRONIX 980N 0x2011 Scorpion-980N keyboard
+product QUALCOMMINC E2002 0x2002 3G modem
+product QUALCOMMINC E2003 0x2003 3G modem
+product QUALCOMMINC AC682 0xffdd CDMA 1xEVDO USB modem
+product QUALCOMMINC AC682_INIT 0xffde CDMA 1xEVDO USB modem (initial)
+product QUALCOMMINC AC8710 0xfff1 3G modem
+product QUALCOMMINC AC2726 0xfff5 3G modem
+product QUALCOMMINC AC8700 0xfffe CDMA 1xEVDO USB modem
+
+/* Quanta products */
+product QUANTA RW6815_1 0x00ce HP iPAQ rw6815
+product QUANTA RT3070 0x0304 RT3070
+product QUANTA Q101_STOR 0x1000 USB Q101 Storage
+product QUANTA Q101 0xea02 HSDPA modem
+product QUANTA Q111 0xea03 HSDPA modem
+product QUANTA GLX 0xea04 HSDPA modem
+product QUANTA GKE 0xea05 HSDPA modem
+product QUANTA GLE 0xea06 HSDPA modem
+product QUANTA RW6815R 0xf003 HP iPAQ rw6815 RNDIS
+
+/* Quectel products */
+product QUECTEL EC25 0x0125 LTE modem
/* Quickshot products */
product QUICKSHOT STRIKEPAD 0x6238 USB StrikePad
+/* Qtronix products */
+product QTRONIX 980N 0x2011 Scorpion-980N keyboard
+
/* Radio Shack */
product RADIOSHACK USBCABLE 0x4026 USB to Serial Cable
@@ -2045,15 +3927,78 @@ product RAINBOW IKEY2000 0x1200 i-Key 2000
/* Ralink Technology products */
product RALINK RT2570 0x1706 RT2500USB Wireless Adapter
+product RALINK RT2070 0x2070 RT2070
product RALINK RT2570_2 0x2570 RT2500USB Wireless Adapter
product RALINK RT2573 0x2573 RT2501USB Wireless Adapter
product RALINK RT2671 0x2671 RT2601USB Wireless Adapter
+product RALINK RT2770 0x2770 RT2770
+product RALINK RT2870 0x2870 RT2870
+product RALINK RT_STOR 0x2878 USB Storage
+product RALINK RT3070 0x3070 RT3070
+product RALINK RT3071 0x3071 RT3071
+product RALINK RT3072 0x3072 RT3072
+product RALINK RT3370 0x3370 RT3370
+product RALINK RT3572 0x3572 RT3572
+product RALINK RT3573 0x3573 RT3573
+product RALINK RT5370 0x5370 RT5370
+product RALINK RT5372 0x5372 RT5372
+product RALINK RT5572 0x5572 RT5572
+product RALINK RT8070 0x8070 RT8070
product RALINK RT2570_3 0x9020 RT2500USB Wireless Adapter
product RALINK RT2573_2 0x9021 RT2501USB Wireless Adapter
-/* ReakTek products */
+/* RATOC Systems products */
+product RATOC REXUSB60 0xb000 USB serial adapter REX-USB60
+product RATOC REXUSB60F 0xb020 USB serial adapter REX-USB60F
+
+/* Realtek products */
/* Green House and CompUSA OEM this part */
+product REALTEK DUMMY 0x0000 Dummy product
+product REALTEK USB20CRW 0x0158 USB20CRW Card Reader
+product REALTEK RTL8188ETV 0x0179 RTL8188ETV
+product REALTEK RTL8188CTV 0x018a RTL8188CTV
+product REALTEK RTL8821AU_2 0x0811 RTL8821AU
+product REALTEK RTL8188RU_2 0x317f RTL8188RU
product REALTEK USBKR100 0x8150 USBKR100 USB Ethernet
+product REALTEK RTL8152 0x8152 RTL8152 USB Ethernet
+product REALTEK RTL8153 0x8153 RTL8153 USB Ethernet
+product REALTEK RTL8188CE_0 0x8170 RTL8188CE
+product REALTEK RTL8171 0x8171 RTL8171
+product REALTEK RTL8172 0x8172 RTL8172
+product REALTEK RTL8173 0x8173 RTL8173
+product REALTEK RTL8174 0x8174 RTL8174
+product REALTEK RTL8188CU_0 0x8176 RTL8188CU
+product REALTEK RTL8191CU 0x8177 RTL8191CU
+product REALTEK RTL8192CU 0x8178 RTL8192CU
+product REALTEK RTL8188EU 0x8179 RTL8188EU
+product REALTEK RTL8188CU_1 0x817a RTL8188CU
+product REALTEK RTL8188CU_2 0x817b RTL8188CU
+product REALTEK RTL8192CE 0x817c RTL8192CE
+product REALTEK RTL8188RU_1 0x817d RTL8188RU
+product REALTEK RTL8188CE_1 0x817e RTL8188CE
+product REALTEK RTL8188RU_3 0x817f RTL8188RU
+product REALTEK RTL8187 0x8187 RTL8187 Wireless Adapter
+product REALTEK RTL8187B_0 0x8189 RTL8187B Wireless Adapter
+product REALTEK RTL8188CUS 0x818a RTL8188CUS
+product REALTEK RTL8192EU 0x818b RTL8192EU
+product REALTEK RTL8188CU_3 0x8191 RTL8188CU
+product REALTEK RTL8196EU 0x8196 RTL8196EU
+product REALTEK RTL8187B_1 0x8197 RTL8187B Wireless Adapter
+product REALTEK RTL8187B_2 0x8198 RTL8187B Wireless Adapter
+product REALTEK RTL8712 0x8712 RTL8712
+product REALTEK RTL8713 0x8713 RTL8713
+product REALTEK RTL8188CU_COMBO 0x8754 RTL8188CU
+product REALTEK RTL8821AU_1 0xa811 RTL8821AU
+product REALTEK RTL8723BU 0xb720 RTL8723BU
+product REALTEK RTL8192SU 0xc512 RTL8192SU
+product REALTEK RTL8812AU 0x8812 RTL8812AU Wireless Adapter
+
+/* RedOctane products */
+product REDOCTANE DUMMY 0x0000 Dummy product
+product REDOCTANE GHMIDI 0x474b GH MIDI INTERFACE
+
+/* Renesas products */
+product RENESAS RX610 0x0053 RX610 RX-Stick
/* Ricoh products */
product RICOH VGPVCC2 0x1830 VGP-VCC2 Camera
@@ -2063,16 +4008,41 @@ product RICOH VGPVCC2_3 0x1834 VGP-VCC2 Camera
product RICOH VGPVCC7 0x183a VGP-VCC7 Camera
product RICOH VGPVCC8 0x183b VGP-VCC8 Camera
+/* Reiner-SCT products */
+product REINERSCT CYBERJACK_ECOM 0x0100 e-com cyberJack
+
/* Roland products */
+product ROLAND UA100 0x0000 UA-100 Audio I/F
+product ROLAND UM4 0x0002 UM-4 MIDI I/F
+product ROLAND SC8850 0x0003 SC-8850 MIDI Synth
+product ROLAND U8 0x0004 U-8 Audio I/F
+product ROLAND UM2 0x0005 UM-2 MIDI I/F
+product ROLAND SC8820 0x0007 SC-8820 MIDI Synth
+product ROLAND PC300 0x0008 PC-300 MIDI Keyboard
product ROLAND UM1 0x0009 UM-1 MIDI I/F
+product ROLAND SK500 0x000b SK-500 MIDI Keyboard
+product ROLAND SCD70 0x000c SC-D70 MIDI Synth
product ROLAND UM880N 0x0014 EDIROL UM-880 MIDI I/F (native)
product ROLAND UM880G 0x0015 EDIROL UM-880 MIDI I/F (generic)
+product ROLAND SD90 0x0016 SD-90 MIDI Synth
+product ROLAND UM550 0x0023 UM-550 MIDI I/F
+product ROLAND SD20 0x0027 SD-20 MIDI Synth
+product ROLAND SD80 0x0029 SD-80 MIDI Synth
+product ROLAND UA700 0x002b UA-700 Audio I/F
+product ROLAND PCR300 0x0033 EDIROL PCR-300 MIDI I/F
+product ROLAND UA25EX_AD 0x00e6 EDIROL UA-25EX (Advanced Driver)
+product ROLAND UA25EX_CC 0x00e7 EDIROL UA-25EX (Class Compliant)
/* Rockfire products */
product ROCKFIRE GAMEPAD 0x2033 gamepad 203USB
/* RATOC Systems products */
product RATOC REXUSB60 0xb000 REX-USB60
+product RATOC REXUSB60F 0xb020 REX-USB60F
+
+/* RT system products */
+product RTSYSTEMS CT29B 0x9e54 FTDI compatible adapter
+product RTSYSTEMS SERIAL_VX7 0x9e52 FTDI compatible adapter
/* Sagem products */
product SAGEM USBSERIAL 0x0027 USB-Serial Controller
@@ -2080,9 +4050,13 @@ product SAGEM XG760A 0x004a XG-760A
product SAGEM XG76NA 0x0062 XG-76NA
/* Samsung products */
+product SAMSUNG WIS09ABGN 0x2018 WIS09ABGN Wireless LAN adapter
product SAMSUNG ML6060 0x3008 ML-6060 laser printer
product SAMSUNG YP_U2 0x5050 YP-U2 MP3 Player
-product SAMSUNG I500 0x6601 I500 Palm USB Phone
+product SAMSUNG YP_U4 0x5092 YP-U4 MP3 Player
+product SAMSUNG I500 0x6601 I500 Palm USB Phone
+product SAMSUNG I330 0x8001 I330 phone cradle
+product SAMSUNG2 RT2870_1 0x2018 RT2870
/* Samsung Techwin products */
product SAMSUNG_TECHWIN DIGIMAX_410 0x000a Digimax 410
@@ -2094,9 +4068,15 @@ product SANDISK SDDR05 0x0005 ImageMate SDDR-05
product SANDISK SDDR12 0x0100 ImageMate SDDR-12
product SANDISK SDDR09 0x0200 ImageMate SDDR-09
product SANDISK SDDR75 0x0810 ImageMate SDDR-75
+product SANDISK SDCZ2_128 0x7100 Cruzer Mini 128MB
product SANDISK SDCZ2_256 0x7104 Cruzer Mini 256MB
product SANDISK SDCZ4_128 0x7112 Cruzer Micro 128MB
product SANDISK SDCZ4_256 0x7113 Cruzer Micro 256MB
+product SANDISK SDCZ48_32 0x5581 Ultra 32GB
+product SANDISK IMAGEMATE_SDDR289 0xb6ba ImageMate SDDR-289
+
+/* Sanwa Electric Instrument Co., Ltd. products */
+product SANWA KB_USB2 0x0701 KB-USB2 multimeter cable
/* Sanyo Electric products */
product SANYO SCP4900 0x0701 Sanyo SCP-4900 USB Phone
@@ -2105,12 +4085,79 @@ product SANYO SCP4900 0x0701 Sanyo SCP-4900 USB Phone
product SCANLOGIC SL11R 0x0002 SL11R IDE Adapter
product SCANLOGIC 336CX 0x0300 Phantom 336CX - C3 scanner
+/* Schweitzer Engineering Laboratories products */
+product SEL C662 0x0001 C662 Cable
+
+/* Sealevel products */
+product SEALEVEL 2101 0x2101 FTDI compatible adapter
+product SEALEVEL 2102 0x2102 FTDI compatible adapter
+product SEALEVEL 2103 0x2103 FTDI compatible adapter
+product SEALEVEL 2104 0x2104 FTDI compatible adapter
+product SEALEVEL 2106 0x9020 FTDI compatible adapter
+product SEALEVEL 2201_1 0x2211 FTDI compatible adapter
+product SEALEVEL 2201_2 0x2221 FTDI compatible adapter
+product SEALEVEL 2202_1 0x2212 FTDI compatible adapter
+product SEALEVEL 2202_2 0x2222 FTDI compatible adapter
+product SEALEVEL 2203_1 0x2213 FTDI compatible adapter
+product SEALEVEL 2203_2 0x2223 FTDI compatible adapter
+product SEALEVEL 2401_1 0x2411 FTDI compatible adapter
+product SEALEVEL 2401_2 0x2421 FTDI compatible adapter
+product SEALEVEL 2401_3 0x2431 FTDI compatible adapter
+product SEALEVEL 2401_4 0x2441 FTDI compatible adapter
+product SEALEVEL 2402_1 0x2412 FTDI compatible adapter
+product SEALEVEL 2402_2 0x2422 FTDI compatible adapter
+product SEALEVEL 2402_3 0x2432 FTDI compatible adapter
+product SEALEVEL 2402_4 0x2442 FTDI compatible adapter
+product SEALEVEL 2403_1 0x2413 FTDI compatible adapter
+product SEALEVEL 2403_2 0x2423 FTDI compatible adapter
+product SEALEVEL 2403_3 0x2433 FTDI compatible adapter
+product SEALEVEL 2403_4 0x2443 FTDI compatible adapter
+product SEALEVEL 2801_1 0x2811 FTDI compatible adapter
+product SEALEVEL 2801_2 0x2821 FTDI compatible adapter
+product SEALEVEL 2801_3 0x2831 FTDI compatible adapter
+product SEALEVEL 2801_4 0x2841 FTDI compatible adapter
+product SEALEVEL 2801_5 0x2851 FTDI compatible adapter
+product SEALEVEL 2801_6 0x2861 FTDI compatible adapter
+product SEALEVEL 2801_7 0x2871 FTDI compatible adapter
+product SEALEVEL 2801_8 0x2881 FTDI compatible adapter
+product SEALEVEL 2802_1 0x2812 FTDI compatible adapter
+product SEALEVEL 2802_2 0x2822 FTDI compatible adapter
+product SEALEVEL 2802_3 0x2832 FTDI compatible adapter
+product SEALEVEL 2802_4 0x2842 FTDI compatible adapter
+product SEALEVEL 2802_5 0x2852 FTDI compatible adapter
+product SEALEVEL 2802_6 0x2862 FTDI compatible adapter
+product SEALEVEL 2802_7 0x2872 FTDI compatible adapter
+product SEALEVEL 2802_8 0x2882 FTDI compatible adapter
+product SEALEVEL 2803_1 0x2813 FTDI compatible adapter
+product SEALEVEL 2803_2 0x2823 FTDI compatible adapter
+product SEALEVEL 2803_3 0x2833 FTDI compatible adapter
+product SEALEVEL 2803_4 0x2843 FTDI compatible adapter
+product SEALEVEL 2803_5 0x2853 FTDI compatible adapter
+product SEALEVEL 2803_6 0x2863 FTDI compatible adapter
+product SEALEVEL 2803_7 0x2873 FTDI compatible adapter
+product SEALEVEL 2803_8 0x2883 FTDI compatible adapter
+
/* Senao products */
+product SENAO EUB1200AC 0x0100 EnGenius EUB1200AC
+product SENAO RT2870_3 0x0605 RT2870
+product SENAO RT2870_4 0x0615 RT2870
product SENAO NUB8301 0x2000 NUB-8301
+product SENAO RT2870_1 0x9701 RT2870
+product SENAO RT2870_2 0x9702 RT2870
+product SENAO RT3070 0x9703 RT3070
+product SENAO RT3071 0x9705 RT3071
+product SENAO RT3072_1 0x9706 RT3072
+product SENAO RT3072_2 0x9707 RT3072
+product SENAO RT3072_3 0x9708 RT3072
+product SENAO RT3072_4 0x9709 RT3072
+product SENAO RT3072_5 0x9801 RT3072
+product SENAO RTL8192SU_1 0x9603 RTL8192SU
+product SENAO RTL8192SU_2 0x9605 RTL8192SU
/* ShanTou products */
product SHANTOU ST268 0x0268 ST268
product SHANTOU DM9601 0x9601 DM 9601
+product SHANTOU ADM8515 0x8515 ADM8515
/* Shark products */
product SHARK PA 0x0400 Pocket Adapter
@@ -2122,6 +4169,8 @@ product SHARP SL5600 0x8006 Zaurus SL-5600 PDA
product SHARP SLC700 0x8007 Zaurus SL-C700 PDA
product SHARP SLC750 0x9031 Zaurus SL-C750 PDA
product SHARP WZERO3ES 0x9123 W-ZERO3 ES Smartphone
+product SHARP WZERO3ADES 0x91ac Advanced W-ZERO3 ES Smartphone
+product SHARP WILLCOM03 0x9242 WILLCOM03
/* Shuttle Technology products */
product SHUTTLE EUSB 0x0001 E-USB Bridge
@@ -2146,42 +4195,82 @@ product SIEMENS2 WL54G 0x3c06 54g USB Network Adapter
product SIEMENS3 SX1 0x0001 SX1
product SIEMENS3 X65 0x0003 X65
product SIEMENS3 X75 0x0004 X75
+product SIEMENS3 EF81 0x0005 EF81
/* Sierra Wireless products */
+product SIERRA EM5625 0x0017 EM5625
+product SIERRA MC5720_2 0x0018 MC5720
+product SIERRA MC5725 0x0020 MC5725
product SIERRA AIRCARD580 0x0112 Sierra Wireless AirCard 580
product SIERRA AIRCARD595 0x0019 Sierra Wireless AirCard 595
product SIERRA AC595U 0x0120 Sierra Wireless AirCard 595U
product SIERRA AC597E 0x0021 Sierra Wireless AirCard 597E
+product SIERRA EM5725 0x0022 EM5725
product SIERRA C597 0x0023 Sierra Wireless Compass 597
-product SIERRA AC880 0x6850 Sierra Wireless AirCard 880
-product SIERRA AC881 0x6851 Sierra Wireless AirCard 881
-product SIERRA AC880E 0x6852 Sierra Wireless AirCard 880E
-product SIERRA AC881E 0x6853 Sierra Wireless AirCard 881E
-product SIERRA AC880U 0x6855 Sierra Wireless AirCard 880U
-product SIERRA AC881U 0x6856 Sierra Wireless AirCard 881U
-product SIERRA EM5625 0x0017 EM5625
+product SIERRA MC5727 0x0024 MC5727
+product SIERRA T598 0x0025 T598
+product SIERRA T11 0x0026 T11
+product SIERRA AC402 0x0027 AC402
+product SIERRA MC5728 0x0028 MC5728
+product SIERRA E0029 0x0029 E0029
+product SIERRA AIRCARD580 0x0112 Sierra Wireless AirCard 580
+product SIERRA AC595U 0x0120 Sierra Wireless AirCard 595U
product SIERRA MC5720 0x0218 MC5720 Wireless Modem
-product SIERRA MC5720_2 0x0018 MC5720
-product SIERRA MC5725 0x0020 MC5725
product SIERRA MINI5725 0x0220 Sierra Wireless miniPCI 5275
+product SIERRA MC5727_2 0x0224 MC5727
product SIERRA MC8755_2 0x6802 MC8755
product SIERRA MC8765 0x6803 MC8765
product SIERRA MC8755 0x6804 MC8755
+product SIERRA MC8765_2 0x6805 MC8765
+product SIERRA MC8755_4 0x6808 MC8755
+product SIERRA MC8765_3 0x6809 MC8765
product SIERRA AC875U 0x6812 AC875U HSDPA USB Modem
product SIERRA MC8755_3 0x6813 MC8755 HSDPA
product SIERRA MC8775_2 0x6815 MC8775
-product SIERRA AIRCARD875 0x6820 Aircard 875 HSDPA
+product SIERRA MC8775 0x6816 MC8775
+product SIERRA AC875 0x6820 Sierra Wireless AirCard 875
+product SIERRA AC875U_2 0x6821 AC875U
+product SIERRA AC875E 0x6822 AC875E
product SIERRA MC8780 0x6832 MC8780
product SIERRA MC8781 0x6833 MC8781
+product SIERRA MC8780_2 0x6834 MC8780
+product SIERRA MC8781_2 0x6835 MC8781
+product SIERRA MC8780_3 0x6838 MC8780
+product SIERRA MC8781_3 0x6839 MC8781
+product SIERRA MC8785 0x683A MC8785
+product SIERRA MC8785_2 0x683B MC8785
+product SIERRA MC8790 0x683C MC8790
+product SIERRA MC8791 0x683D MC8791
+product SIERRA MC8792 0x683E MC8792
+product SIERRA AC880 0x6850 Sierra Wireless AirCard 880
+product SIERRA AC881 0x6851 Sierra Wireless AirCard 881
+product SIERRA AC880E 0x6852 Sierra Wireless AirCard 880E
+product SIERRA AC881E 0x6853 Sierra Wireless AirCard 881E
+product SIERRA AC880U 0x6855 Sierra Wireless AirCard 880U
+product SIERRA AC881U 0x6856 Sierra Wireless AirCard 881U
+product SIERRA AC885E 0x6859 AC885E
+product SIERRA AC885E_2 0x685A AC885E
+product SIERRA AC885U 0x6880 Sierra Wireless AirCard 885U
+product SIERRA C888 0x6890 C888
+product SIERRA C22 0x6891 C22
+product SIERRA E6892 0x6892 E6892
+product SIERRA E6893 0x6893 E6893
+product SIERRA MC8700 0x68A3 MC8700
+product SIERRA MC7354 0x68C0 MC7354
+product SIERRA MC7355 0x9041 MC7355
+product SIERRA MC7430 0x9071 Sierra Wireless MC7430 Qualcomm Snapdragon X7 LTE-A
+product SIERRA AC313U 0x68aa Sierra Wireless AirCard 313U
product SIERRA TRUINSTALL 0x0fff Aircard Tru Installer
/* Sigmatel products */
+product SIGMATEL WBT_3052 0x4200 WBT-3052 IrDA/USB Bridge
product SIGMATEL I_BEAD100 0x8008 i-Bead 100 MP3 Player
/* SIIG products */
/* Also: Omnidirectional Control Technology products */
product SIIG DIGIFILMREADER 0x0004 DigiFilm-Combo Reader
product SIIG WINTERREADER 0x0330 WINTERREADER Reader
+product SIIG2 DK201 0x0103 FTDI compatible adapter
product SIIG2 USBTOETHER 0x0109 USB TO Ethernet
product SIIG2 US2308 0x0421 Serial
@@ -2190,21 +4279,76 @@ product SILICOM U2E 0x0001 U2E
product SILICOM GPE 0x0002 Psion Gold Port Ethernet
/* SI Labs */
+product SILABS VSTABI 0x0f91 VStabi Controller
+product SILABS ARKHAM_DS101_M 0x1101 Arkham DS101 Monitor
+product SILABS ARKHAM_DS101_A 0x1601 Arkham DS101 Adapter
+product SILABS BSM7DUSB 0x800a SPORTident BSM7-D USB
product SILABS POLOLU 0x803b Pololu Serial
+product SILABS CYGNAL_DEBUG 0x8044 Cygnal Debug Adapter
+product SILABS SB_PARAMOUNT_ME 0x8043 Software Bisque Paramount ME
+product SILABS SAEL 0x8053 SA-EL USB
+product SILABS GSM2228 0x8054 Enfora GSM2228 USB
product SILABS ARGUSISP 0x8066 Argussoft ISP
+product SILABS IMS_USB_RS422 0x806f IMS USB-RS422
product SILABS CRUMB128 0x807a Crumb128 board
+product SILABS OPTRIS_MSPRO 0x80c4 Optris MSpro LT Thermometer
product SILABS DEGREE 0x80ca Degree Controls Inc
+product SILABS TRACIENT 0x80dd Tracient RFID
product SILABS TRAQMATE 0x80ed Track Systems Traqmate
product SILABS SUUNTO 0x80f6 Suunto Sports Instrument
+product SILABS ARYGON_MIFARE 0x8115 Arygon Mifare RFID reader
product SILABS BURNSIDE 0x813d Burnside Telecon Deskmobile
+product SILABS TAMSMASTER 0x813f Tams Master Easy Control
+product SILABS WMRBATT 0x814a WMR RIGblaster Plug&Play
+product SILABS WMRRIGBLASTER 0x814a WMR RIGblaster Plug&Play
+product SILABS WMRRIGTALK 0x814b WMR RIGtalk RT1
+product SILABS B_G_H3000 0x8156 B&G H3000 Data Cable
product SILABS HELICOM 0x815e Helicomm IP-Link 1220-DVM
-product SILABS CP2102 0xea60 SILABS USB UART
+product SILABS HAMLINKUSB 0x815f Timewave HamLinkUSB
+product SILABS AVIT_USB_TTL 0x818b AVIT Research USB-TTL
+product SILABS MJS_TOSLINK 0x819f MJS USB-TOSLINK
+product SILABS WAVIT 0x81a6 ThinkOptics WavIt
+product SILABS MULTIPLEX_RC 0x81a9 Multiplex RC adapter
+product SILABS MSD_DASHHAWK 0x81ac MSD DashHawk
+product SILABS INSYS_MODEM 0x81ad INSYS Modem
product SILABS LIPOWSKY_JTAG 0x81c8 Lipowsky Baby-JTAG
product SILABS LIPOWSKY_LIN 0x81e2 Lipowsky Baby-LIN
+product SILABS AEROCOMM 0x81e7 Aerocomm Radio
+product SILABS ZEPHYR_BIO 0x81e8 Zephyr Bioharness
+product SILABS EMS_C1007 0x81f2 EMS C1007 HF RFID controller
product SILABS LIPOWSKY_HARP 0x8218 Lipowsky HARP-1
-product SILABS CP2102 0xea60 SILABS USB UARTa
+product SILABS C2_EDGE_MODEM 0x822b Commander 2 EDGE(GSM) Modem
+product SILABS CYGNAL_GPS 0x826b Cygnal Fasttrax GPS
+product SILABS TELEGESIS_ETRX2 0x8293 Telegesis ETRX2USB
+product SILABS PROCYON_AVS 0x82f9 Procyon AVS
+product SILABS MC35PU 0x8341 MC35pu
+product SILABS CYGNAL 0x8382 Cygnal
+product SILABS AMBER_AMB2560 0x83a8 Amber Wireless AMB2560
+product SILABS DEKTEK_DTAPLUS 0x83d8 DekTec DTA Plus VHF/UHF Booster
+product SILABS KYOCERA_GPS 0x8411 Kyocera GPS
+product SILABS IRZ_SG10 0x8418 IRZ SG-10 GSM/GPRS Modem
+product SILABS BEI_VCP 0x846e BEI USB Sensor (VCP)
+product SILABS BALLUFF_RFID 0x8477 Balluff RFID reader
+product SILABS AC_SERV_IBUS 0x85ea AC-Services IBUS Interface
+product SILABS AC_SERV_CIS 0x85eb AC-Services CIS-IBUS
+product SILABS V_PREON32 0x85f8 Virtenio Preon32
+product SILABS AC_SERV_CAN 0x8664 AC-Services CAN Interface
+product SILABS AC_SERV_OBD 0x8665 AC-Services OBD Interface
+product SILABS MMB_ZIGBEE 0x88a4 MMB Networks ZigBee
+product SILABS INGENI_ZIGBEE 0x88a5 Planet Innovation Ingeni ZigBee
+product SILABS HUBZ 0x8a2a HubZ dual ZigBee and Z-Wave
+product SILABS CP2102 0xea60 SILABS USB UART
product SILABS CP210X_2 0xea61 CP210x Serial
+product SILABS CP210X_3 0xea70 CP210x Serial
+product SILABS CP210X_4 0xea80 CP210x Serial
+product SILABS INFINITY_MIC 0xea71 Infinity GPS-MIC-1 Radio Monophone
+product SILABS USBSCOPE50 0xf001 USBscope50
+product SILABS USBWAVE12 0xf002 USBwave12
+product SILABS USBPULSE100 0xf003 USBpulse100
+product SILABS USBCOUNT50 0xf004 USBcount50
product SILABS2 DCU11CLONE 0xaa26 DCU-11 clone
+product SILABS3 GPRS_MODEM 0xea61 GPRS Modem
+product SILABS4 100EU_MODEM 0xea61 GPRS Modem 100EU
/* Silicon Portals Inc. */
product SILICONPORTALS YAPPH_NF 0x0200 YAP Phone (no firmware)
@@ -2219,6 +4363,35 @@ product SITECOM SERIAL 0x2068 USB to serial cable (v2)
product SITECOM2 WL022 0x182d WL-022
/* Sitecom Europe products */
+product SITECOMEU RT2870_1 0x0017 RT2870
+product SITECOMEU WL168V1 0x000d WL-168 v1
+product SITECOMEU LN030 0x0021 MCS7830
+product SITECOMEU WL168V4 0x0028 WL-168 v4
+product SITECOMEU RT2870_2 0x002b RT2870
+product SITECOMEU RT2870_3 0x002c RT2870
+product SITECOMEU RT2870_4 0x002d RT2870
+product SITECOMEU RT2770 0x0039 RT2770
+product SITECOMEU RT3070_2 0x003b RT3070
+product SITECOMEU RT3070_3 0x003c RT3070
+product SITECOMEU RT3070_4 0x003d RT3070
+product SITECOMEU RT3070 0x003e RT3070
+product SITECOMEU WL608 0x003f WL-608
+product SITECOMEU RT3071 0x0040 RT3071
+product SITECOMEU RT3072_1 0x0041 RT3072
+product SITECOMEU RT3072_2 0x0042 RT3072
+product SITECOMEU WL353 0x0045 WL-353
+product SITECOMEU RT3072_3 0x0047 RT3072
+product SITECOMEU RT3072_4 0x0048 RT3072
+product SITECOMEU RT3072_5 0x004a RT3072
+product SITECOMEU WL349V1 0x004b WL-349 v1
+product SITECOMEU RT3072_6 0x004d RT3072
+product SITECOMEU WLA1000 0x005b WLA-1000
+product SITECOMEU RTL8188CU_1 0x0052 RTL8188CU
+product SITECOMEU RTL8188CU_2 0x005c RTL8188CU
+product SITECOMEU RTL8192CU 0x0061 RTL8192CU
+product SITECOMEU LN032 0x0072 LN-032
+product SITECOMEU WLA7100 0x0074 WLA-7100
+product SITECOMEU LN031 0x0056 LN-031
product SITECOMEU LN028 0x061c LN-028
product SITECOMEU WL113 0x9071 WL-113
product SITECOMEU ZD1211B 0x9075 ZD1211B
@@ -2229,6 +4402,12 @@ product SITECOMEU WL113R2 0x9712 WL-113 rev 2
product SKANHEX MD_7425 0x410a MD 7425 Camera
product SKANHEX SX_520Z 0x5200 SX 520z Camera
+/* Smart Technologies products */
+product SMART PL2303 0x2303 Serial adapter
+
+/* Smart Modular Technologies products */
+product SMART2 G2MEMKEY 0x1700 G2 Memory Key
+
/* SmartBridges products */
product SMARTBRIDGES SMARTLINK 0x0001 SmartLink USB Ethernet
product SMARTBRIDGES SMARTNIC 0x0003 smartNIC 2 PnP Ethernet
@@ -2239,7 +4418,29 @@ product SMC 2202USB 0x0200 10/100 Ethernet
product SMC 2206USB 0x0201 EZ Connect USB Ethernet
product SMC 2862WG 0xee13 EZ Connect Wireless Adapter
product SMC2 2020HUB 0x2020 USB Hub
+product SMC2 2514HUB 0x2514 USB Hub
product SMC3 2662WUSB 0xa002 2662W-AR Wireless
+product SMC2 LAN7800_ETH 0x7800 USB/Ethernet
+product SMC2 LAN7801_ETH 0x7801 USB/Ethernet
+product SMC2 LAN7850_ETH 0x7850 USB/Ethernet
+product SMC2 LAN9500_ETH 0x9500 USB/Ethernet
+product SMC2 LAN9505_ETH 0x9505 USB/Ethernet
+product SMC2 LAN9530_ETH 0x9530 USB/Ethernet
+product SMC2 LAN9730_ETH 0x9730 USB/Ethernet
+product SMC2 LAN9500_SAL10 0x9900 USB/Ethernet
+product SMC2 LAN9505_SAL10 0x9901 USB/Ethernet
+product SMC2 LAN9500A_SAL10 0x9902 USB/Ethernet
+product SMC2 LAN9505A_SAL10 0x9903 USB/Ethernet
+product SMC2 LAN9514_SAL10 0x9904 USB/Ethernet
+product SMC2 LAN9500A_HAL 0x9905 USB/Ethernet
+product SMC2 LAN9505A_HAL 0x9906 USB/Ethernet
+product SMC2 LAN9500_ETH_2 0x9907 USB/Ethernet
+product SMC2 LAN9500A_ETH_2 0x9908 USB/Ethernet
+product SMC2 LAN9514_ETH_2 0x9909 USB/Ethernet
+product SMC2 LAN9500A_ETH 0x9e00 USB/Ethernet
+product SMC2 LAN9505A_ETH 0x9e01 USB/Ethernet
+product SMC2 LAN89530_ETH 0x9e08 USB/Ethernet
+product SMC2 LAN9514_ETH 0xec00 USB/Ethernet
/* SOHOware products */
product SOHOWARE NUB100 0x9100 10/100 USB Ethernet
@@ -2267,23 +4468,55 @@ product SONY CLIE_NX60 0x00da Sony Clie nx60
product SONY CLIE_TH55 0x0144 Sony Clie th55
product SONY CLIE_TJ37 0x0169 Sony Clie tj37
product SONY RF_RECEIVER 0x01db Sony RF mouse/kbd Receiver VGP-WRC1
+product SONY QN3 0x0437 Sony QN3 CMD-Jxx phone cable
/* Sony Ericsson products */
-product SONYERICSSON DCU10 0x0528 USB Cable
+product SONYERICSSON DCU10 0x0528 DCU-10 Phone Data Cable
+product SONYERICSSON DATAPILOT 0x2003 Datapilot Phone Cable
/* SOURCENEXT products */
product SOURCENEXT KEIKAI8 0x039f KeikaiDenwa 8
product SOURCENEXT KEIKAI8_CHG 0x012e KeikaiDenwa 8 with charger
/* SparkLAN products */
-product SPARKLAN RT2573 0x0004 RT2573
+product SPARKLAN RT2573 0x0004 RT2573
+product SPARKLAN RT2870_1 0x0006 RT2870
+product SPARKLAN RT3070 0x0010 RT3070
+
+/* Soundgraph products */
+product SOUNDGRAPH IMON_VFD 0x0044 Antec Veris Elite VFD Panel, Knob, and Remote
+product SOUNDGRAPH SSTONE_LC16 0xffdc Silverstone LC16 VFD Panel, Knob, and Remote
+
+/* Speed Dragon Multimedia products */
+product SPEEDDRAGON MS3303H 0x110b MS3303H Serial
/* Sphairon Access Systems GmbH products */
product SPHAIRON UB801R 0x0110 UB801R
+/* Stelera Wireless products */
+product STELERA ZEROCD 0x1000 Zerocd Installer
+product STELERA C105 0x1002 Stelera/Bandrish C105 USB
+product STELERA E1003 0x1003 3G modem
+product STELERA E1004 0x1004 3G modem
+product STELERA E1005 0x1005 3G modem
+product STELERA E1006 0x1006 3G modem
+product STELERA E1007 0x1007 3G modem
+product STELERA E1008 0x1008 3G modem
+product STELERA E1009 0x1009 3G modem
+product STELERA E100A 0x100a 3G modem
+product STELERA E100B 0x100b 3G modem
+product STELERA E100C 0x100c 3G modem
+product STELERA E100D 0x100d 3G modem
+product STELERA E100E 0x100e 3G modem
+product STELERA E100F 0x100f 3G modem
+product STELERA E1010 0x1010 3G modem
+product STELERA E1011 0x1011 3G modem
+product STELERA E1012 0x1012 3G modem
+
/* STMicroelectronics products */
product STMICRO BIOCPU 0x2016 Biometric Coprocessor
product STMICRO COMMUNICATOR 0x7554 USB Communicator
+product STMICRO ST72682 0xfada USB 2.0 Flash drive controller
/* STSN products */
product STSN STSN0001 0x0001 Internet Access Device
@@ -2297,9 +4530,39 @@ product SUNTAC AS64LX 0x000b SUNTAC U-Cable type A3
product SUNTAC AS144L4 0x0011 SUNTAC U-Cable type A4
/* Sun Microsystems products */
-product SUN KEYBOARD 0x0005 Type 6 USB keyboard
+product SUN KEYBOARD_TYPE_6 0x0005 Type 6 USB keyboard
+product SUN KEYBOARD_TYPE_7 0x00a2 Type 7 USB keyboard
/* XXX The above is a North American PC style keyboard possibly */
product SUN MOUSE 0x0100 Type 6 USB mouse
+product SUN KBD_HUB 0x100e Kbd Hub
+
+/* Sunplus Innovation Technology Inc. products */
+product SUNPLUS USBMOUSE 0x0007 USB Optical Mouse
+
+/* Super Top products */
+product SUPERTOP IDE 0x6600 USB-IDE
+product SUPERTOP FLASHDRIVE 0x121c extrememory Snippy
+
+/* Syntech products */
+product SYNTECH CPT8001C 0x0001 CPT-8001C Barcode scanner
+product SYNTECH CYPHERLAB100 0x1000 CipherLab USB Barcode Scanner
+
+/* Teclast products */
+product TECLAST TLC300 0x3203 USB Media Player
+
+/* Testo products */
+product TESTO USB_INTERFACE 0x0001 FTDI compatible adapter
+
+/* TexTech products */
+product TEXTECH DUMMY 0x0000 Dummy product
+product TEXTECH U2M_1 0x0101 Textech USB MIDI cable
+product TEXTECH U2M_2 0x1806 Textech USB MIDI cable
+
+/* The Mobility Lab products */
+product TML USB_SERIAL 0x0064 FTDI compatible adapter
+
+/* Thurlby Thandar Instrument products */
+product TTI QL355P 0x03e8 FTDI compatible adapter
/* Supra products */
product DIAMOND2 SUPRAEXPRESS56K 0x07da Supra Express 56K modem
@@ -2308,11 +4571,16 @@ product DIAMOND2 RIO600USB 0x5001 Rio 600 USB
product DIAMOND2 RIO800USB 0x5002 Rio 800 USB
/* Surecom Technology products */
+product SURECOM EP9001G2A 0x11f2 EP-9001-G rev 2A
product SURECOM RT2570 0x11f3 RT2570
product SURECOM RT2573 0x31f3 RT2573
/* Sweex products */
product SWEEX ZD1211 0x1809 ZD1211
+product SWEEX2 LW153 0x0153 LW153
+product SWEEX2 LW154 0x0154 LW154
+product SWEEX2 LW303 0x0302 LW303
+product SWEEX2 LW313 0x0313 LW313
/* System TALKS, Inc. */
product SYSTEMTALKS SGCX2UL 0x1920 SGC-X2UL
@@ -2323,6 +4591,10 @@ product TAPWAVE ZODIAC 0x0100 Zodiac
/* Taugagreining products */
product TAUGA CAMERAMATE 0x0005 CameraMate (DPCM_USB)
+/* TCTMobile products */
+product TCTMOBILE X060S 0x0000 X060S 3G modem
+product TCTMOBILE X080S 0xf000 X080S 3G modem
+
/* TDK products */
product TDK UPA9664 0x0115 USB-PDC Adapter UPA9664
product TDK UCA1464 0x0116 USB-cdmaOne Adapter UCA1464
@@ -2341,29 +4613,80 @@ product TEKRAM ZD1211_2 0x6630 ZD1211
/* Telex Communications products */
product TELEX MIC1 0x0001 Enhanced USB Microphone
+/* Telit products */
+product TELIT UC864E 0x1003 UC864E 3G modem
+product TELIT UC864G 0x1004 UC864G 3G modem
+
/* Ten X Technology, Inc. */
product TENX UAUDIO0 0xf211 USB audio headset
+/* ThingM products */
+product THINGM BLINK1 0x01ed USB notification light
+
/* Texas Intel products */
product TI UTUSB41 0x1446 UT-USB41 hub
product TI TUSB2046 0x2046 TUSB2046 hub
+product TI USB3410 0x3410 TI USB 3410 Modem
+product TI USB5052 0x5052 TI USB 5250 Modem
+product TI FRI2 0x5053 TI Fish River Island II
+product TI USB5052_EEPROM 0x505a TI USB 5250 Modem w/Eeprom
+product TI USB5052_FW 0x505f TI USB 5250 Modme w/Firmware running
+product TI USB5152 0x5152 TI USB 5152 Modem
+product TI EZ430 0xf430 TI ex430 development tool
/* Thrustmaster products */
product THRUST FUSION_PAD 0xa0a3 Fusion Digital Gamepad
+/* TLayTech products */
+product TLAYTECH TEU800 0x1682 TEU800 3G modem
+
/* Topre Corporation products */
product TOPRE HHKB 0x0100 HHKB Professional
/* Toshiba Corporation products */
product TOSHIBA POCKETPC_E740 0x0706 PocketPC e740
+product TOSHIBA RT3070 0x0a07 RT3070
+product TOSHIBA G450 0x0d45 G450 modem
+product TOSHIBA HSDPA 0x1302 G450 modem
+product TOSHIBA TRANSMEMORY 0x6545 USB ThumbDrive
+
+/* TP-Link products */
+product TPLINK T4U 0x0101 Archer T4U
+product TPLINK WN821NV5 0x0107 TL-WN821N v5
+product TPLINK WN822NV4 0x0108 TL-WN822N v4
+product TPLINK WN823NV2 0x0109 TL-WN823N v2
+product TPLINK WN722NV2 0x010c TL-WN722N v2
+product TPLINK T4UV2 0x010d Archer T4U ver 2
+product TPLINK T4UHV1 0x0103 Archer T4UH ver 1
+product TPLINK T4UHV2 0x010e Archer T4UH ver 2
+product TPLINK RTL8153 0x0601 RTL8153 USB 10/100/1000 LAN
/* Trek Technology products */
product TREK THUMBDRIVE 0x1111 ThumbDrive
product TREK MEMKEY 0x8888 IBM USB Memory Key
product TREK THUMBDRIVE_8MB 0x9988 ThumbDrive_8MB
+/* TRENDnet products */
+product TRENDNET RTL8192CU 0x624d RTL8192CU
+product TRENDNET TEW646UBH 0x646b TEW-646UBH
+product TRENDNET RTL8188CU 0x648b RTL8188CU
+product TRENDNET TEW805UB 0x805b TEW-805UB
+
/* Tripp-Lite products */
-product TRIPPLITE U209 0x2008 Serial
+product TRIPPLITE U209 0x2008 Serial
+product TRIPPLITE2 OMNIVS1000 0x0001 OMNIVS1000, SMART550USB
+product TRIPPLITE2 AVR550U 0x1003 AVR550U
+product TRIPPLITE2 AVR750U 0x1007 AVR750U
+product TRIPPLITE2 ECO550UPS 0x1008 ECO550UPS
+product TRIPPLITE2 T750_INTL 0x1f06 T750 INTL
+product TRIPPLITE2 RT_2200_INTL 0x1f0a R/T 2200 INTL
+product TRIPPLITE2 OMNI1000LCD 0x2005 OMNI1000LCD
+product TRIPPLITE2 OMNI900LCD 0x2007 OMNI900LCD
+product TRIPPLITE2 SMART_2200RMXL2U 0x3012 smart2200RMXL2U
+product TRIPPLITE2 UPS_3014 0x3014 Unknown UPS
+product TRIPPLITE2 SU1500RTXL2UA 0x4001 SmartOnline SU1500RTXL2UA
+product TRIPPLITE2 SU6000RT4U 0x4002 SmartOnline SU6000RT4U
+product TRIPPLITE2 SU1500RTXL2UA_2 0x4003 SmartOnline SU1500RTXL2UA
/* Trumpion products */
product TRUMPION T33520 0x1001 T33520 USB Flash Card Controller
@@ -2394,6 +4717,7 @@ product UMEDIA TEW444UBEU_NF 0x3007 TEW-444UB EU (no firmware)
product UMEDIA TEW429UB_A 0x300a TEW-429UB_A
product UMEDIA TEW429UB 0x300b TEW-429UB
product UMEDIA TEW429UBC1 0x300d TEW-429UB C1
+product UMEDIA RT2870_1 0x300e RT2870
product UMEDIA ALL0298V2 0x3204 ALL0298 v2
product UMEDIA AR5523_2 0x3205 AR5523
product UMEDIA AR5523_2_NF 0x3206 AR5523 (no firmware)
@@ -2401,14 +4725,28 @@ product UMEDIA AR5523_2_NF 0x3206 AR5523 (no firmware)
/* Universal Access products */
product UNIACCESS PANACHE 0x0101 Panache Surf USB ISDN Adapter
+/* Unknown products */
+product UNKNOWN4 NF_RIC 0x0001 FTDI compatible adapter
+
+/* USI products */
+product USI MC60 0x10c5 MC60 Serial
+
/* U.S. Robotics products */
+product USR USR5422 0x0118 USR5422 WLAN
product USR USR5423 0x0121 USR5423 WLAN
/* VIA Technologies products */
product VIA USB2IDEBRIDGE 0x6204 USB 2.0 IDE Bridge
-/* USI products */
-product USI MC60 0x10c5 MC60 Serial
+/* VIA Labs */
+product VIALABS USB30SATABRIDGE 0x0700 USB 3.0 SATA Bridge
+product VIALABS VL701 0x0701 VL701 USB 3.0 SATA Bridge
+
+/* Vaisala products */
+product VAISALA CABLE 0x0200 USB Interface cable
+
+/* Vertex products */
+product VERTEX VW110L 0x0100 Vertex VW110L modem
/* VidzMedia products */
product VIDZMEDIA MONSTERTV 0x4fb1 MonsterTV P2H
@@ -2438,13 +4776,59 @@ product WACOM GRAPHIRE 0x0010 Graphire
product WACOM GRAPHIRE3_4X5 0x0013 Graphire 3 4x5
product WACOM INTUOSA5 0x0021 Intuos A5
product WACOM GD0912U 0x0022 Intuos 9x12 Graphics Tablet
-/* WCH products*/
+
+/* WAGO Kontakttechnik GmbH products */
+product WAGO SERVICECABLE 0x07a6 USB Service Cable 750-923
+
+/* WaveSense products */
+product WAVESENSE JAZZ 0xaaaa Jazz blood glucose meter
+
+/* WCH products */
product WCH CH341SER 0x5523 CH341/CH340 USB-Serial Bridge
+product WCH2 DUMMY 0x0000 Dummy product
+product WCH2 CH341SER_2 0x5523 CH341/CH340 USB-Serial Bridge
+product WCH2 CH341SER 0x7523 CH341/CH340 USB-Serial Bridge
+product WCH2 U2M 0X752d CH345 USB2.0-MIDI
+
+/* West Mountain Radio products */
+product WESTMOUNTAIN RIGBLASTER_ADVANTAGE 0x0003 RIGblaster Advantage
+
/* Western Digital products */
product WESTERN COMBO 0x0200 Firewire USB Combo
product WESTERN EXTHDD 0x0400 External HDD
product WESTERN HUB 0x0500 USB HUB
product WESTERN MYBOOK 0x0901 MyBook External HDD
+product WESTERN MYPASSPORT_00 0x0704 MyPassport External HDD
+product WESTERN MYPASSPORT_11 0x0741 MyPassport External HDD
+product WESTERN MYPASSPORT_01 0x0746 MyPassport External HDD
+product WESTERN MYPASSPORT_02 0x0748 MyPassport External HDD
+product WESTERN MYPASSPORT_03 0x074A MyPassport External HDD
+product WESTERN MYPASSPORT_04 0x074C MyPassport External HDD
+product WESTERN MYPASSPORT_05 0x074E MyPassport External HDD
+product WESTERN MYPASSPORT_06 0x07A6 MyPassport External HDD
+product WESTERN MYPASSPORT_07 0x07A8 MyPassport External HDD
+product WESTERN MYPASSPORT_08 0x07AA MyPassport External HDD
+product WESTERN MYPASSPORT_09 0x07AC MyPassport External HDD
+product WESTERN MYPASSPORT_10 0x07AE MyPassport External HDD
+product WESTERN MYPASSPORTES_00 0x070A MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_01 0x071A MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_02 0x0730 MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_03 0x0732 MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_04 0x0740 MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_05 0x0742 MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_06 0x0750 MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_07 0x0752 MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_08 0x07A0 MyPassport Essential External HDD
+product WESTERN MYPASSPORTES_09 0x07A2 MyPassport Essential External HDD
+
+/* WeTelecom products */
+product WETELECOM WM_D200 0x6801 WM-D200
+
+/* WIENER Plein & Baus GmbH products */
+product WIENERPLEINBAUS PL512 0x0010 PL512 PSU
+product WIENERPLEINBAUS RCM 0x0011 RCM Remote Control
+product WIENERPLEINBAUS MPOD 0x0012 MPOD PSU
+product WIENERPLEINBAUS CML 0x0015 CML Data Logger
/* Windbond Electronics */
product WINBOND UH104 0x5518 4-port USB Hub
@@ -2453,8 +4837,10 @@ product WINBOND UH104 0x5518 4-port USB Hub
product WINMAXGROUP FLASH64MC 0x6660 USB Flash Disk 64M-C
/* Wistron NeWeb products */
+product WISTRONNEWEB WNC0600 0x0326 WNC-0600USB
product WISTRONNEWEB UR045G 0x0427 PrismGT USB 2.0 WLAN
product WISTRONNEWEB UR055G 0x0711 UR055G
+product WISTRONNEWEB O8494 0x0804 ORiNOCO 802.11n
product WISTRONNEWEB AR5523_1 0x0826 AR5523
product WISTRONNEWEB AR5523_1_NF 0x0827 AR5523 (no firmware)
product WISTRONNEWEB AR5523_2 0x082a AR5523
@@ -2470,21 +4856,39 @@ product XIRLINK PCCAM 0x8080 IBM PC Camera
product XYRATEX PRISM_GT_1 0x2000 PrismGT USB 2.0 WLAN
product XYRATEX PRISM_GT_2 0x2002 PrismGT USB 2.0 WLAN
-/* Y-E Data products */
-product YEDATA FLASHBUSTERU 0x0000 Flashbuster-U
-
/* Yamaha products */
product YAMAHA UX256 0x1000 UX256 MIDI I/F
+product YAMAHA MU1000 0x1001 MU1000 MIDI Synth.
+product YAMAHA MU2000 0x1002 MU2000 MIDI Synth.
+product YAMAHA MU500 0x1003 MU500 MIDI Synth.
+product YAMAHA UW500 0x1004 UW500 USB Audio I/F
+product YAMAHA MOTIF6 0x1005 MOTIF6 MIDI Synth. Workstation
+product YAMAHA MOTIF7 0x1006 MOTIF7 MIDI Synth. Workstation
+product YAMAHA MOTIF8 0x1007 MOTIF8 MIDI Synth. Workstation
product YAMAHA UX96 0x1008 UX96 MIDI I/F
+product YAMAHA UX16 0x1009 UX16 MIDI I/F
+product YAMAHA S08 0x100e S08 MIDI Keyboard
+product YAMAHA CLP150 0x100f CLP-150 digital piano
+product YAMAHA CLP170 0x1010 CLP-170 digital piano
+product YAMAHA RPU200 0x3104 RP-U200
product YAMAHA RTA54I 0x4000 NetVolante RTA54i Broadband&ISDN Router
-product YAMAHA RTA55I 0x4004 NetVolante RTA55i Broadband VoIP Router
product YAMAHA RTW65B 0x4001 NetVolante RTW65b Broadband Wireless Router
product YAMAHA RTW65I 0x4002 NetVolante RTW65i Broadband&ISDN Wireless Router
+product YAMAHA RTA55I 0x4004 NetVolante RTA55i Broadband VoIP Router
/* Yano products */
product YANO U640MO 0x0101 U640MO-03
product YANO FW800HD 0x05fc METALWEAR-HDD
+/* Y.C. Cable products */
+product YCCABLE PL2303 0x0fba PL2303 Serial
+
+/* Y-E Data products */
+product YEDATA FLASHBUSTERU 0x0000 Flashbuster-U
+
+/* Yiso Wireless Co. products */
+product YISO C893 0xc893 CDMA 2000 1xEVDO PC Card
+
/* Z-Com products */
product ZCOM M4Y750 0x0001 M4Y-750
product ZCOM XI725 0x0002 XI-725/726
@@ -2493,20 +4897,48 @@ product ZCOM XG703A 0x0008 PrismGT USB 2.0 WLAN
product ZCOM ZD1211 0x0011 ZD1211
product ZCOM AR5523 0x0012 AR5523
product ZCOM AR5523_NF 0x0013 AR5523 driver (no firmware)
+product ZCOM XM142 0x0015 XM-142
product ZCOM ZD1211B 0x001a ZD1211B
+product ZCOM RT2870_1 0x0022 RT2870
+product ZCOM UB81 0x0023 UB81
+product ZCOM RT2870_2 0x0025 RT2870
+product ZCOM UB82 0x0026 UB82
+
+/* Zeevo, Inc. products */
+product ZEEVO BLUETOOTH 0x07d0 BT-500 Bluetooth USB Adapter
/* Zinwell products */
product ZINWELL RT2570 0x0260 RT2570
+product ZINWELL RT2870_1 0x0280 RT2870
+product ZINWELL RT2870_2 0x0282 RT2870
+product ZINWELL RT3072_1 0x0283 RT3072
+product ZINWELL RT3072_2 0x0284 RT3072
+product ZINWELL RT3070 0x5257 RT3070
/* Zoom Telephonics, Inc. products */
product ZOOM 2986L 0x9700 2986L Fax modem
+product ZOOM 3095 0x3095 3095 USB Fax modem
/* Zoran Microelectronics products */
product ZORAN EX20DSC 0x4343 Digital Camera EX-20 DSC
+/* ZTE products */
+product ZTE MF622 0x0001 MF622 modem
+product ZTE MF628 0x0015 MF628 modem
+product ZTE MF626 0x0031 MF626 modem
+product ZTE MF820D_INSTALLER 0x0166 MF820D CD
+product ZTE MF820D 0x0167 MF820D modem
+product ZTE INSTALLER 0x2000 UMTS CD
+product ZTE MC2718 0xffe8 MC2718 modem
+product ZTE AC8700 0xfffe CDMA 1xEVDO USB modem
+
/* Zydas Technology Corporation products */
-product ZYDAS ZD1211 0x1211 ZD1211 WLAN abg
+product ZYDAS ZD1201 0x1201 ZD1201
+product ZYDAS ZD1211 0x1211 ZD1211 WLAN abg
product ZYDAS ZD1211B 0x1215 ZD1211B
+product ZYDAS ZD1221 0x1221 ZD1221
+product ZYDAS ALL0298 0xa211 ALL0298
+product ZYDAS ZD1211B_2 0xb215 ZD1211B
/* ZyXEL Communication Co. products */
product ZYXEL OMNI56K 0x1500 Omni 56K Plus
@@ -2515,5 +4947,16 @@ product ZYXEL ZYAIRG220 0x3401 ZyAIR G-220
product ZYXEL G200V2 0x3407 G-200 v2
product ZYXEL AG225H 0x3409 AG-225H
product ZYXEL M202 0x340a M-202
+product ZYXEL G270S 0x340c G-270S
product ZYXEL G220V2 0x340f G-220 v2
product ZYXEL G202 0x3410 G-202
+product ZYXEL RT2573 0x3415 RT2573
+product ZYXEL RT2870_1 0x3416 RT2870
+product ZYXEL NWD271N 0x3417 NWD-271N
+product ZYXEL NWD211AN 0x3418 NWD-211AN
+product ZYXEL RT2870_2 0x341a RT2870
+product ZYXEL RT3070 0x341e NWD2105
+product ZYXEL RTL8192CU 0x341f RTL8192CU
+product ZYXEL NWD2705 0x3421 NWD2705
+product ZYXEL NWD6605 0x3426 ND6605
+product ZYXEL PRESTIGE 0x401a Prestige
diff --git a/usr/src/uts/common/netsmb/mchain.h b/usr/src/uts/common/netsmb/mchain.h
index c5c8512fd7..156671999b 100644
--- a/usr/src/uts/common/netsmb/mchain.h
+++ b/usr/src/uts/common/netsmb/mchain.h
@@ -35,6 +35,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _MCHAIN_H_
@@ -70,10 +72,10 @@
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
/* little-endian values on big-endian (swap) */
-#define letohs(x) BSWAP_16(x)
-#define htoles(x) BSWAP_16(x)
-#define letohl(x) BSWAP_32(x)
-#define htolel(x) BSWAP_32(x)
+#define letohs(x) BSWAP_16(x)
+#define htoles(x) BSWAP_16(x)
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
#define letohq(x) BSWAP_64(x)
#define htoleq(x) BSWAP_64(x)
@@ -93,7 +95,7 @@
* wrappers for streams functions. See: subr_mchain.c
*/
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* BSD-style mbuf "shim" for kernel code. Note, this
@@ -103,6 +105,7 @@
*/
#include <sys/stream.h> /* mblk_t */
+#include <sys/strsun.h> /* MBLKL */
typedef mblk_t mbuf_t;
/* BEGIN CSTYLED */
@@ -112,9 +115,9 @@ typedef mblk_t mbuf_t;
* m_data ... (m_data + m_len)
* In Unix STREAMS, the mblk payload is:
* b_rptr ... b_wptr
- *
+ *
* Here are some handy conversion notes:
- *
+ *
* struct mbuf struct mblk
* m->m_next m->b_cont
* m->m_nextpkt m->b_next
@@ -124,7 +127,7 @@ typedef mblk_t mbuf_t;
* &m->m_dat[MLEN] m->b_datap->db_lim
* M_TRAILINGSPACE(m) MBLKTAIL(m)
* m_freem(m) freemsg(m)
- *
+ *
* Note that mbufs chains also have a special "packet" header,
* which has the length of the whole message. In STREAMS one
* typically just calls msgdsize(m) to get that.
@@ -177,7 +180,7 @@ void m_freem(mbuf_t *);
#define MB_MZERO 3 /* bzero(), mb_put_mem only */
#define MB_MCUSTOM 4 /* use an user defined function */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
struct mbchain {
mblk_t *mb_top;
@@ -224,6 +227,7 @@ void mb_initm(mbchain_t *, mbuf_t *);
void mb_done(mbchain_t *);
void *mb_reserve(mbchain_t *, int size);
+int mb_put_align8(mbchain_t *mbp);
int mb_put_padbyte(mbchain_t *mbp);
int mb_put_uint8(mbchain_t *, uint8_t);
int mb_put_uint16be(mbchain_t *, uint16_t);
@@ -234,6 +238,7 @@ int mb_put_uint64be(mbchain_t *, uint64_t);
int mb_put_uint64le(mbchain_t *, uint64_t);
int mb_put_mem(mbchain_t *, const void *, int, int);
int mb_put_mbuf(mbchain_t *, mbuf_t *);
+int mb_put_mbchain(mbchain_t *, mbchain_t *);
int md_init(mdchain_t *mdp);
void md_initm(mdchain_t *mbp, mbuf_t *m);
@@ -248,5 +253,7 @@ int md_get_uint64be(mdchain_t *, uint64_t *);
int md_get_uint64le(mdchain_t *, uint64_t *);
int md_get_mem(mdchain_t *, void *, int, int);
int md_get_mbuf(mdchain_t *, int, mbuf_t **);
+int md_seek(mdchain_t *, uint32_t);
+uint32_t md_tell(mdchain_t *);
#endif /* !_MCHAIN_H_ */
diff --git a/usr/src/uts/common/netsmb/smb.h b/usr/src/uts/common/netsmb/smb.h
index e3bfc5144c..b57be5bbfe 100644
--- a/usr/src/uts/common/netsmb/smb.h
+++ b/usr/src/uts/common/netsmb/smb.h
@@ -40,6 +40,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_SMB_H_
@@ -66,8 +67,8 @@ enum smb_dialects {
SMB_DIALECT_LANMAN1_0, /* MICROSOFT NETWORKS 3.0, LANMAN1.0 */
SMB_DIALECT_LANMAN2_0, /* LM1.2X002, DOS LM1.2X002, Samba */
SMB_DIALECT_LANMAN2_1, /* DOS LANMAN2.1, LANMAN2.1 */
- SMB_DIALECT_NTLM0_12 /* NT LM 0.12, Windows for Workgroups */
- /* 3.1a, * NT LANMAN 1.0 */
+ SMB_DIALECT_NTLM0_12, /* NT LM 0.12, etc. */
+ SMB_DIALECT_SMB2_FF /* SMB1 negotiate to SMB2 */
};
/*
@@ -82,11 +83,18 @@ enum smb_dialects {
/*
* SMB header
*/
+
#define SMB_SIGNATURE "\xFFSMB"
#define SMB_SIGLEN 4
#define SMB_HDRCMD(p) (*((uchar_t *)(p) + SMB_SIGLEN))
#define SMB_HDRMID(p) (*(ushort_t *)((uchar_t *)(p) + 30))
+#define SMB_HDR_OFF_MID 30
#define SMB_HDRLEN 32
+
+#define SMB_HDR_V1 0xFF
+#define SMB_HDR_V2 0xFE
+#define SMB_HDR_V3E 0xFD /* SMB3 encrypted */
+
/*
* bits in the smb_flags field
*/
@@ -151,6 +159,25 @@ enum smb_dialects {
#define SMB_CAP_COMPRESSED_DATA 0x40000000
#define SMB_CAP_EXT_SECURITY 0x80000000
+/* SMB_COM_TREE_CONNECT_ANDX flags. See [MS-SMB] for a complete description. */
+#define TREE_CONNECT_ANDX_DISCONNECT_TID 0x0001
+#define TREE_CONNECT_ANDX_EXTENDED_SIGNATURES 0x0004
+#define TREE_CONNECT_ANDX_EXTENDED_RESPONSE 0x0008
+
+/*
+ * SMB_COM_TREE_CONNECT_ANDX optional support flags. See [MS-SMB] for a
+ * complete description.
+ */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* supports SearchAttributes */
+#define SMB_SHARE_IS_IN_DFS 0x0002 /* share is managed by DFS */
+#define SMB_CSC_MASK 0x000C /* Offline-caching bits. */
+#define SMB_UNIQUE_FILE_NAME 0x0010 /* Long file names only */
+#define SMB_EXTENDED_SIGNATURES 0x0020 /* Signing key protection. */
+/* See [MS-SMB] for a complete description of SMB_CSC_MASK bits. */
+#define SMB_CSC_CACHE_MANUAL_REINT 0x0000
+#define SMB_CSC_CACHE_AUTO_REINT 0x0004
+#define SMB_CSC_CACHE_VDO 0x0008
+
/*
* File attributes
*/
@@ -372,6 +399,7 @@ enum smb_dialects {
#define SMB_QFS_DEVICE_INFO 0x104
#define SMB_QFS_ATTRIBUTE_INFO 0x105
#define SMB_QFS_UNIX_INFO 0x200
+#define SMB_QFS_POSIX_WHOAMI 0x202
#define SMB_QFS_MAC_FS_INFO 0x301
#define SMB_QFS_VOLUME_INFORMATION 1001
#define SMB_QFS_SIZE_INFORMATION 1003
@@ -381,6 +409,11 @@ enum smb_dialects {
#define SMB_QFS_FULL_SIZE_INFORMATION 1007
#define SMB_QFS_OBJECTID_INFORMATION 1008
+/*
+ * NT Notify Change Compeletion Filter
+ * NT Notify Actions
+ * (We don't use these.)
+ */
/*
* SMB_QFS_ATTRIBUTE_INFO bits.
@@ -403,6 +436,7 @@ enum smb_dialects {
#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
#define FILE_SUPPORTS_ENCRYPTION 0x00020000
#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
/*
* SMB_TRANS2_QUERY_PATH levels
@@ -424,9 +458,12 @@ enum smb_dialects {
#define SMB_QFILEINFO_COMPRESSION_INFO 0x10b
#define SMB_QFILEINFO_UNIX_BASIC 0x200
#define SMB_QFILEINFO_UNIX_LINK 0x201
+#define SMB_QFILEINFO_POSIX_ACL 0x204
+#define SMB_QFILEINFO_UNIX_INFO2 0x20B
#define SMB_QFILEINFO_MAC_DT_GET_APPL 0x306
#define SMB_QFILEINFO_MAC_DT_GET_ICON 0x307
#define SMB_QFILEINFO_MAC_DT_GET_ICON_INFO 0x308
+#define SMB_QFILEINFO_MAC_SPOTLIGHT 0x310
#define SMB_QFILEINFO_BASIC_INFORMATION 1004
#define SMB_QFILEINFO_STANDARD_INFORMATION 1005
#define SMB_QFILEINFO_INTERNAL_INFORMATION 1006
@@ -454,6 +491,9 @@ enum smb_dialects {
#define SMB_FIND_NAME_INFO 0x103
#define SMB_FIND_BOTH_DIRECTORY_INFO 0x104
#define SMB_FIND_UNIX_INFO 0x200
+/* Transact 2 Find First levels */
+#define SMB_FIND_FILE_UNIX 0x202
+#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
/*
* Selectors for NT_TRANSACT_QUERY_SECURITY_DESC and
@@ -707,6 +747,9 @@ typedef struct ntsid ntsid_t;
#define SMB_SFILEINFO_UNIX_BASIC 0x200
#define SMB_SFILEINFO_UNIX_LINK 0x201
#define SMB_SFILEINFO_UNIX_HLINK 0x203
+#define SMB_SFILEINFO_POSIX_ACL 0x204
+#define SMB_SFILEINFO_POSIX_UNLINK 0x20A
+#define SMB_SFILEINFO_UNIX_INFO2 0x20B
#define SMB_SFILEINFO_DIRECTORY_INFORMATION 1001
#define SMB_SFILEINFO_FULL_DIRECTORY_INFORMATION 1002
#define SMB_SFILEINFO_BOTH_DIRECTORY_INFORMATION 1003
@@ -816,4 +859,19 @@ typedef struct ntlmv2_namehdr ntlmv2_namehdr_t;
#define STYPE_TEMPORARY 0x40000000
#define STYPE_HIDDEN 0x80000000
+/*
+ * Characters that are not allowed in an SMB file name component.
+ * From MSDN: Naming Files, Paths, ...
+ * < (less than)
+ * > (greater than)
+ * : (colon)
+ * " (double quote)
+ * / (forward slash)
+ * \ (backslash)
+ * | (vertical bar or pipe)
+ * ? (question mark)
+ * * (asterisk)
+ */
+#define SMB_FILENAME_INVALID_CHARS "<>:\"/\\|?*"
+
#endif /* _NETSMB_SMB_H_ */
diff --git a/usr/src/uts/common/netsmb/smb2.h b/usr/src/uts/common/netsmb/smb2.h
new file mode 100644
index 0000000000..abae5e8063
--- /dev/null
+++ b/usr/src/uts/common/netsmb/smb2.h
@@ -0,0 +1,465 @@
+/*
+ * 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 2018 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef _NETSMB_SMB2_H
+#define _NETSMB_SMB2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMB2_PROTOCOL_ID { 0xFE, 'S', 'M', 'B' }
+#define SMB2_HDR_SIZE 64
+#define SMB2_HDRLEN SMB2_HDR_SIZE
+
+/*
+ * SMB2 header command codes.
+ * These are uint16_t on the wire.
+ */
+typedef enum {
+ SMB2_NEGOTIATE = 0,
+ SMB2_SESSION_SETUP,
+ SMB2_LOGOFF,
+ SMB2_TREE_CONNECT,
+ SMB2_TREE_DISCONNECT,
+ SMB2_CREATE,
+ SMB2_CLOSE,
+ SMB2_FLUSH,
+ SMB2_READ,
+ SMB2_WRITE,
+ SMB2_LOCK,
+ SMB2_IOCTL,
+ SMB2_CANCEL,
+ SMB2_ECHO,
+ SMB2_QUERY_DIRECTORY,
+ SMB2_CHANGE_NOTIFY,
+ SMB2_QUERY_INFO,
+ SMB2_SET_INFO,
+ SMB2_OPLOCK_BREAK,
+ /*
+ * The above (oplock break) is the last real SMB2 op-code.
+ * We use one more slot to represent invalid commands, and
+ * the final enum value is used for array sizes. Keep last!
+ */
+ SMB2_INVALID_CMD,
+ SMB2__NCMDS
+} SMB2_cmd_code;
+
+/*
+ * SMB2 header flags.
+ */
+
+/*
+ * SERVER_TO_REDIR
+ * When set, indicates the message is a response rather than
+ * a request. This MUST be set on responses sent from the
+ * server to the client, and MUST NOT be set on requests
+ * sent from the client to the server.
+ */
+#define SMB2_FLAGS_SERVER_TO_REDIR 0x00000001
+
+/*
+ * ASYNC_COMMAND
+ * When set, indicates that this is an ASYNC SMB2 header.
+ * Always set for headers of the form described in this
+ * section.
+ */
+#define SMB2_FLAGS_ASYNC_COMMAND 0x00000002
+
+/*
+ * RELATED_OPERATIONS
+ * When set in an SMB2 request, indicates that this request
+ * is a related operation in a compounded request chain.
+ * [MS-SMB2 sec. 3.2.4.1.4]
+ *
+ * When set in an SMB2 compound response, indicates that
+ * the request corresponding to this response was part of a
+ * related operation in a compounded request chain.
+ * [MS-SMB2 sec. 3.3.5.2.7.2]
+ */
+#define SMB2_FLAGS_RELATED_OPERATIONS 0x00000004
+
+/*
+ * SIGNED
+ * When set, indicates that this packet has been signed.
+ * [MS-SMB2 3.1.5.1]
+ */
+#define SMB2_FLAGS_SIGNED 0x00000008
+
+/*
+ * [MS-SMB2] 3.2.5.3.1 The SessionKey MUST be set to the
+ * first 16 bytes of the cryptographic key from GSSAPI.
+ * (Padded with zeros if the GSSAPI key is shorter.)
+ */
+#define SMB2_SESSION_KEY_LEN 16
+
+/*
+ * DFS_OPERATIONS
+ * When set, indicates that this command is a Distributed
+ * File System (DFS) operation. [MS-SMB2 3.3.5.9]
+ */
+#define SMB2_FLAGS_DFS_OPERATIONS 0x10000000
+
+/*
+ * REPLAY_OPERATION
+ * This flag is only valid for the SMB 3.0 dialect. When set,
+ * it indicates that this command is a replay operation.
+ * The client MUST ignore this bit on receipt.
+ */
+#define SMB2_FLAGS_REPLAY_OPERATION 0x20000000
+
+/*
+ * SMB2 Netgotiate [MS-SMB2 2.2.3]
+ */
+
+#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01
+#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02
+
+#define SMB2_CAP_DFS 0x00000001
+
+/* Added with SMB2.1 */
+#define SMB2_CAP_DFS 0x00000001
+#define SMB2_CAP_LEASING 0x00000002
+/*
+ * LARGE_MTU:
+ * When set, indicates that the client supports multi-credit operations.
+ */
+#define SMB2_CAP_LARGE_MTU 0x00000004
+
+/* Added with SMB3.0 */
+#define SMB2_CAP_MULTI_CHANNEL 0x00000008
+#define SMB2_CAP_PERSISTENT_HANDLES 0x00000010
+#define SMB2_CAP_DIRECTORY_LEASING 0x00000020
+#define SMB2_CAP_ENCRYPTION 0x00000040
+
+/* SMB2 session flags */
+#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
+#define SMB2_SESSION_FLAG_IS_NULL 0x0002
+#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004
+
+/*
+ * SMB2 Tree connect, disconnect
+ */
+
+/* SMB2 sharetype flags */
+#define SMB2_SHARE_TYPE_DISK 0x1
+#define SMB2_SHARE_TYPE_PIPE 0x2
+#define SMB2_SHARE_TYPE_PRINT 0x3
+
+/* SMB2 share flags */
+#define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000
+#define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010
+#define SMB2_SHAREFLAG_VDO_CACHING 0x00000020
+#define SMB2_SHAREFLAG_NO_CACHING 0x00000030
+#define SMB2_SHAREFLAG_DFS 0x00000001
+#define SMB2_SHAREFLAG_DFS_ROOT 0x00000002
+#define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x00000100
+#define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x00000200
+#define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x00000400
+#define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x00000800
+#define SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK 0x00001000
+/* SMB 3.0 */
+#define SMB2_SHAREFLAG_ENABLE_HASH_V1 0x00002000
+#define SMB2_SHAREFLAG_ENABLE_HASH_V2 0x00004000
+#define SMB2_SHAREFLAG_ENCRYPT_DATA 0x00008000
+
+/* SMB2 share capabilities */
+#define SMB2_SHARE_CAP_DFS 0x00000008
+/* SMB 3.0 */
+#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY 0x00000010
+#define SMB2_SHARE_CAP_SCALEOUT 0x00000020
+#define SMB2_SHARE_CAP_CLUSTER 0x00000040
+
+/*
+ * SMB2 Create (open)
+ */
+
+/* SMB2 requested oplock levels */
+#define SMB2_OPLOCK_LEVEL_NONE 0x00
+#define SMB2_OPLOCK_LEVEL_II 0x01
+#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
+#define SMB2_OPLOCK_LEVEL_BATCH 0x09
+#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
+
+/* SMB2 impersonation levels */
+#define SMB2_IMPERSONATION_ANONYMOUS 0x00
+#define SMB2_IMPERSONATION_IDENTIFICATION 0x01
+#define SMB2_IMPERSONATION_IMPERSONATION 0x02
+#define SMB2_IMPERSONATION_DELEGATE 0x03
+
+/*
+ * Note: ShareAccess, CreateDispositon, CreateOptions,
+ * all use the same definitions as SMB1 (from MS-FSA).
+ * Ditto FileAccess flags (as with ACLs)
+ */
+
+/* SMB2 Create Context tags */
+
+#define SMB2_CREATE_EA_BUFFER 0x45787441 /* ("ExtA") */
+/*
+ * The data contains the extended attributes
+ * that MUST be stored on the created file.
+ * This value MUST NOT be set for named
+ * pipes and print files.
+ */
+
+#define SMB2_CREATE_SD_BUFFER 0x53656344 /* ("SecD") */
+/*
+ * The data contains a security descriptor that
+ * MUST be stored on the created file.
+ * This value MUST NOT be set for named
+ * pipes and print files.
+ */
+
+#define SMB2_CREATE_DURABLE_HANDLE_REQUEST 0x44486e51 /* ("DHnQ") */
+/* The client is requesting the open to be durable */
+
+#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT 0x44486e43 /* ("DHnC") */
+/*
+ * The client is requesting to reconnect to a
+ * durable open after being disconnected
+ */
+
+#define SMB2_CREATE_ALLOCATION_SIZE 0x416c5369 /* ("AISi") */
+/*
+ * The data contains the required allocation
+ * size of the newly created file.
+ */
+
+#define SMB2_CREATE_QUERY_MAXIMAL_ACCESS 0x4d784163 /* ("MxAc") */
+/*
+ * The client is requesting that the server
+ * return maximal access information.
+ */
+
+#define SMB2_CREATE_TIMEWARP_TOKEN 0x54577270 /* ("TWrp") */
+/*
+ * The client is requesting that the server
+ * open an earlier version of the file identified
+ * by the provided time stamp.
+ */
+
+#define SMB2_CREATE_QUERY_ON_DISK_ID 0x51466964 /* ("QFid") */
+/*
+ * The client is requesting that the server return a 32-byte
+ * opaque BLOB that uniquely identifies the file being opened
+ * on disk. No data is passed to the server by the client.
+ */
+
+#define SMB2_CREATE_REQUEST_LEASE 0x52714c73 /* ("RqLs") */
+/*
+ * The client is requesting that the server return a lease.
+ * This value is only supported for the SMB 2.1 and 3.0 dialects.
+ */
+
+/* SMB2 create request lease */
+#define SMB2_LEASE_NONE 0x00
+#define SMB2_LEASE_READ_CACHING 0x01
+#define SMB2_LEASE_HANDLE_CACHING 0x02
+#define SMB2_LEASE_WRITE_CACHING 0x04
+
+/* SMB2 lease break notification flags */
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED 0x01
+
+/*
+ * SMB2 Close
+ */
+#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB 0x0001
+
+/*
+ * SMB2 Write
+ */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+/*
+ * SMB2 Lock Request
+ */
+
+/* SMB2 lock flags */
+
+/*
+ * SMB2_LOCKFLAG_SHARED_LOCK
+ * The range MUST be locked shared, allowing other opens
+ * to read from or take a shared lock on the range. All opens
+ * MUST NOT be allowed to write within the range. Other
+ * locks can be requested and taken on this range.
+ */
+#define SMB2_LOCKFLAG_SHARED_LOCK 0x00000001
+
+/*
+ * SMB2_LOCKFLAG_EXCLUSIVE_LOCK
+ * The range MUST be locked exclusive, not allowing other
+ * opens to read, write, or lock within the range.
+ */
+#define SMB2_LOCKFLAG_EXCLUSIVE_LOCK 0x00000002
+
+/*
+ * SMB2_LOCKFLAG_UNLOCK
+ * The range MUST be unlocked from a previous lock taken
+ * on this range. The unlock range MUST be identical to the
+ * lock range. Sub-ranges cannot be unlocked.
+ */
+#define SMB2_LOCKFLAG_UNLOCK 0x00000004
+
+/*
+ * SMB2_LOCKFLAG_FAIL_IMMEDIATELY
+ * The lock operation MUST fail immediately if it conflicts
+ * with an existing lock, instead of waiting for the range to
+ * become available. This can be OR'ed with either of
+ * shared_lock, exclusive_lock (nothing else).
+ */
+#define SMB2_LOCKFLAG_FAIL_IMMEDIATELY 0x00000010
+
+/*
+ * SMB2 Ioctl Request
+ */
+#define SMB2_IOCTL_IS_FSCTL 0x00000001
+
+
+/*
+ * SMB2 Query Directory
+ */
+
+/*
+ * SMB2 query directory info levels
+ * Same as SMB1 (see ntifs.h)
+ */
+
+/*
+ * SMB2 Query Directory Flags
+ * (our own names for these - spec. used poor names)
+ */
+#define SMB2_QDIR_FLAG_RESTART 0x01 /* SMB2_RESTART_SCANS */
+#define SMB2_QDIR_FLAG_SINGLE 0x02 /* SMB2_RETURN_SINGLE_ENTRY */
+#define SMB2_QDIR_FLAG_INDEX 0x04 /* SMB2_INDEX_SPECIFIED */
+#define SMB2_QDIR_FLAG_REOPEN 0x10 /* SMB2_REOPEN */
+
+/*
+ * SMB2 Query Info Request
+ */
+
+/* info type */
+#define SMB2_0_INFO_FILE 0x01
+/* The file information is requested. */
+#define SMB2_0_INFO_FILESYSTEM 0x02
+/* The underlying object store information is requested. */
+#define SMB2_0_INFO_SECURITY 0x03
+/* The security information is requested. */
+#define SMB2_0_INFO_QUOTA 0x04
+/* The underlying object store quota information is requested. */
+
+/*
+ * MS-FSCC 2.5 FileSystem Information Classes.
+ * Also see MSDN for ZwQueryVolumeInformationFile.
+ */
+typedef enum _FS_INFORMATION_CLASS
+{
+ FileFsVolumeInformation = 1, /* Query */
+ FileFsLabelInformation = 2, /* Set */
+ FileFsSizeInformation = 3, /* Query */
+ FileFsDeviceInformation = 4, /* Query */
+ FileFsAttributeInformation = 5, /* Query */
+ FileFsControlInformation = 6, /* Query, Set */
+ FileFsFullSizeInformation = 7, /* Query */
+ FileFsObjectIdInformation = 8, /* Query, Set */
+ FileFsDriverPathInformation = 9 /* Query */
+} FS_INFORMATION_CLASS;
+
+/*
+ * MS-FSCC 2.4 File Information Classes
+ */
+typedef enum _FILE_INFORMATION_CLASS
+{
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation = 2,
+ FileBothDirectoryInformation = 3,
+ FileBasicInformation = 4,
+ FileStandardInformation = 5,
+ FileInternalInformation = 6,
+ FileEaInformation = 7,
+ FileAccessInformation = 8,
+ FileNameInformation = 9,
+ FileRenameInformation = 10,
+ FileLinkInformation = 11,
+ FileNamesInformation = 12,
+ FileDispositionInformation = 13,
+ FilePositionInformation = 14,
+ FileFullEaInformation = 15,
+ FileModeInformation = 16,
+ FileAlignmentInformation = 17,
+ FileAllInformation = 18,
+ FileAllocationInformation = 19,
+ FileEndOfFileInformation = 20,
+ FileAlternateNameInformation = 21,
+ FileStreamInformation = 22,
+ FilePipeInformation = 23,
+ FilePipeLocalInformation = 24,
+ FilePipeRemoteInformation = 25,
+ FileMailslotQueryInformation = 26,
+ FileMailslotSetInformation = 27,
+ FileCompressionInformation = 28,
+ FileObjectIdInformation = 29,
+ FileMoveClusterInformation = 31,
+ FileQuotaInformation = 32,
+ FileReparsePointInformation = 33,
+ FileNetworkOpenInformation = 34,
+ FileAttributeTagInformation = 35,
+ FileTrackingInformation = 36,
+ FileIdBothDirectoryInformation = 37,
+ FileIdFullDirectoryInformation = 38,
+ FileValidDataLengthInformation = 39,
+ FileShortNameInformation = 40,
+ FileSfioReserveInformation = 44,
+ FileSfioVolumeInformation = 45,
+ FileHardLinkInformation = 46,
+ FileNormalizedNameInformation = 48,
+ FileIdGlobalTxDirectoryInformation = 50,
+ FileStandardLinkInformation = 54
+} FILE_INFORMATION_CLASS;
+
+/*
+ * SMB2 Change Nofity Request
+ */
+#define SMB2_WATCH_TREE 0x00000001
+
+/*
+ * After here, added stuff from darwin
+ */
+#define SMB2_TID_UNKNOWN 0
+#define SMB2_FID_UNUSED 0xffffffffffffffff
+
+/* smb2_durable_handle flags */
+typedef enum _SMB2_DURABLE_HANDLE_FLAGS
+{
+ SMB2_DURABLE_HANDLE_REQUEST = 0x0001,
+ SMB2_DURABLE_HANDLE_RECONNECT = 0x0002,
+ SMB2_DURABLE_HANDLE_GRANTED = 0x0004,
+ SMB2_LEASE_GRANTED = 0x0008
+} _SMB2_DURABLE_HANDLE_FLAGS;
+
+struct smb2_durable_handle {
+ uint64_t fid; /* SMBFID to reconnect in durable handle reconnect */
+ uint64_t flags;
+ uint64_t lease_key_hi; /* atomic increment number */
+ uint64_t lease_key_low; /* node hash value */
+ uint32_t lease_state;
+ uint32_t pad;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETSMB_SMB2_H */
diff --git a/usr/src/uts/common/netsmb/smb_dev.h b/usr/src/uts/common/netsmb/smb_dev.h
index d2e7690062..817d214b3e 100644
--- a/usr/src/uts/common/netsmb/smb_dev.h
+++ b/usr/src/uts/common/netsmb/smb_dev.h
@@ -33,9 +33,10 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _NETSMB_DEV_H_
@@ -71,9 +72,9 @@
* associated structures change in ways that would
* make them incompatible with an old driver.
*/
-#define NSMB_VERMAJ 1
-#define NSMB_VERMIN 4000
-#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN)
+#define NSMB_VERMAJ 2
+#define NSMB_VERMIN 0x100
+#define NSMB_VERSION ((NSMB_VERMAJ << 16) | NSMB_VERMIN)
/*
* Some errno values we need to expose to the library.
@@ -84,7 +85,7 @@
* EAUTH is used for CIFS authentication errors.
*/
#ifndef EBADRPC
-#define EBADRPC 113
+#define EBADRPC 113
#endif
#ifndef EAUTH
#define EAUTH 114
@@ -111,13 +112,21 @@
#define SMBVOPT_PRIVATE 0x0002 /* connection should be private */
#define SMBVOPT_SINGLESHARE 0x0004 /* keep only one share at this VC */
#define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */
-#define SMBVOPT_EXT_SEC 0x0020 /* extended security negotiation */
-#define SMBVOPT_USE_KEYCHAIN 0x0040 /* get p/w from keychain */
-#define SMBVOPT_KC_DOMAIN 0x0080 /* keychain lookup uses domain */
+#define SMBVOPT_ANONYMOUS 0x0020 /* using a NULL session */
+
+#define SMBVOPT_SIGNING_ENABLED 0x10000 /* sign if server agrees */
+#define SMBVOPT_SIGNING_REQUIRED 0x20000 /* signing required */
+#define SMBVOPT_SIGNING_MASK 0x30000 /* all signing bits */
-#define SMBVOPT_SIGNING_ENABLED 0x0100 /* sign if server agrees */
-#define SMBVOPT_SIGNING_REQUIRED 0x0200 /* signing required */
-#define SMBVOPT_SIGNING_MASK 0x0300 /* all signing bits */
+#define SMB2_DIALECT_BASE 0x0200
+#define SMB2_DIALECT_0202 0x0202
+#define SMB2_DIALECT_02ff 0x02ff
+#define SMB2_DIALECT_0210 0x0210
+#define SMB2_DIALECT_0300 0x0300
+#define SMB2_DIALECT_0302 0x0302
+
+/* Maximum supported dialect (for ssn_maxver) */
+#define SMB2_DIALECT_MAX SMB2_DIALECT_0210
/*
* Option flags in smbioc_oshare.ioc_opt
@@ -137,13 +146,18 @@
/*
* network IO daemon states
- * really connection states.
*/
enum smbiod_state {
- SMBIOD_ST_IDLE = 0, /* no user requests enqueued yet */
- SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */
+ SMBIOD_ST_UNINIT = 0, /* uninitialized */
+ SMBIOD_ST_RECONNECT, /* a [re]connect attempt requested */
SMBIOD_ST_RCFAILED, /* a reconnect attempt has failed */
- SMBIOD_ST_VCACTIVE, /* session established */
+ SMBIOD_ST_CONNECTED, /* Transport (TCP) connected */
+ SMBIOD_ST_NEGOTIATED, /* Negotiated SMB/SMB2+ */
+ SMBIOD_ST_AUTHCONT, /* Session setup continuing */
+ SMBIOD_ST_AUTHFAIL, /* Session setup failed */
+ SMBIOD_ST_AUTHOK, /* Session setup success */
+ SMBIOD_ST_VCACTIVE, /* iod_work running */
+ SMBIOD_ST_IDLE, /* no trees, will go DEAD */
SMBIOD_ST_DEAD /* connection gone, no IOD */
};
@@ -204,8 +218,10 @@ typedef struct smbioc_ssn_ident smbioc_ssn_ident_t;
* Structure used with SMBIOC_SSN_FIND, _CREATE
*/
struct smbioc_ossn {
- uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */
uint32_t ssn_owner; /* Unix owner (UID) */
+ uint32_t ssn_vopt; /* i.e. SMBVOPT_CREATE */
+ uint16_t ssn_minver; /* Min SMB version. */
+ uint16_t ssn_maxver; /* Max SMB version. */
smbioc_ssn_ident_t ssn_id;
char ssn_srvname[SMBIOC_MAX_NAME];
};
@@ -232,55 +248,19 @@ typedef struct smbioc_tcon {
smbioc_oshare_t tc_sh;
} smbioc_tcon_t;
-
-/*
- * Negotiated protocol parameters
- */
-struct smb_sopt {
- int16_t sv_proto; /* protocol dialect */
- uchar_t sv_sm; /* security mode */
- int16_t sv_tz; /* offset in min relative to UTC */
- uint16_t sv_maxmux; /* max number of outstanding rq's */
- uint16_t sv_maxvcs; /* max number of VCs */
- uint16_t sv_rawmode;
- uint32_t sv_maxtx; /* maximum transmit buf size */
- uint32_t sv_maxraw; /* maximum raw-buffer size */
- uint32_t sv_skey; /* session key */
- uint32_t sv_caps; /* capabilites SMB_CAP_ */
-};
-typedef struct smb_sopt smb_sopt_t;
-
-/*
- * State carried in/out of the driver by the IOD thread.
- * Inside the driver, these are members of the "VC" object.
- */
-struct smb_iods {
- int32_t is_tran_fd; /* transport FD */
- uint32_t is_vcflags; /* SMBV_... */
- uint8_t is_hflags; /* SMB header flags */
- uint16_t is_hflags2; /* SMB header flags2 */
- uint16_t is_smbuid; /* SMB header UID */
- uint16_t is_next_mid; /* SMB header MID */
- uint32_t is_txmax; /* max tx/rx packet size */
- uint32_t is_rwmax; /* max read/write data size */
- uint32_t is_rxmax; /* max readx data size */
- uint32_t is_wxmax; /* max writex data size */
- uint8_t is_ssn_key[SMBIOC_HASH_SZ]; /* session key */
- /* Signing state */
- uint32_t is_next_seq; /* my next sequence number */
- uint32_t is_u_maclen; /* MAC key length */
- lptr_t is_u_mackey; /* user-space ptr! */
-};
-typedef struct smb_iods smb_iods_t;
-
/*
* This is the operational state information passed
* in and out of the driver for SMBIOC_SSN_WORK
*/
struct smbioc_ssn_work {
- smb_iods_t wk_iods;
- smb_sopt_t wk_sopt;
- int wk_out_state;
+ uint32_t wk_out_state; /* out-only */
+ uint32_t wk_u_ssnkey_len; /* ssn key length */
+ lptr_t wk_u_ssnkey_buf; /* user-space ptr! */
+ uint32_t wk_u_auth_rlen; /* recv auth tok len */
+ uint32_t wk_u_auth_wlen; /* send auth tok len */
+ lptr_t wk_u_auth_rbuf; /* recv auth tok buf */
+ lptr_t wk_u_auth_wbuf; /* send auth tok buf */
+ uint8_t wk_cl_guid[16]; /* client GUID */
};
typedef struct smbioc_ssn_work smbioc_ssn_work_t;
@@ -288,66 +268,27 @@ typedef struct smbioc_ssn_work smbioc_ssn_work_t;
* User-level SMB requests
*/
-/*
- * SMBIOC_REQUEST (simple SMB request)
- */
-typedef struct smbioc_rq {
- uchar_t ioc_cmd;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint32_t ioc_tbufsz; /* transmit */
- uint32_t ioc_rbufsz; /* receive */
- lptr_t _ioc_tbuf;
- lptr_t _ioc_rbuf;
-} smbioc_rq_t;
-#define ioc_tbuf _ioc_tbuf.lp_ptr
-#define ioc_rbuf _ioc_rbuf.lp_ptr
-
-
-#define SMBIOC_T2RQ_MAXSETUP 4
-#define SMBIOC_T2RQ_MAXNAME 128
-
-typedef struct smbioc_t2rq {
- uint16_t ioc_setup[SMBIOC_T2RQ_MAXSETUP];
- int32_t ioc_setupcnt;
- char ioc_name[SMBIOC_T2RQ_MAXNAME];
- ushort_t ioc_tparamcnt;
- ushort_t ioc_tdatacnt;
- ushort_t ioc_rparamcnt;
- ushort_t ioc_rdatacnt;
- uint8_t ioc__pad1;
- uint8_t ioc_errclass;
- uint16_t ioc_serror;
- uint32_t ioc_error;
- uint16_t ioc_rpflags2;
- uint16_t ioc__pad2;
- lptr_t _ioc_tparam;
- lptr_t _ioc_tdata;
- lptr_t _ioc_rparam;
- lptr_t _ioc_rdata;
-} smbioc_t2rq_t;
-#define ioc_tparam _ioc_tparam.lp_ptr
-#define ioc_tdata _ioc_tdata.lp_ptr
-#define ioc_rparam _ioc_rparam.lp_ptr
-#define ioc_rdata _ioc_rdata.lp_ptr
-
-
-typedef struct smbioc_flags {
- int32_t ioc_level; /* 0 - session, 1 - share */
- int32_t ioc_flags;
- int32_t ioc_mask;
-} smbioc_flags_t;
-
typedef struct smbioc_rw {
- int32_t ioc_fh;
uint32_t ioc_cnt;
+ uint32_t ioc_flags;
lloff_t _ioc_offset;
lptr_t _ioc_base;
} smbioc_rw_t;
#define ioc_offset _ioc_offset._f
#define ioc_base _ioc_base.lp_ptr
+/* Transact on named pipe (send/recv) */
+typedef struct smbioc_xnp {
+ uint32_t ioc_tdlen; /* transmit len */
+ uint32_t ioc_rdlen; /* recv maxlen */
+ uint32_t ioc_more; /* more data to read */
+ uint32_t ioc_pad1;
+ lptr_t _ioc_tdata;
+ lptr_t _ioc_rdata;
+} smbioc_xnp_t;
+#define ioc_tdata _ioc_tdata.lp_ptr
+#define ioc_rdata _ioc_rdata.lp_ptr
+
typedef struct smbioc_ntcreate {
uint32_t ioc_req_acc;
uint32_t ioc_efattr;
@@ -383,18 +324,16 @@ typedef struct smbioc_pk {
* Keep GETVERS first and use it to verify
* driver compatibility with the library.
*/
-#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
+#define SMBIOC_BASE ((('n' << 8) | 's') << 8)
typedef enum nsmb_ioc {
SMBIOC_GETVERS = SMBIOC_BASE, /* keep first */
- SMBIOC_FLAGS2, /* get hflags2 */
+ SMBIOC_FLAGS2, /* obsolete */
SMBIOC_GETSSNKEY, /* get SMB session key */
SMBIOC_DUP_DEV, /* duplicate dev handle */
- SMBIOC_REQUEST, /* simple request */
- SMBIOC_T2RQ, /* trans2 request */
-
SMBIOC_READ, /* read (pipe) */
SMBIOC_WRITE, /* write (pipe) */
+ SMBIOC_XACTNP, /* "transact" (pipe) */
SMBIOC_NTCREATE, /* open or create */
SMBIOC_PRINTJOB, /* open print job */
SMBIOC_CLOSEFH, /* from ntcreate or printjob */
@@ -409,9 +348,12 @@ typedef enum nsmb_ioc {
SMBIOC_TREE_KILL,
SMBIOC_TREE_RELE,
+ SMBIOC_IOD_CONNECT, /* Setup connection */
+ SMBIOC_IOD_NEGOTIATE, /* SMB/SMB2 negotiate */
+ SMBIOC_IOD_SSNSETUP, /* SMB/SMB2 session setup */
SMBIOC_IOD_WORK, /* work on session requests */
SMBIOC_IOD_IDLE, /* wait for requests on this session */
- SMBIOC_IOD_RCFAIL, /* notify that reconnect failed */
+ SMBIOC_IOD_RCFAIL, /* tell driver reconnect failed */
/* Password Keychain (PK) support. */
SMBIOC_PK_ADD, /* Add/Modify a password entry */
diff --git a/usr/src/uts/common/os/brand.c b/usr/src/uts/common/os/brand.c
index 62c3bbe2d6..60e8150a0d 100644
--- a/usr/src/uts/common/os/brand.c
+++ b/usr/src/uts/common/os/brand.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/kmem.h>
@@ -671,9 +671,9 @@ restoreexecenv(struct execenv *ep, stack_t *sp)
/*ARGSUSED*/
int
brand_solaris_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args,
- intpdata_t *idatap, int level, long *execsz, int setid, caddr_t exec_file,
- cred_t *cred, int *brand_action, struct brand *pbrand, char *bname,
- char *brandlib, char *brandlib32)
+ intpdata_t *idatap, int level, size_t *execsz, int setid,
+ caddr_t exec_file, cred_t *cred, int *brand_action, struct brand *pbrand,
+ char *bname, char *brandlib, char *brandlib32)
{
vnode_t *nvp;
diff --git a/usr/src/uts/common/os/core.c b/usr/src/uts/common/os/core.c
index 437f26e6e0..a147b1cf0f 100644
--- a/usr/src/uts/common/os/core.c
+++ b/usr/src/uts/common/os/core.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016, Joyent Inc.
+ * Copyright 2019 Joyent Inc.
* Copyright (c) 2016 by Delphix. All rights reserved.
*/
@@ -795,7 +795,7 @@ clock_t core_delay_usec = 10000;
* using core_write() below, and so it has the same failure semantics.
*/
int
-core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
+core_seg(proc_t *p, vnode_t *vp, u_offset_t offset, caddr_t addr, size_t size,
rlim64_t rlimit, cred_t *credp)
{
caddr_t eaddr;
@@ -803,6 +803,11 @@ core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
size_t len;
int err = 0;
+ if (offset > OFF_MAX || offset + size > OFF_MAX ||
+ offset + size < offset) {
+ return (EOVERFLOW);
+ }
+
eaddr = addr + size;
for (base = addr; base < eaddr; base += len) {
len = eaddr - base;
@@ -843,15 +848,20 @@ core_seg(proc_t *p, vnode_t *vp, offset_t offset, caddr_t addr, size_t size,
* unexpectedly returns zero but no progress has been made, we return ENOSPC.
*/
int
-core_write(vnode_t *vp, enum uio_seg segflg, offset_t offset,
+core_write(vnode_t *vp, enum uio_seg segflg, u_offset_t offset,
const void *buf, size_t len, rlim64_t rlimit, cred_t *credp)
{
ssize_t resid = len;
int error = 0;
+ if (offset > OFF_MAX || offset + len > OFF_MAX ||
+ offset + len < offset) {
+ return (EOVERFLOW);
+ }
+
while (len != 0) {
- error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len, offset,
- segflg, 0, rlimit, credp, &resid);
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)buf, len,
+ (offset_t)offset, segflg, 0, rlimit, credp, &resid);
if (error != 0)
break;
diff --git a/usr/src/uts/common/os/dumpsubr.c b/usr/src/uts/common/os/dumpsubr.c
index 0eb96464bf..484b2042e2 100644
--- a/usr/src/uts/common/os/dumpsubr.c
+++ b/usr/src/uts/common/os/dumpsubr.c
@@ -3123,7 +3123,7 @@ dump_set_uuid(const char *uuidstr)
(void) strncpy(dump_osimage_uuid, uuidstr, 36 + 1);
- cmn_err(CE_CONT, "?This Solaris instance has UUID %s\n",
+ cmn_err(CE_CONT, "?This illumos instance has UUID %s\n",
dump_osimage_uuid);
return (0);
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index 500bd1ecb6..24b6f0e2eb 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -26,7 +26,7 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/*
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/types.h>
@@ -144,7 +144,7 @@ exec_common(const char *fname, const char **argp, const char **envp,
proc_t *p = ttoproc(curthread);
klwp_t *lwp = ttolwp(curthread);
struct user *up = PTOU(p);
- long execsz; /* temporary count of exec size */
+ size_t execsz; /* temporary count of exec size */
int i;
int error;
char exec_file[MAXCOMLEN+1];
@@ -603,7 +603,7 @@ gexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
caddr_t exec_file,
struct cred *cred,
int *brand_action)
@@ -1491,7 +1491,7 @@ noexec(
struct uarg *args,
struct intpdata *idatap,
int level,
- long *execsz,
+ size_t *execsz,
int setid,
caddr_t exec_file,
struct cred *cred)
diff --git a/usr/src/uts/common/os/sunmdi.c b/usr/src/uts/common/os/sunmdi.c
index 5bbef59e9c..0905a0852b 100644
--- a/usr/src/uts/common/os/sunmdi.c
+++ b/usr/src/uts/common/os/sunmdi.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014 Nexenta Systems Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -1478,11 +1479,10 @@ i_mdi_client_free(mdi_vhci_t *vh, mdi_client_t *ct)
mutex_destroy(&ct->ct_mutex);
kmem_free(ct, sizeof (*ct));
- if (cdip != NULL) {
- MDI_VHCI_CLIENT_UNLOCK(vh);
- (void) i_mdi_devinfo_remove(vdip, cdip, flags);
- MDI_VHCI_CLIENT_LOCK(vh);
- }
+ MDI_VHCI_CLIENT_UNLOCK(vh);
+ (void) i_mdi_devinfo_remove(vdip, cdip, flags);
+ MDI_VHCI_CLIENT_LOCK(vh);
+
return (rv);
}
diff --git a/usr/src/uts/common/os/sysent.c b/usr/src/uts/common/os/sysent.c
index 554ba1b881..fb64000e4d 100644
--- a/usr/src/uts/common/os/sysent.c
+++ b/usr/src/uts/common/os/sysent.c
@@ -28,7 +28,7 @@
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
#include <sys/param.h>
#include <sys/types.h>
@@ -355,11 +355,11 @@ typedef int64_t (*llfcn_t)(); /* for casting one-word returns */
*/
/* returns a 64-bit quantity for both ABIs */
#define SYSENT_C(name, call, narg) \
- { (narg), SE_64RVAL, NULL, NULL, (llfcn_t)(call) }
+ { (narg), SE_64RVAL, NULL, NULL, (llfcn_t)(uintptr_t)(call) }
/* returns one 32-bit value for both ABIs: r_val1 */
#define SYSENT_CI(name, call, narg) \
- { (narg), SE_32RVAL1, NULL, NULL, (llfcn_t)(call) }
+ { (narg), SE_32RVAL1, NULL, NULL, (llfcn_t)(uintptr_t)(call) }
/* returns 2 32-bit values: r_val1 & r_val2 */
#define SYSENT_2CI(name, call, narg) \
@@ -420,7 +420,7 @@ typedef int64_t (*llfcn_t)(); /* for casting one-word returns */
* Initialization macro for loadable native system calls.
*/
#define SYSENT_LOADABLE() \
- { 0, SE_LOADABLE, (int (*)())nosys, NULL, loadable_syscall }
+ { 0, SE_LOADABLE, nosys32, NULL, loadable_syscall }
/*
* Initialization macro for loadable 32-bit compatibility system calls.
@@ -622,7 +622,7 @@ struct sysent sysent[NSYSCALL] =
/* 157 */ SYSENT_CI("getitimer", getitimer, 2),
/* 158 */ SYSENT_CI("setitimer", setitimer, 3),
/* 159 */ SYSENT_CI("lwp_create", syslwp_create, 3),
- /* 160 */ SYSENT_CI("lwp_exit", (int (*)())syslwp_exit, 0),
+ /* 160 */ SYSENT_CI("lwp_exit", syslwp_exit, 0),
/* 161 */ SYSENT_CI("lwp_suspend", syslwp_suspend, 1),
/* 162 */ SYSENT_CI("lwp_continue", syslwp_continue, 1),
/* 163 */ SYSENT_CI("lwp_kill", lwp_kill, 2),
@@ -820,7 +820,7 @@ extern int ucredsys32(int, int, caddr32_t);
struct sysent sysent32[NSYSCALL] =
{
/* 0 */ SYSENT_C("indir", indir, 1),
- /* 1 */ SYSENT_CI("exit", (int (*)())rexit, 1),
+ /* 1 */ SYSENT_CI("exit", rexit, 1),
/* 2 */ SYSENT_CI("psecflags", psecflags, 3),
/* 3 */ SYSENT_CI("read", read32, 3),
/* 4 */ SYSENT_CI("write", write32, 3),
@@ -983,7 +983,7 @@ struct sysent sysent32[NSYSCALL] =
/* 157 */ SYSENT_CI("getitimer", getitimer, 2),
/* 158 */ SYSENT_CI("setitimer", setitimer, 3),
/* 159 */ SYSENT_CI("lwp_create", syslwp_create, 3),
- /* 160 */ SYSENT_CI("lwp_exit", (int (*)())syslwp_exit, 0),
+ /* 160 */ SYSENT_CI("lwp_exit", syslwp_exit, 0),
/* 161 */ SYSENT_CI("lwp_suspend", syslwp_suspend, 1),
/* 162 */ SYSENT_CI("lwp_continue", syslwp_continue, 1),
/* 163 */ SYSENT_CI("lwp_kill", lwp_kill, 2),
diff --git a/usr/src/uts/common/smb/Makefile b/usr/src/uts/common/smb/Makefile
index 74ac618565..afa0837b2b 100644
--- a/usr/src/uts/common/smb/Makefile
+++ b/usr/src/uts/common/smb/Makefile
@@ -21,7 +21,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
include ../../../Makefile.master
@@ -29,8 +29,10 @@ include ../../../Makefile.master
HDRS= \
doserror.h \
lmerr.h \
+ ntaccess.h \
nterror.h \
ntstatus.h \
+ winioctl.h \
wintypes.h
diff --git a/usr/src/uts/common/smbsrv/ntaccess.h b/usr/src/uts/common/smb/ntaccess.h
index 114150baa9..77d48b48ad 100644
--- a/usr/src/uts/common/smbsrv/ntaccess.h
+++ b/usr/src/uts/common/smb/ntaccess.h
@@ -21,13 +21,13 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_NTACCESS_H
#define _SMBSRV_NTACCESS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This file defines the NT compatible access control masks and values.
* An access mask as a 32-bit value arranged as shown below.
diff --git a/usr/src/uts/common/smbsrv/winioctl.h b/usr/src/uts/common/smb/winioctl.h
index bbde2e4a6f..a18d7853ce 100644
--- a/usr/src/uts/common/smbsrv/winioctl.h
+++ b/usr/src/uts/common/smb/winioctl.h
@@ -22,10 +22,10 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
-#ifndef _SMBSRV_WINIOCTL_H
-#define _SMBSRV_WINIOCTL_H
+#ifndef _SMB_WINIOCTL_H
+#define _SMB_WINIOCTL_H
/*
* Standard Windows NT IOCTL/FSCTL definitions (derived from the VC++
@@ -544,4 +544,4 @@ extern "C" {
}
#endif
-#endif /* _SMBSRV_WINIOCTL_H */
+#endif /* _SMB_WINIOCTL_H */
diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile
index 4664c09cfb..a80be7497f 100644
--- a/usr/src/uts/common/smbsrv/Makefile
+++ b/usr/src/uts/common/smbsrv/Makefile
@@ -20,7 +20,7 @@
#
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2018 Nexenta Systems, Inc. All rights reserved.
#
include ../../../Makefile.master
@@ -36,7 +36,6 @@ HDRS= alloc.h \
netbios.h \
netrauth.h \
nmpipes.h \
- ntaccess.h \
ntifs.h \
ntlocale.h \
smb_sid.h \
@@ -61,7 +60,6 @@ HDRS= alloc.h \
smb2_kproto.h \
string.h \
svrapi.h \
- winioctl.h \
winsvc.h
NDLHDRS= dssetup.ndl \
diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h
index a4986bea78..65e2708569 100644
--- a/usr/src/uts/common/smbsrv/smb.h
+++ b/usr/src/uts/common/smbsrv/smb.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_SMB_H
@@ -39,7 +39,7 @@
#include <smb/nterror.h>
#include <smb/lmerr.h>
#include <smb/doserror.h>
-#include <smbsrv/ntaccess.h>
+#include <smb/ntaccess.h>
/*
* Macintosh Extensions for CIFS
diff --git a/usr/src/uts/common/sys/brand.h b/usr/src/uts/common/sys/brand.h
index e33de24757..df22f492bf 100644
--- a/usr/src/uts/common/sys/brand.h
+++ b/usr/src/uts/common/sys/brand.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2017, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_BRAND_H
@@ -172,10 +172,9 @@ struct brand_ops {
void (*b_forklwp)(klwp_t *, klwp_t *);
void (*b_freelwp)(klwp_t *);
void (*b_lwpexit)(klwp_t *);
- int (*b_elfexec)(struct vnode *vp, struct execa *uap,
- struct uarg *args, struct intpdata *idata, int level,
- long *execsz, int setid, caddr_t exec_file,
- struct cred *cred, int *brand_action);
+ int (*b_elfexec)(struct vnode *, struct execa *, struct uarg *,
+ struct intpdata *, int, size_t *, int, caddr_t, struct cred *,
+ int *);
void (*b_sigset_native_to_brand)(sigset_t *);
void (*b_sigset_brand_to_native)(sigset_t *);
void (*b_sigfd_translate)(k_siginfo_t *);
@@ -258,7 +257,7 @@ extern int brand_solaris_cmd(int, uintptr_t, uintptr_t, uintptr_t,
extern void brand_solaris_copy_procdata(proc_t *, proc_t *,
struct brand *);
extern int brand_solaris_elfexec(vnode_t *, execa_t *, uarg_t *,
- intpdata_t *, int, long *, int, caddr_t, cred_t *, int *,
+ intpdata_t *, int, size_t *, int, caddr_t, cred_t *, int *,
struct brand *, char *, char *, char *);
extern void brand_solaris_exec(struct brand *);
extern int brand_solaris_fini(char **, struct modlinkage *,
diff --git a/usr/src/uts/common/sys/conf.h b/usr/src/uts/common/sys/conf.h
index 4bf3d5c7e3..148104f83a 100644
--- a/usr/src/uts/common/sys/conf.h
+++ b/usr/src/uts/common/sys/conf.h
@@ -41,11 +41,11 @@
extern "C" {
#endif
-#define FMNAMESZ 8 /* used by struct fmodsw */
+#define FMNAMESZ 8 /* used by struct fmodsw */
#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* XXX Given that drivers need to include this file,
@@ -53,10 +53,14 @@ extern "C" {
* it legitimizes (aka provides prototypes for)
* all sorts of functions that aren't in the DKI/SunDDI
*/
+#include <sys/types.h>
#include <sys/systm.h>
+
+#endif /* _KERNEL || _FAKE_KERNEL */
+#ifdef _KERNEL
+
#include <sys/devops.h>
#include <sys/model.h>
-#include <sys/types.h>
#include <sys/buf.h>
#include <sys/cred.h>
#include <sys/uio.h>
diff --git a/usr/src/uts/common/sys/debug.h b/usr/src/uts/common/sys/debug.h
index e4a959205a..9c91905af2 100644
--- a/usr/src/uts/common/sys/debug.h
+++ b/usr/src/uts/common/sys/debug.h
@@ -138,12 +138,12 @@ _NOTE(CONSTCOND) } while (0)
#define __CTASSERT(x, y) \
typedef char __compile_time_assertion__ ## y [(x) ? 1 : -1] __unused
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern void abort_sequence_enter(char *);
extern void debug_enter(char *);
-#endif /* _KERNEL */
+#endif /* _KERNEL || _FAKE_KERNEL */
#if defined(DEBUG) && !defined(__sun)
/* CSTYLED */
diff --git a/usr/src/uts/common/sys/dirent.h b/usr/src/uts/common/sys/dirent.h
index 114fcf6e30..c079fb983a 100644
--- a/usr/src/uts/common/sys/dirent.h
+++ b/usr/src/uts/common/sys/dirent.h
@@ -76,7 +76,7 @@ typedef struct dirent64 {
#endif /* _LARGEFILE64_SOURCE */
#if !defined(__XOPEN_OR_POSIX) || defined(__EXTENSIONS__)
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#define DIRENT64_RECLEN(namelen) \
((offsetof(dirent64_t, d_name[0]) + 1 + (namelen) + 7) & ~ 7)
#define DIRENT64_NAMELEN(reclen) \
diff --git a/usr/src/uts/common/sys/dld_impl.h b/usr/src/uts/common/sys/dld_impl.h
index 81708aad38..336fa9cb67 100644
--- a/usr/src/uts/common/sys/dld_impl.h
+++ b/usr/src/uts/common/sys/dld_impl.h
@@ -331,7 +331,7 @@ typedef struct dld_ap {
\
mutex_enter(&(dsp)->ds_lock); \
if ((dsp)->ds_dlstate != DL_IDLE || \
- !mac_tx_is_flow_blocked((dsp)->ds_mch, NULL)) { \
+ !mac_tx_is_flow_blocked((dsp)->ds_mch, 0)) { \
if ((dsp)->ds_tx_flow_mp == NULL) \
(dsp)->ds_tx_flow_mp = getq(q); \
ASSERT((dsp)->ds_tx_flow_mp != NULL); \
diff --git a/usr/src/uts/common/sys/dnlc.h b/usr/src/uts/common/sys/dnlc.h
index bf947659d0..4a5c20d6d0 100644
--- a/usr/src/uts/common/sys/dnlc.h
+++ b/usr/src/uts/common/sys/dnlc.h
@@ -76,7 +76,7 @@ extern "C" {
* storing full names, then we are ok. The space savings are worth it.
*/
typedef struct ncache {
- struct ncache *hash_next; /* hash chain, MUST BE FIRST */
+ struct ncache *hash_next; /* hash chain, MUST BE FIRST */
struct ncache *hash_prev;
struct vnode *vp; /* vnode the name refers to */
struct vnode *dp; /* vnode of parent of name */
@@ -169,7 +169,7 @@ struct nc_stats {
(namlen) = Xcp - (name); \
}
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/vfs.h>
#include <sys/vnode.h>
@@ -205,7 +205,7 @@ void dnlc_reduce_cache(void *);
*/
typedef struct dcfree {
uint64_t df_handle; /* fs supplied handle */
- struct dcfree *df_next; /* link to next free entry in bucket */
+ struct dcfree *df_next; /* link to next free entry in bucket */
uint_t df_len; /* length of free entry */
} dcfree_t;
diff --git a/usr/src/uts/common/sys/exec.h b/usr/src/uts/common/sys/exec.h
index 3b7ac5aa7c..12115b7e27 100644
--- a/usr/src/uts/common/sys/exec.h
+++ b/usr/src/uts/common/sys/exec.h
@@ -27,7 +27,7 @@
/* All Rights Reserved */
/*
- * Copyright 2016, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_EXEC_H
@@ -83,7 +83,7 @@ typedef struct uarg {
ssize_t arglen;
char *fname;
char *pathname;
- ssize_t auxsize;
+ size_t auxsize;
caddr_t stackend;
size_t stk_align;
size_t stk_size;
@@ -182,7 +182,7 @@ struct execsw {
int exec_maglen;
int (*exec_func)(struct vnode *vp, struct execa *uap,
struct uarg *args, struct intpdata *idata, int level,
- long *execsz, int setid, caddr_t exec_file,
+ size_t *execsz, int setid, caddr_t exec_file,
struct cred *cred, int *brand_action);
int (*exec_core)(struct vnode *vp, struct proc *p,
struct cred *cred, rlim64_t rlimit, int sig,
@@ -220,7 +220,7 @@ extern int exece(const char *fname, const char **argp, const char **envp);
extern int exec_common(const char *fname, const char **argp,
const char **envp, int brand_action);
extern int gexec(vnode_t **vp, struct execa *uap, struct uarg *args,
- struct intpdata *idata, int level, long *execsz, caddr_t exec_file,
+ struct intpdata *idata, int level, size_t *execsz, caddr_t exec_file,
struct cred *cred, int *brand_action);
extern struct execsw *allocate_execsw(char *name, char *magic,
size_t magic_size);
@@ -246,32 +246,32 @@ extern void exec_set_sp(size_t);
* when compiling the 32-bit compatability elf code in the elfexec module.
*/
extern int elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
extern int mapexec_brand(vnode_t *, uarg_t *, Ehdr *, Addr *,
intptr_t *, caddr_t, char **, caddr_t *, caddr_t *, size_t *,
uintptr_t *, uintptr_t *);
-extern int elfreadhdr(vnode_t *, cred_t *, Ehdr *, int *, caddr_t *,
- ssize_t *);
+extern int elfreadhdr(vnode_t *, cred_t *, Ehdr *, uint_t *, caddr_t *,
+ size_t *);
#endif /* !_ELF32_COMPAT */
#if defined(_LP64)
extern int elf32exec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
- long *, int, caddr_t, cred_t *, int *);
+ size_t *, int, caddr_t, cred_t *, int *);
extern int mapexec32_brand(vnode_t *, uarg_t *, Elf32_Ehdr *, Elf32_Addr *,
intptr_t *, caddr_t, char **, caddr_t *, caddr_t *, size_t *,
uintptr_t *, uintptr_t *);
-extern int elf32readhdr(vnode_t *, cred_t *, Elf32_Ehdr *, int *, caddr_t *,
- ssize_t *);
+extern int elf32readhdr(vnode_t *, cred_t *, Elf32_Ehdr *, uint_t *, caddr_t *,
+ size_t *);
#endif /* _LP64 */
/*
* Utility functions for exec module core routines:
*/
-extern int core_seg(proc_t *, vnode_t *, offset_t, caddr_t,
- size_t, rlim64_t, cred_t *);
+extern int core_seg(proc_t *, vnode_t *, u_offset_t, caddr_t, size_t,
+ rlim64_t, cred_t *);
-extern int core_write(vnode_t *, enum uio_seg, offset_t,
- const void *, size_t, rlim64_t, cred_t *);
+extern int core_write(vnode_t *, enum uio_seg, u_offset_t, const void *,
+ size_t, rlim64_t, cred_t *);
/* a.out stuff */
diff --git a/usr/src/uts/common/sys/file.h b/usr/src/uts/common/sys/file.h
index eb1328f38d..556a7ab2a1 100644
--- a/usr/src/uts/common/sys/file.h
+++ b/usr/src/uts/common/sys/file.h
@@ -33,7 +33,7 @@
#define _SYS_FILE_H
#include <sys/t_lock.h>
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/model.h>
#include <sys/user.h>
#endif
@@ -119,7 +119,7 @@ typedef struct fpollinfo {
#define FCLOEXEC 0x800000 /* O_CLOEXEC = 0x800000 */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Fake flags for driver ioctl calls to inform them of the originating
@@ -183,7 +183,7 @@ typedef struct fpollinfo {
extern int flock(int, int);
#endif
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Routines dealing with user per-open file flags and
@@ -192,15 +192,16 @@ extern int flock(int, int);
struct proc; /* forward reference for function prototype */
struct vnodeops;
struct vattr;
+struct uf_info;
extern file_t *getf(int);
extern file_t *getf_gen(int, uf_entry_gen_t *);
extern void releasef(int);
-extern void areleasef(int, uf_info_t *);
+extern void areleasef(int, struct uf_info *);
#ifndef _BOOT
-extern void closeall(uf_info_t *);
+extern void closeall(struct uf_info *);
#endif
-extern void flist_fork(uf_info_t *, uf_info_t *);
+extern void flist_fork(struct uf_info *, struct uf_info *);
extern int closef(file_t *);
extern int closeandsetf(int, file_t *);
extern int ufalloc_file(int, file_t *);
@@ -217,8 +218,8 @@ extern void f_setfd(int, char);
extern int f_getfl(int, int *);
extern int f_badfd(int, int *, int);
extern int fassign(struct vnode **, int, int *);
-extern void fcnt_add(uf_info_t *, int);
-extern void close_exec(uf_info_t *);
+extern void fcnt_add(struct uf_info *, int);
+extern void close_exec(struct uf_info *);
extern void clear_stale_fd(void);
extern void clear_active_fd(int);
extern void set_active_fd(int);
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index b0dbfe0f25..0728f42212 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -988,6 +988,7 @@ typedef enum zfs_ioc {
ZFS_IOC_POOL_CHECKPOINT,
ZFS_IOC_POOL_DISCARD_CHECKPOINT,
ZFS_IOC_POOL_INITIALIZE,
+ ZFS_IOC_POOL_SYNC,
ZFS_IOC_LAST
} zfs_ioc_t;
diff --git a/usr/src/uts/common/sys/ieeefp.h b/usr/src/uts/common/sys/ieeefp.h
index 9b47e6ce47..2ee4ec4d51 100644
--- a/usr/src/uts/common/sys/ieeefp.h
+++ b/usr/src/uts/common/sys/ieeefp.h
@@ -27,8 +27,6 @@
#ifndef _SYS_IEEEFP_H
#define _SYS_IEEEFP_H
-#pragma ident "%Z%%M% %I% %E% SMI" /* SunOS4.0 1.6 */
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -60,6 +58,7 @@ enum fp_exception_type { /* exceptions according to bit number */
fp_overflow = 3,
fp_invalid = 4
};
+#define N_IEEE_EXCEPTION 5 /* Number of floating-point exceptions. */
enum fp_trap_enable_type { /* trap enable bits according to bit number */
fp_trap_inexact = 0,
@@ -93,6 +92,7 @@ enum fp_exception_type { /* exceptions according to bit number */
fp_underflow = 4,
fp_inexact = 5
};
+#define N_IEEE_EXCEPTION 6 /* Number of floating-point exceptions. */
enum fp_trap_enable_type { /* trap enable bits according to bit number */
fp_trap_invalid = 0,
@@ -109,7 +109,7 @@ enum fp_class_type { /* floating-point classes */
fp_zero = 0,
fp_subnormal = 1,
fp_normal = 2,
- fp_infinity = 3,
+ fp_infinity = 3,
fp_quiet = 4,
fp_signaling = 5
};
diff --git a/usr/src/uts/common/sys/model.h b/usr/src/uts/common/sys/model.h
index fab96bbe00..0569c086f5 100644
--- a/usr/src/uts/common/sys/model.h
+++ b/usr/src/uts/common/sys/model.h
@@ -37,7 +37,7 @@ extern "C" {
#include <sys/isa_defs.h>
-#if defined(_KERNEL) || defined(_KMEMUSER)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL) || defined(_KMEMUSER)
/*
* These bits are used in various places to specify the data model
diff --git a/usr/src/uts/common/sys/modhash.h b/usr/src/uts/common/sys/modhash.h
index 68d1c4dedd..7f7103ecb9 100644
--- a/usr/src/uts/common/sys/modhash.h
+++ b/usr/src/uts/common/sys/modhash.h
@@ -34,7 +34,7 @@
extern "C" {
#endif
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/types.h>
diff --git a/usr/src/uts/common/sys/poll.h b/usr/src/uts/common/sys/poll.h
index 4434a8551a..558edbfba9 100644
--- a/usr/src/uts/common/sys/poll.h
+++ b/usr/src/uts/common/sys/poll.h
@@ -96,7 +96,7 @@ typedef unsigned long nfds_t;
#endif /* _KERNEL */
-#if defined(_KERNEL) || defined(_KMEMUSER)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL) || defined(_KMEMUSER)
#include <sys/thread.h>
diff --git a/usr/src/uts/common/sys/prsystm.h b/usr/src/uts/common/sys/prsystm.h
index 7adc920da2..75259dc421 100644
--- a/usr/src/uts/common/sys/prsystm.h
+++ b/usr/src/uts/common/sys/prsystm.h
@@ -28,7 +28,7 @@
/* All Rights Reserved */
/*
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _SYS_PRSYSTM_H
@@ -86,7 +86,7 @@ extern void prgetcred(proc_t *, struct prcred *);
extern void prgetpriv(proc_t *, struct prpriv *);
extern size_t prgetprivsize(void);
extern void prgetsecflags(proc_t *, struct prsecflags *);
-extern int prnsegs(struct as *, int);
+extern uint_t prnsegs(struct as *, int);
extern void prexit(proc_t *);
extern void prfree(proc_t *);
extern void prlwpexit(kthread_t *);
diff --git a/usr/src/uts/common/sys/share.h b/usr/src/uts/common/sys/share.h
index 4de5f5ce65..1a8aead065 100644
--- a/usr/src/uts/common/sys/share.h
+++ b/usr/src/uts/common/sys/share.h
@@ -63,7 +63,7 @@ struct shrlocklist {
struct shrlocklist *next;
};
-#if defined(_KERNEL)
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
struct flock64;
extern int add_share(struct vnode *, struct shrlock *);
diff --git a/usr/src/uts/common/sys/signal.h b/usr/src/uts/common/sys/signal.h
index 1818665b45..b12dff6034 100644
--- a/usr/src/uts/common/sys/signal.h
+++ b/usr/src/uts/common/sys/signal.h
@@ -246,7 +246,7 @@ struct sigstack {
#include <sys/ucontext.h>
#endif /* defined(_XPG4_2) */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/t_lock.h>
extern const k_sigset_t nullsmask; /* a null signal mask */
diff --git a/usr/src/uts/common/sys/stream.h b/usr/src/uts/common/sys/stream.h
index efcd2a9194..7488d3dee8 100644
--- a/usr/src/uts/common/sys/stream.h
+++ b/usr/src/uts/common/sys/stream.h
@@ -36,7 +36,7 @@
* For source compatibility
*/
#include <sys/isa_defs.h>
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
#include <sys/kmem.h>
#include <sys/uio.h>
#endif
@@ -641,7 +641,7 @@ struct stroptions {
#define SO_MAXBLK 0x100000 /* set maximum message block size */
#define SO_TAIL 0x200000 /* set the extra allocated space */
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* Structure for rw (read/write) procedure calls. A pointer
* to a struiod_t is passed as a parameter to the rwnext() call.
@@ -766,7 +766,7 @@ typedef struct cmdblk {
*/
#define bpsize(bp) ((unsigned int)(bp->b_datap->db_lim - bp->b_datap->db_base))
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
/*
* For two-byte M_ERROR messages: indication that a side does not have an error
diff --git a/usr/src/uts/common/sys/strsubr.h b/usr/src/uts/common/sys/strsubr.h
index 0f29dd3675..f3bc1ed407 100644
--- a/usr/src/uts/common/sys/strsubr.h
+++ b/usr/src/uts/common/sys/strsubr.h
@@ -40,6 +40,7 @@
*/
#include <sys/stream.h>
#include <sys/stropts.h>
+#include <sys/vnode.h>
#include <sys/kstat.h>
#include <sys/uio.h>
#include <sys/proc.h>
@@ -115,7 +116,7 @@ extern "C" {
/*
* Function types for the parameterized stream head.
* The msgfunc_t takes the parameters:
- * msgfunc(vnode_t *vp, mblk_t *mp, strwakeup_t *wakeups,
+ * msgfunc(vnode_t *vp, mblk_t *mp, strwakeup_t *wakeups,
* strsigset_t *firstmsgsigs, strsigset_t *allmsgsigs,
* strpollset_t *pollwakeups);
* It returns an optional message to be processed by the stream head.
@@ -130,7 +131,7 @@ typedef short strpollset_t;
typedef uintptr_t callbparams_id_t;
typedef mblk_t *(*msgfunc_t)(vnode_t *, mblk_t *, strwakeup_t *,
strsigset_t *, strsigset_t *, strpollset_t *);
-typedef int (*errfunc_t)(vnode_t *, int, int *);
+typedef int (*errfunc_t)(vnode_t *, int, int *);
/*
* Per stream sd_lock in putnext may be replaced by per cpu stream_putlocks
@@ -276,7 +277,7 @@ typedef struct stdata {
/* 0x00020000 unused */
/* 0x00040000 unused */
#define STRTOSTOP 0x00080000 /* block background writes */
-#define STRCMDWAIT 0x00100000 /* someone is doing an _I_CMD */
+#define STRCMDWAIT 0x00100000 /* someone is doing an _I_CMD */
/* 0x00200000 unused */
#define STRMOUNT 0x00400000 /* stream is mounted */
#define STRNOTATMARK 0x00800000 /* Not at mark (when empty read q) */
@@ -410,7 +411,7 @@ typedef struct stdata {
*
* The new way is:
*
- * mutex_enter(SQLOCK(sq));
+ * mutex_enter(SQLOCK(sq));
* count = sq->sq_count;
* SQ_PUTLOCKS_ENTER(sq);
* SUM_SQ_PUTCOUNTS(sq, count);
@@ -459,8 +460,8 @@ struct syncq {
*/
uint16_t sq_type; /* type (concurrency) of syncq */
uint16_t sq_rmqcount; /* # threads inside removeq() */
- kcondvar_t sq_wait; /* block on this sync queue */
- kcondvar_t sq_exitwait; /* waiting for thread to leave the */
+ kcondvar_t sq_wait; /* block on this sync queue */
+ kcondvar_t sq_exitwait; /* waiting for thread to leave the */
/* inner perimeter */
/*
* Handling synchronous callbacks such as qtimeout and qbufcall
@@ -1024,7 +1025,7 @@ typedef struct str_stack str_stack_t;
/*
* Copy modes for tty and I_STR ioctls
*/
-#define U_TO_K 01 /* User to Kernel */
+#define U_TO_K 01 /* User to Kernel */
#define K_TO_K 02 /* Kernel to Kernel */
/*
@@ -1077,7 +1078,7 @@ typedef struct str_stack str_stack_t;
#define STRUNLOCKMATES(X) mutex_exit(&((X)->sd_lock)); \
mutex_exit(&(((X)->sd_mate)->sd_lock))
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_FAKE_KERNEL)
extern void strinit(void);
extern int strdoioctl(struct stdata *, struct strioctl *, int, int,
diff --git a/usr/src/uts/common/sys/t_kuser.h b/usr/src/uts/common/sys/t_kuser.h
index 7aac9d94d2..b3c4da657c 100644
--- a/usr/src/uts/common/sys/t_kuser.h
+++ b/usr/src/uts/common/sys/t_kuser.h
@@ -98,6 +98,7 @@ extern int t_kconnect(TIUSER *, struct t_call *, struct t_call *);
extern int t_kfree(TIUSER *, char *, int);
extern int t_kgetstate(TIUSER *, int *);
extern int t_kopen(struct file *, dev_t, int, TIUSER **, struct cred *);
+extern int t_koptmgmt(TIUSER *, struct t_optmgmt *, struct t_optmgmt *);
extern int t_krcvudata(TIUSER *, struct t_kunitdata *, int *, int *);
extern int t_ksndudata(TIUSER *, struct t_kunitdata *, frtn_t *);
extern int t_kspoll(TIUSER *, int, int, int *);
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index 8eadfcb56f..3979ddaef7 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -279,6 +279,8 @@ VMM_OBJS += vmm.o \
vmm_sol_vm.o \
vmm_sol_glue.o \
vmm_sol_ept.o \
+ vmm_sol_rvi.o \
+ vmm_support.o \
vmm_zsd.o
VIONA_OBJS += viona.o
diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules
index 3ea69978ce..0e3ea556ea 100644
--- a/usr/src/uts/i86pc/Makefile.rules
+++ b/usr/src/uts/i86pc/Makefile.rules
@@ -232,6 +232,9 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/vmm/io/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/vmm/%.s
+ $(COMPILE.s) -o $@ $<
+
$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/vmm/intel/%.s
$(COMPILE.s) -o $@ $<
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_common.c b/usr/src/uts/i86pc/io/pcplusmp/apic_common.c
index 30644ad12a..b1a0b9c3d0 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_common.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic_common.c
@@ -23,7 +23,7 @@
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
* Copyright (c) 2016, 2017 by Delphix. All rights reserved.
*/
@@ -808,6 +808,8 @@ gethrtime_again:
void
apic_nmi_intr(caddr_t arg, struct regs *rp)
{
+ int action = nmi_action;
+
if (apic_shutdown_processors) {
apic_disable_local_apic();
return;
@@ -819,18 +821,41 @@ apic_nmi_intr(caddr_t arg, struct regs *rp)
return;
apic_num_nmis++;
- if (apic_kmdb_on_nmi && psm_debugger()) {
- debug_enter("NMI received: entering kmdb\n");
- } else if (apic_panic_on_nmi) {
- /* Keep panic from entering kmdb. */
- nopanicdebug = 1;
- panic("NMI received\n");
- } else {
+ /*
+ * "nmi_action" always over-rides the older way of doing this, unless we
+ * can't actually drop into kmdb when requested.
+ */
+ if (action == NMI_ACTION_KMDB && !psm_debugger())
+ action = NMI_ACTION_UNSET;
+
+ if (action == NMI_ACTION_UNSET) {
+ if (apic_kmdb_on_nmi && psm_debugger())
+ action = NMI_ACTION_KMDB;
+ else if (apic_panic_on_nmi)
+ action = NMI_ACTION_PANIC;
+ else
+ action = NMI_ACTION_IGNORE;
+ }
+
+ switch (action) {
+ case NMI_ACTION_IGNORE:
/*
* prom_printf is the best shot we have of something which is
* problem free from high level/NMI type of interrupts
*/
prom_printf("NMI received\n");
+ break;
+
+ case NMI_ACTION_PANIC:
+ /* Keep panic from entering kmdb. */
+ nopanicdebug = 1;
+ panic("NMI received\n");
+ break;
+
+ case NMI_ACTION_KMDB:
+ default:
+ debug_enter("NMI received: entering kmdb\n");
+ break;
}
lock_clear(&apic_nmi_lock);
diff --git a/usr/src/uts/i86pc/io/viona/viona.c b/usr/src/uts/i86pc/io/viona/viona.c
index 74fd237fc9..6a62ae7ccf 100644
--- a/usr/src/uts/i86pc/io/viona/viona.c
+++ b/usr/src/uts/i86pc/io/viona/viona.c
@@ -1537,7 +1537,7 @@ viona_worker_rx(viona_vring_t *ring, viona_link_t *link)
ASSERT(MUTEX_HELD(&ring->vr_lock));
ASSERT3U(ring->vr_state, ==, VRS_RUN);
- atomic_or_16(ring->vr_used_flags, VRING_USED_F_NO_NOTIFY);
+ *ring->vr_used_flags |= VRING_USED_F_NO_NOTIFY;
mac_rx_set(link->l_mch, viona_rx, link);
do {
@@ -1578,7 +1578,7 @@ viona_worker_tx(viona_vring_t *ring, viona_link_t *link)
boolean_t bail = B_FALSE;
uint_t ntx = 0;
- atomic_or_16(ring->vr_used_flags, VRING_USED_F_NO_NOTIFY);
+ *ring->vr_used_flags |= VRING_USED_F_NO_NOTIFY;
while (viona_vr_num_avail(ring)) {
viona_tx(link, ring);
@@ -1590,14 +1590,18 @@ viona_worker_tx(viona_vring_t *ring, viona_link_t *link)
if (ntx++ >= ring->vr_size)
break;
}
- atomic_and_16(ring->vr_used_flags, ~VRING_USED_F_NO_NOTIFY);
+ *ring->vr_used_flags &= ~VRING_USED_F_NO_NOTIFY;
VIONA_PROBE2(tx, viona_link_t *, link, uint_t, ntx);
/*
* Check for available descriptors on the ring once more in
* case a late addition raced with the NO_NOTIFY flag toggle.
+ *
+ * The barrier ensures that visibility of the vr_used_flags
+ * store does not cross the viona_vr_num_avail() check below.
*/
+ membar_enter();
bail = VRING_NEED_BAIL(ring, p);
if (!bail && viona_vr_num_avail(ring)) {
continue;
@@ -2457,6 +2461,7 @@ pad_drop:
mp = next;
}
+ membar_enter();
if ((*ring->vr_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
viona_intr_ring(ring);
}
@@ -2484,6 +2489,7 @@ viona_tx_done(viona_vring_t *ring, uint32_t len, uint16_t cookie)
{
vq_pushchain(ring, len, cookie);
+ membar_enter();
if ((*ring->vr_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
viona_intr_ring(ring);
}
diff --git a/usr/src/uts/i86pc/io/vmm/amd/svm.c b/usr/src/uts/i86pc/io/vmm/amd/svm.c
index e921383d22..ca9ed9e4e1 100644
--- a/usr/src/uts/i86pc/io/vmm/amd/svm.c
+++ b/usr/src/uts/i86pc/io/vmm/amd/svm.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#ifndef __FreeBSD__
#include <sys/x86_archext.h>
+#include <sys/trap.h>
#endif
#include <vm/vm.h>
@@ -123,6 +124,7 @@ static int disable_npf_assist;
SYSCTL_INT(_hw_vmm_svm, OID_AUTO, disable_npf_assist, CTLFLAG_RWTUN,
&disable_npf_assist, 0, NULL);
+#ifdef __FreeBSD__
/* Maximum ASIDs supported by the processor */
static uint32_t nasid;
SYSCTL_UINT(_hw_vmm_svm, OID_AUTO, num_asids, CTLFLAG_RDTUN, &nasid, 0,
@@ -135,6 +137,7 @@ static struct asid asid[MAXCPU];
* SVM host state saved area of size 4KB for each core.
*/
static uint8_t hsave[MAXCPU][PAGE_SIZE] __aligned(PAGE_SIZE);
+#endif /* __FreeBSD__ */
static VMM_STAT_AMD(VCPU_EXITINTINFO, "VM exits during event delivery");
static VMM_STAT_AMD(VCPU_INTINFO_INJECTED, "Events pending at VM entry");
@@ -156,6 +159,7 @@ decode_assist(void)
return (svm_feature & AMD_CPUID_SVM_DECODE_ASSIST);
}
+#ifdef __FreeBSD__
static void
svm_disable(void *arg __unused)
{
@@ -298,6 +302,31 @@ svm_restore(void)
svm_enable(NULL);
}
+#else /* __FreeBSD__ */
+static int
+svm_cleanup(void)
+{
+ /* This is taken care of by the hma registration */
+ return (0);
+}
+
+static int
+svm_init(int ipinum)
+{
+ vmcb_clean &= VMCB_CACHE_DEFAULT;
+
+ svm_msr_init();
+ svm_npt_init(ipinum);
+
+ return (0);
+}
+
+static void
+svm_restore(void)
+{
+ /* No-op on illumos */
+}
+#endif /* __FreeBSD__ */
/* Pentium compatible MSRs */
#define MSR_PENTIUM_START 0
@@ -1309,7 +1338,11 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit)
struct svm_regctx *ctx;
uint64_t code, info1, info2, val;
uint32_t eax, ecx, edx;
+#ifdef __FreeBSD__
int error, errcode_valid, handled, idtvec, reflect;
+#else
+ int error, errcode_valid = 0, handled, idtvec, reflect;
+#endif
bool retu;
ctx = svm_get_guest_regctx(svm_sc, vcpu);
@@ -1380,8 +1413,11 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit)
*/
reflect = 0;
VCPU_CTR0(svm_sc->vm, vcpu, "Vectoring to MCE handler");
- /* XXXJOY: we will need equivalent of vmx_call_trap */
+#ifdef __FreeBSD__
__asm __volatile("int $18");
+#else
+ vmm_call_trap(T_MCE);
+#endif
break;
case IDT_PF:
error = svm_setreg(svm_sc, vcpu, VM_REG_GUEST_CR2,
@@ -1772,11 +1808,14 @@ restore_host_tss(void)
tss_sd->sd_type = SDT_SYSTSS;
ltr(GSEL(GPROC0_SEL, SEL_KPL));
#else
- /* XXXJOY: Add logic to restore TSS for us */
- panic("SVM Restore system TSS");
+ system_desc_t *tss = (system_desc_t *)&CPU->cpu_gdt[GDT_KTSS];
+
+ tss->ssd_type = SDT_SYSTSS;
+ wr_tsr(KTSS_SEL);
#endif
}
+#ifdef __FreeBSD__
static void
check_asid(struct svm_softc *sc, int vcpuid, pmap_t pmap, u_int thiscpu)
{
@@ -1879,6 +1918,27 @@ check_asid(struct svm_softc *sc, int vcpuid, pmap_t pmap, u_int thiscpu)
KASSERT(ctrl->asid == vcpustate->asid.num,
("ASID mismatch: %u/%u", ctrl->asid, vcpustate->asid.num));
}
+#else /* __FreeBSD__ */
+static void
+check_asid(struct svm_softc *sc, int vcpuid, pmap_t pmap, u_int thiscpu)
+{
+ struct svm_vcpu *vcpustate = svm_get_vcpu(sc, vcpuid);
+ struct vmcb_ctrl *ctrl = svm_get_vmcb_ctrl(sc, vcpuid);
+ long eptgen;
+ uint8_t flush;
+
+ eptgen = pmap->pm_eptgen;
+ flush = hma_svm_asid_update(&vcpustate->hma_asid, flush_by_asid(),
+ vcpustate->eptgen == eptgen);
+
+ if (flush != VMCB_TLB_FLUSH_NOTHING) {
+ ctrl->asid = vcpustate->hma_asid.hsa_asid;
+ svm_set_dirty(sc, vcpuid, VMCB_CACHE_ASID);
+ }
+ ctrl->tlb_ctrl = flush;
+ vcpustate->eptgen = eptgen;
+}
+#endif /* __FreeBSD__ */
static __inline void
disable_gintr(void)
@@ -1983,7 +2043,11 @@ svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
/*
* Force new ASID allocation by invalidating the generation.
*/
+#ifdef __FreeBSD__
vcpustate->asid.gen = 0;
+#else
+ vcpustate->hma_asid.hsa_gen = 0;
+#endif
/*
* Invalidate the VMCB state cache by marking all fields dirty.
@@ -2006,10 +2070,25 @@ svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
svm_msr_guest_enter(svm_sc, vcpu);
+#ifndef __FreeBSD__
+ VERIFY(!vcpustate->loaded && curthread->t_preempt != 0);
+ vcpustate->loaded = B_TRUE;
+#endif
+
/* Update Guest RIP */
state->rip = rip;
do {
+#ifndef __FreeBSD__
+ /*
+ * Interrupt injection may involve mutex contention which, on
+ * illumos bhyve, are blocking/non-spin. Doing so with global
+ * interrupts disabled is a recipe for deadlock, so it is
+ * performed here.
+ */
+ svm_inj_interrupts(svm_sc, vcpu, vlapic);
+#endif
+
/*
* Disable global interrupts to guarantee atomicity during
* loading of guest state. This includes not only the state
@@ -2059,7 +2138,9 @@ svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
*/
ldt_sel = sldt();
+#ifdef __FreeBSD__
svm_inj_interrupts(svm_sc, vcpu, vlapic);
+#endif
/* Activate the nested pmap on 'curcpu' */
CPU_SET_ATOMIC_ACQ(curcpu, &pmap->pm_active);
@@ -2108,6 +2189,11 @@ svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
svm_msr_guest_exit(svm_sc, vcpu);
+#ifndef __FreeBSD__
+ VERIFY(vcpustate->loaded && curthread->t_preempt != 0);
+ vcpustate->loaded = B_FALSE;
+#endif
+
return (0);
}
@@ -2309,6 +2395,28 @@ svm_vlapic_cleanup(void *arg, struct vlapic *vlapic)
free(vlapic, M_SVM_VLAPIC);
}
+#ifndef __FreeBSD__
+static void
+svm_savectx(void *arg, int vcpu)
+{
+ struct svm_softc *sc = arg;
+
+ if (sc->vcpu[vcpu].loaded) {
+ svm_msr_guest_exit(sc, vcpu);
+ }
+}
+
+static void
+svm_restorectx(void *arg, int vcpu)
+{
+ struct svm_softc *sc = arg;
+
+ if (sc->vcpu[vcpu].loaded) {
+ svm_msr_guest_enter(sc, vcpu);
+ }
+}
+#endif /* __FreeBSD__ */
+
struct vmm_ops vmm_ops_amd = {
svm_init,
svm_cleanup,
@@ -2328,11 +2436,7 @@ struct vmm_ops vmm_ops_amd = {
svm_vlapic_cleanup,
#ifndef __FreeBSD__
- /*
- * When SVM support is wired up and tested, it is likely to require
- * savectx/restorectx functions similar to VMX.
- */
- NULL,
- NULL,
+ svm_savectx,
+ svm_restorectx,
#endif
};
diff --git a/usr/src/uts/i86pc/io/vmm/amd/svm_msr.c b/usr/src/uts/i86pc/io/vmm/amd/svm_msr.c
index 67c43100f1..0c1ce0e4e0 100644
--- a/usr/src/uts/i86pc/io/vmm/amd/svm_msr.c
+++ b/usr/src/uts/i86pc/io/vmm/amd/svm_msr.c
@@ -54,6 +54,7 @@ enum {
HOST_MSR_NUM /* must be the last enumeration */
};
+#ifdef __FreeBSD__
static uint64_t host_msrs[HOST_MSR_NUM];
void
@@ -68,6 +69,19 @@ svm_msr_init(void)
host_msrs[IDX_MSR_STAR] = rdmsr(MSR_STAR);
host_msrs[IDX_MSR_SF_MASK] = rdmsr(MSR_SF_MASK);
}
+#else
+
+CTASSERT(HOST_MSR_NUM == SVM_HOST_MSR_NUM);
+
+void
+svm_msr_init(void)
+{
+ /*
+ * These MSRs do vary between CPUs on illumos, so saving system-wide
+ * values for them serves no purpose.
+ */
+}
+#endif /* __FreeBSD__ */
void
svm_msr_guest_init(struct svm_softc *sc, int vcpu)
@@ -89,11 +103,23 @@ svm_msr_guest_enter(struct svm_softc *sc, int vcpu)
/*
* Save host MSRs (if any) and restore guest MSRs (if any).
*/
+#ifndef __FreeBSD__
+ uint64_t *host_msrs = sc->host_msrs[vcpu];
+
+ /* Save host MSRs */
+ host_msrs[IDX_MSR_LSTAR] = rdmsr(MSR_LSTAR);
+ host_msrs[IDX_MSR_CSTAR] = rdmsr(MSR_CSTAR);
+ host_msrs[IDX_MSR_STAR] = rdmsr(MSR_STAR);
+ host_msrs[IDX_MSR_SF_MASK] = rdmsr(MSR_SF_MASK);
+#endif /* __FreeBSD__ */
}
void
svm_msr_guest_exit(struct svm_softc *sc, int vcpu)
{
+#ifndef __FreeBSD__
+ uint64_t *host_msrs = sc->host_msrs[vcpu];
+#endif
/*
* Save guest MSRs (if any) and restore host MSRs.
*/
diff --git a/usr/src/uts/i86pc/io/vmm/amd/svm_softc.h b/usr/src/uts/i86pc/io/vmm/amd/svm_softc.h
index 8735353bb4..b5ac1903e7 100644
--- a/usr/src/uts/i86pc/io/vmm/amd/svm_softc.h
+++ b/usr/src/uts/i86pc/io/vmm/amd/svm_softc.h
@@ -34,10 +34,17 @@
#define SVM_IO_BITMAP_SIZE (3 * PAGE_SIZE)
#define SVM_MSR_BITMAP_SIZE (2 * PAGE_SIZE)
+#ifdef __FreeBSD__
struct asid {
uint64_t gen; /* range is [1, ~0UL] */
uint32_t num; /* range is [1, nasid - 1] */
};
+#else
+#include <sys/hma.h>
+
+/* This must match HOST_MSR_NUM in svm_msr.c (where it is CTASSERTed) */
+#define SVM_HOST_MSR_NUM 4
+#endif /* __FreeBSD__ */
/*
* XXX separate out 'struct vmcb' from 'svm_vcpu' to avoid wasting space
@@ -51,7 +58,12 @@ struct svm_vcpu {
int lastcpu; /* host cpu that the vcpu last ran on */
uint32_t dirty; /* state cache bits that must be cleared */
long eptgen; /* pmap->pm_eptgen when the vcpu last ran */
+#ifdef __FreeBSD__
struct asid asid;
+#else
+ hma_svm_asid_t hma_asid;
+ boolean_t loaded;
+#endif
} __aligned(PAGE_SIZE);
/*
@@ -64,6 +76,9 @@ struct svm_softc {
uint8_t *iopm_bitmap; /* shared by all vcpus */
uint8_t *msr_bitmap; /* shared by all vcpus */
struct vm *vm;
+#ifndef __FreeBSD__
+ uint64_t host_msrs[VM_MAXCPU][SVM_HOST_MSR_NUM];
+#endif
};
CTASSERT((offsetof(struct svm_softc, nptp) & PAGE_MASK) == 0);
diff --git a/usr/src/uts/i86pc/io/vmm/amd/svm_support.s b/usr/src/uts/i86pc/io/vmm/amd/svm_support.s
index 4258c95d70..fad994b09c 100644
--- a/usr/src/uts/i86pc/io/vmm/amd/svm_support.s
+++ b/usr/src/uts/i86pc/io/vmm/amd/svm_support.s
@@ -25,7 +25,12 @@
*
* $FreeBSD$
*/
-#include <machine/asmacros.h>
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#include <sys/asm_linkage.h>
#include "svm_assym.h"
@@ -34,115 +39,126 @@
#if defined(lint)
struct svm_regctx;
-struct pcpu;
+struct cpu;
/*ARGSUSED*/
void
-svm_launch(uint64_t pa, struct svm_regctx *gctx, struct pcpu *pcpu)
+svm_launch(uint64_t pa, struct svm_regctx *gctx, struct cpu *cpu)
{}
#else /* lint */
-/*
- * Be friendly to DTrace FBT's prologue/epilogue pattern matching.
- *
- * They are also responsible for saving/restoring the host %rbp across VMRUN.
- */
-#define VENTER push %rbp ; mov %rsp,%rbp
-#define VLEAVE pop %rbp
-
#define VMLOAD .byte 0x0f, 0x01, 0xda
#define VMRUN .byte 0x0f, 0x01, 0xd8
#define VMSAVE .byte 0x0f, 0x01, 0xdb
+
+/*
+ * Flush scratch registers to avoid lingering guest state being used for
+ * Spectre v1 attacks when returning from guest entry.
+ */
+#define SVM_GUEST_FLUSH_SCRATCH \
+ xorl %edi, %edi; \
+ xorl %esi, %esi; \
+ xorl %edx, %edx; \
+ xorl %ecx, %ecx; \
+ xorl %r8d, %r8d; \
+ xorl %r9d, %r9d; \
+ xorl %r10d, %r10d; \
+ xorl %r11d, %r11d;
+
+/* Stack layout (offset from %rsp) for svm_launch */
+#define SVMSTK_R15 0x00 /* callee saved %r15 */
+#define SVMSTK_R14 0x08 /* callee saved %r14 */
+#define SVMSTK_R13 0x10 /* callee saved %r13 */
+#define SVMSTK_R12 0x18 /* callee saved %r12 */
+#define SVMSTK_RBX 0x20 /* callee saved %rbx */
+#define SVMSTK_RDX 0x28 /* save-args %rdx (struct cpu *) */
+#define SVMSTK_RSI 0x30 /* save-args %rsi (struct svm_regctx *) */
+#define SVMSTK_RDI 0x38 /* save-args %rdi (uint64_t vmcb_pa) */
+#define SVMSTK_FP 0x40 /* frame pointer %rbp */
+#define SVMSTKSIZE SVMSTK_FP
+
/*
* svm_launch(uint64_t vmcb, struct svm_regctx *gctx, struct pcpu *pcpu)
* %rdi: physical address of VMCB
* %rsi: pointer to guest context
* %rdx: pointer to the pcpu data
*/
-ENTRY(svm_launch)
- VENTER
-
- /* save pointer to the pcpu data */
- push %rdx
-
- /*
- * Host register state saved across a VMRUN.
- *
- * All "callee saved registers" except:
- * %rsp: because it is preserved by the processor across VMRUN.
- * %rbp: because it is saved/restored by the function prologue/epilogue.
- */
- push %rbx
- push %r12
- push %r13
- push %r14
- push %r15
-
- /* Save the physical address of the VMCB in %rax */
- movq %rdi, %rax
-
- push %rsi /* push guest context pointer on the stack */
-
- /*
- * Restore guest state.
- */
- movq SCTX_R8(%rsi), %r8
- movq SCTX_R9(%rsi), %r9
- movq SCTX_R10(%rsi), %r10
- movq SCTX_R11(%rsi), %r11
- movq SCTX_R12(%rsi), %r12
- movq SCTX_R13(%rsi), %r13
- movq SCTX_R14(%rsi), %r14
- movq SCTX_R15(%rsi), %r15
- movq SCTX_RBP(%rsi), %rbp
- movq SCTX_RBX(%rsi), %rbx
- movq SCTX_RCX(%rsi), %rcx
- movq SCTX_RDX(%rsi), %rdx
- movq SCTX_RDI(%rsi), %rdi
- movq SCTX_RSI(%rsi), %rsi /* %rsi must be restored last */
+ENTRY_NP(svm_launch)
+ pushq %rbp
+ movq %rsp, %rbp
+ subq $SVMSTKSIZE, %rsp
+ movq %r15, SVMSTK_R15(%rsp)
+ movq %r14, SVMSTK_R14(%rsp)
+ movq %r13, SVMSTK_R13(%rsp)
+ movq %r12, SVMSTK_R12(%rsp)
+ movq %rbx, SVMSTK_RBX(%rsp)
+ movq %rdx, SVMSTK_RDX(%rsp)
+ movq %rsi, SVMSTK_RSI(%rsp)
+ movq %rdi, SVMSTK_RDI(%rsp)
+
+ /* VMLOAD and VMRUN expect the VMCB physaddr in %rax */
+ movq %rdi, %rax
+
+ /* Restore guest state. */
+ movq SCTX_R8(%rsi), %r8
+ movq SCTX_R9(%rsi), %r9
+ movq SCTX_R10(%rsi), %r10
+ movq SCTX_R11(%rsi), %r11
+ movq SCTX_R12(%rsi), %r12
+ movq SCTX_R13(%rsi), %r13
+ movq SCTX_R14(%rsi), %r14
+ movq SCTX_R15(%rsi), %r15
+ movq SCTX_RBP(%rsi), %rbp
+ movq SCTX_RBX(%rsi), %rbx
+ movq SCTX_RCX(%rsi), %rcx
+ movq SCTX_RDX(%rsi), %rdx
+ movq SCTX_RDI(%rsi), %rdi
+ movq SCTX_RSI(%rsi), %rsi /* %rsi must be restored last */
VMLOAD
VMRUN
VMSAVE
- pop %rax /* pop guest context pointer from the stack */
-
- /*
- * Save guest state.
- */
- movq %r8, SCTX_R8(%rax)
- movq %r9, SCTX_R9(%rax)
- movq %r10, SCTX_R10(%rax)
- movq %r11, SCTX_R11(%rax)
- movq %r12, SCTX_R12(%rax)
- movq %r13, SCTX_R13(%rax)
- movq %r14, SCTX_R14(%rax)
- movq %r15, SCTX_R15(%rax)
- movq %rbp, SCTX_RBP(%rax)
- movq %rbx, SCTX_RBX(%rax)
- movq %rcx, SCTX_RCX(%rax)
- movq %rdx, SCTX_RDX(%rax)
- movq %rdi, SCTX_RDI(%rax)
- movq %rsi, SCTX_RSI(%rax)
-
- /* Restore host state */
- pop %r15
- pop %r14
- pop %r13
- pop %r12
- pop %rbx
-
- /* Restore %GS.base to point to the host's pcpu data */
- pop %rdx
- mov %edx, %eax
- shr $32, %rdx
- mov $MSR_GSBASE, %ecx
+ /* Grab the svm_regctx pointer */
+ movq SVMSTK_RSI(%rsp), %rax
+
+ /* Save guest state. */
+ movq %r8, SCTX_R8(%rax)
+ movq %r9, SCTX_R9(%rax)
+ movq %r10, SCTX_R10(%rax)
+ movq %r11, SCTX_R11(%rax)
+ movq %r12, SCTX_R12(%rax)
+ movq %r13, SCTX_R13(%rax)
+ movq %r14, SCTX_R14(%rax)
+ movq %r15, SCTX_R15(%rax)
+ movq %rbp, SCTX_RBP(%rax)
+ movq %rbx, SCTX_RBX(%rax)
+ movq %rcx, SCTX_RCX(%rax)
+ movq %rdx, SCTX_RDX(%rax)
+ movq %rdi, SCTX_RDI(%rax)
+ movq %rsi, SCTX_RSI(%rax)
+
+ /* Restore callee-saved registers */
+ movq SVMSTK_R15(%rsp), %r15
+ movq SVMSTK_R14(%rsp), %r14
+ movq SVMSTK_R13(%rsp), %r13
+ movq SVMSTK_R12(%rsp), %r12
+ movq SVMSTK_RBX(%rsp), %rbx
+
+ /* Fix %gsbase to point back to the correct 'struct cpu *' */
+ movq SVMSTK_RDX(%rsp), %rdx
+ movl %edx, %eax
+ shrq $32, %rdx
+ movl $MSR_GSBASE, %ecx
wrmsr
- VLEAVE
+ SVM_GUEST_FLUSH_SCRATCH
+
+ addq $SVMSTKSIZE, %rsp
+ popq %rbp
ret
-END(svm_launch)
+SET_SIZE(svm_launch)
#endif /* lint */
diff --git a/usr/src/uts/i86pc/io/vmm/intel/vmx.c b/usr/src/uts/i86pc/io/vmm/intel/vmx.c
index a723be0d28..a039455be7 100644
--- a/usr/src/uts/i86pc/io/vmm/intel/vmx.c
+++ b/usr/src/uts/i86pc/io/vmm/intel/vmx.c
@@ -2640,7 +2640,7 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
#ifdef __FreeBSD__
__asm __volatile("int $18");
#else
- vmx_call_trap(T_MCE);
+ vmm_call_trap(T_MCE);
#endif
return (1);
}
@@ -2929,7 +2929,7 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
#ifdef __FreeBSD__
__asm __volatile("int $18");
#else
- vmx_call_trap(T_MCE);
+ vmm_call_trap(T_MCE);
#endif
return (1);
}
@@ -3147,7 +3147,7 @@ vmx_exit_handle_nmi(struct vmx *vmx, int vcpuid, struct vm_exit *vmexit)
#ifdef __FreeBSD__
__asm __volatile("int $2");
#else
- vmx_call_trap(T_NMIFLT);
+ vmm_call_trap(T_NMIFLT);
#endif
}
}
diff --git a/usr/src/uts/i86pc/io/vmm/intel/vmx.h b/usr/src/uts/i86pc/io/vmm/intel/vmx.h
index 9766e6b749..2d16799bdd 100644
--- a/usr/src/uts/i86pc/io/vmm/intel/vmx.h
+++ b/usr/src/uts/i86pc/io/vmm/intel/vmx.h
@@ -164,9 +164,6 @@ CTASSERT((offsetof(struct vmx, pir_desc[0]) & 63) == 0);
#define VMX_VMWRITE_ERROR 4
int vmx_enter_guest(struct vmxctx *ctx, struct vmx *vmx, int launched);
void vmx_call_isr(uintptr_t entry);
-#ifndef __FreeBSD__
-void vmx_call_trap(uint64_t);
-#endif
u_long vmx_fix_cr0(u_long cr0);
u_long vmx_fix_cr4(u_long cr4);
diff --git a/usr/src/uts/i86pc/io/vmm/intel/vmx_support.s b/usr/src/uts/i86pc/io/vmm/intel/vmx_support.s
index a2375e3a6c..0130f88dd6 100644
--- a/usr/src/uts/i86pc/io/vmm/intel/vmx_support.s
+++ b/usr/src/uts/i86pc/io/vmm/intel/vmx_support.s
@@ -381,44 +381,4 @@ ENTRY_NP(vmx_call_isr)
ret
SET_SIZE(vmx_call_isr)
-/*
- * %rdi = trapno
- *
- * This variant is for any explicit exception injection that we need: in this
- * case, we can't just, for example, do a direct "int $2", as that will then
- * trash our %cr3 via tr_nmiint due to KPTI. So we have to fake a trap frame in
- * a similar fashion to vmx_call_isr(). Both NMIs and MCEs don't push an 'err'
- * into the frame.
- */
-ENTRY_NP(vmx_call_trap)
- pushq %rbp
- movq %rsp, %rbp
- movq %rsp, %r11
- andq $~0xf, %rsp /* align stack */
- pushq $KDS_SEL /* %ss */
- pushq %r11 /* %rsp */
- pushfq /* %rflags */
- pushq $KCS_SEL /* %cs */
- leaq .trap_iret_dest(%rip), %rcx
- pushq %rcx /* %rip */
- cli
- cmpq $T_NMIFLT, %rdi
- je nmiint
- cmpq $T_MCE, %rdi
- je mcetrap
-
- pushq %rdi /* save our bad trapno... */
- leaq __vmx_call_bad_trap(%rip), %rdi
- xorl %eax, %eax
- call panic
- /*NOTREACHED*/
-
-.trap_iret_dest:
- popq %rbp
- ret
-SET_SIZE(vmx_call_trap)
-
-__vmx_call_bad_trap:
- .string "bad trapno for vmx_call_trap()"
-
#endif /* lint */
diff --git a/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h b/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h
index 7ac745f509..600872c321 100644
--- a/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h
+++ b/usr/src/uts/i86pc/io/vmm/vm/vm_glue.h
@@ -93,6 +93,7 @@ struct vmm_pt_ops {
};
extern struct vmm_pt_ops ept_ops;
+extern struct vmm_pt_ops rvi_ops;
#endif /* _VM_GLUE_ */
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
index 2fa0267f72..4b759b44e9 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
@@ -1628,10 +1628,19 @@ vmm_is_supported(intptr_t arg)
int r;
const char *msg;
- if (!vmm_is_intel())
- return (ENXIO);
+ if (vmm_is_intel()) {
+ r = vmx_x86_supported(&msg);
+ } else if (vmm_is_amd()) {
+ /*
+ * HMA already ensured that the features necessary for SVM
+ * operation were present and online during vmm_attach().
+ */
+ r = 0;
+ } else {
+ r = ENXIO;
+ msg = "Unsupported CPU vendor";
+ }
- r = vmx_x86_supported(&msg);
if (r != 0 && arg != NULL) {
if (copyoutstr(msg, (char *)arg, strlen(msg), NULL) != 0)
return (EFAULT);
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_rvi.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_rvi.c
new file mode 100644
index 0000000000..d630d32630
--- /dev/null
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_rvi.c
@@ -0,0 +1,297 @@
+/*
+ * 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 2019 Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kmem.h>
+#include <sys/machsystm.h>
+#include <sys/x86_archext.h>
+
+#include <sys/gipt.h>
+#include <vm/vm_glue.h>
+
+
+struct rvi_map {
+ gipt_map_t rm_gipt;
+ uint64_t rm_wired_page_count;
+};
+typedef struct rvi_map rvi_map_t;
+
+#define RVI_LOCK(m) (&(m)->rm_gipt.giptm_lock)
+
+#define RVI_MAX_LEVELS 4
+
+CTASSERT(RVI_MAX_LEVELS <= GIPT_MAX_LEVELS);
+
+#define RVI_PRESENT PT_VALID
+#define RVI_WRITABLE PT_WRITABLE
+#define RVI_ACCESSED PT_REF
+#define RVI_DIRTY PT_MOD
+#define RVI_LGPG PT_PAGESIZE
+#define RVI_NX PT_NX
+#define RVI_USER PT_USER
+#define RVI_PWT PT_WRITETHRU
+#define RVI_PCD PT_NOCACHE
+
+#define RVI_PA_MASK PT_PADDR
+
+#define RVI_PAT(attr) rvi_attr_to_pat(attr)
+#define RVI_PADDR(addr) ((addr) & RVI_PA_MASK)
+#define RVI_PROT(prot) \
+ ((((prot) & PROT_WRITE) != 0 ? RVI_WRITABLE : 0) | \
+ (((prot) & PROT_EXEC) == 0 ? RVI_NX : 0))
+
+#define RVI_IS_ABSENT(pte) (((pte) & RVI_PRESENT) == 0)
+#define RVI_PTE_PFN(pte) mmu_btop(RVI_PADDR(pte))
+#define RVI_MAPS_PAGE(pte, lvl) \
+ (!RVI_IS_ABSENT(pte) && (((pte) & RVI_LGPG) != 0 || (lvl) == 0))
+#define RVI_PTE_PROT(pte) \
+ (RVI_IS_ABSENT(pte) ? 0 : ( \
+ PROT_READ | \
+ (((pte) & RVI_NX) == 0 ? PROT_EXEC : 0) | \
+ (((pte) & RVI_WRITABLE) != 0 ? PROT_WRITE : 0)))
+
+#define RVI_PTE_ASSIGN_PAGE(lvl, pfn, prot, attr) \
+ (RVI_PADDR(pfn_to_pa(pfn)) | \
+ (((lvl) != 0) ? RVI_LGPG : 0) | \
+ RVI_USER | RVI_ACCESSED | RVI_PRESENT | \
+ RVI_PAT(attr) | \
+ RVI_PROT(prot))
+
+#define RVI_PTE_ASSIGN_TABLE(pfn) \
+ (RVI_PADDR(pfn_to_pa(pfn)) | \
+ RVI_USER | RVI_ACCESSED | RVI_PRESENT | \
+ RVI_PAT(MTRR_TYPE_WB) | \
+ RVI_PROT(PROT_READ | PROT_WRITE | PROT_EXEC))
+
+
+/* Make sure that PAT indexes line up as expected */
+CTASSERT((PAT_DEFAULT_ATTRIBUTE & 0xf) == MTRR_TYPE_WB);
+CTASSERT(((PAT_DEFAULT_ATTRIBUTE >> 24) & 0xf) == MTRR_TYPE_UC);
+
+static inline uint64_t
+rvi_attr_to_pat(const uint8_t attr)
+{
+ if (attr == MTRR_TYPE_UC) {
+ /* !PAT + PCD + PWT -> PAT3 -> MTRR_TYPE_UC */
+ return (RVI_PCD|RVI_PWT);
+ } else if (attr == MTRR_TYPE_WB) {
+ /* !PAT + !PCD + !PWT -> PAT0 -> MTRR_TYPE_WB */
+ return (0);
+ }
+
+ panic("unexpected memattr %x", attr);
+ return (0);
+}
+
+static gipt_pte_type_t
+rvi_pte_type(uint64_t pte, uint_t level)
+{
+ if (RVI_IS_ABSENT(pte)) {
+ return (PTET_EMPTY);
+ } else if (RVI_MAPS_PAGE(pte, level)) {
+ return (PTET_PAGE);
+ } else {
+ return (PTET_LINK);
+ }
+}
+
+static uint64_t
+rvi_pte_map(uint64_t pfn)
+{
+ return (RVI_PTE_ASSIGN_TABLE(pfn));
+}
+
+static void *
+rvi_create(uintptr_t *pml4_kaddr)
+{
+ rvi_map_t *rmap;
+ gipt_map_t *map;
+ gipt_t *root;
+ struct gipt_cbs cbs = {
+ .giptc_pte_type = rvi_pte_type,
+ .giptc_pte_map = rvi_pte_map,
+ };
+
+ rmap = kmem_zalloc(sizeof (*rmap), KM_SLEEP);
+ map = &rmap->rm_gipt;
+ root = gipt_alloc();
+ root->gipt_level = RVI_MAX_LEVELS - 1;
+ gipt_map_init(map, RVI_MAX_LEVELS, GIPT_HASH_SIZE_DEFAULT, &cbs, root);
+
+ *pml4_kaddr = (uintptr_t)root->gipt_kva;
+ return (rmap);
+}
+
+static void
+rvi_destroy(void *arg)
+{
+ rvi_map_t *rmap = arg;
+
+ if (rmap != NULL) {
+ gipt_map_t *map = &rmap->rm_gipt;
+
+ gipt_map_fini(map);
+ kmem_free(rmap, sizeof (*rmap));
+ }
+}
+
+static uint64_t
+rvi_wired_count(void *arg)
+{
+ rvi_map_t *rmap = arg;
+ uint64_t res;
+
+ mutex_enter(RVI_LOCK(rmap));
+ res = rmap->rm_wired_page_count;
+ mutex_exit(RVI_LOCK(rmap));
+
+ return (res);
+}
+
+static int
+rvi_is_wired(void *arg, uint64_t va, uint_t *protp)
+{
+ rvi_map_t *rmap = arg;
+ gipt_t *pt;
+ int rv = -1;
+
+ mutex_enter(RVI_LOCK(rmap));
+ pt = gipt_map_lookup_deepest(&rmap->rm_gipt, va);
+ if (pt != NULL) {
+ const uint64_t pte = GIPT_VA2PTE(pt, va);
+
+ if (RVI_MAPS_PAGE(pte, pt->gipt_level)) {
+ *protp = RVI_PTE_PROT(pte);
+ rv = 0;
+ }
+ }
+ mutex_exit(RVI_LOCK(rmap));
+
+ return (rv);
+}
+
+static int
+rvi_map(void *arg, uint64_t va, pfn_t pfn, uint_t lvl, uint_t prot,
+ uint8_t attr)
+{
+ rvi_map_t *rmap = arg;
+ gipt_map_t *map = &rmap->rm_gipt;
+ gipt_t *pt;
+ uint64_t *ptep, pte;
+
+ ASSERT((prot & PROT_READ) != 0);
+ ASSERT3U((prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)), ==, 0);
+ ASSERT3U(lvl, <, RVI_MAX_LEVELS);
+
+ mutex_enter(RVI_LOCK(rmap));
+ pt = gipt_map_lookup(map, va, lvl);
+ if (pt == NULL) {
+ /*
+ * A table at the appropriate VA/level that would house this
+ * mapping does not currently exist. Try to walk down to that
+ * point, creating any necessary parent(s).
+ */
+ pt = gipt_map_create_parents(map, va, lvl);
+
+ /*
+ * There was a large page mapping in the way of creating the
+ * necessary parent table(s).
+ */
+ if (pt == NULL) {
+ panic("unexpected large page @ %08lx", va);
+ }
+ }
+ ptep = GIPT_VA2PTEP(pt, va);
+
+ pte = *ptep;
+ if (!RVI_IS_ABSENT(pte)) {
+ if (!RVI_MAPS_PAGE(pte, lvl)) {
+ panic("unexpected PT link @ %08lx in %p", va, pt);
+ } else {
+ panic("unexpected page mapped @ %08lx in %p", va, pt);
+ }
+ }
+
+ pte = RVI_PTE_ASSIGN_PAGE(lvl, pfn, prot, attr);
+ *ptep = pte;
+ pt->gipt_valid_cnt++;
+ rmap->rm_wired_page_count += gipt_level_count[lvl];
+
+ mutex_exit(RVI_LOCK(rmap));
+ return (0);
+}
+
+static uint64_t
+rvi_unmap(void *arg, uint64_t va, uint64_t end_va)
+{
+ rvi_map_t *rmap = arg;
+ gipt_map_t *map = &rmap->rm_gipt;
+ gipt_t *pt;
+ uint64_t cur_va = va;
+ uint64_t unmapped = 0;
+
+ mutex_enter(RVI_LOCK(rmap));
+
+ pt = gipt_map_lookup_deepest(map, cur_va);
+ if (pt == NULL) {
+ mutex_exit(RVI_LOCK(rmap));
+ return (0);
+ }
+ if (!RVI_MAPS_PAGE(GIPT_VA2PTE(pt, cur_va), pt->gipt_level)) {
+ cur_va = gipt_map_next_page(map, cur_va, end_va, &pt);
+ if (cur_va == 0) {
+ mutex_exit(RVI_LOCK(rmap));
+ return (0);
+ }
+ }
+
+ while (cur_va < end_va) {
+ uint64_t *ptep = GIPT_VA2PTEP(pt, cur_va);
+ const uint_t lvl = pt->gipt_level;
+
+ ASSERT(RVI_MAPS_PAGE(*ptep, lvl));
+ *ptep = 0;
+ pt->gipt_valid_cnt--;
+ unmapped += gipt_level_count[pt->gipt_level];
+
+ gipt_t *next_pt = pt;
+ uint64_t next_va;
+ next_va = gipt_map_next_page(map, cur_va, end_va, &next_pt);
+
+ if (pt->gipt_valid_cnt == 0) {
+ gipt_map_clean_parents(map, pt);
+ }
+ if (next_va == 0) {
+ break;
+ }
+ pt = next_pt;
+ cur_va = next_va;
+ }
+ rmap->rm_wired_page_count -= unmapped;
+
+ mutex_exit(RVI_LOCK(rmap));
+
+ return (unmapped);
+}
+
+struct vmm_pt_ops rvi_ops = {
+ .vpo_init = rvi_create,
+ .vpo_free = rvi_destroy,
+ .vpo_wired_cnt = rvi_wired_count,
+ .vpo_is_wired = rvi_is_wired,
+ .vpo_map = rvi_map,
+ .vpo_unmap = rvi_unmap,
+};
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c
index 8d5051144c..58a62586a1 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_vm.c
@@ -24,6 +24,7 @@
#include <sys/machsystm.h>
#include <sys/vmsystm.h>
#include <sys/malloc.h>
+#include <sys/x86_archext.h>
#include <vm/as.h>
#include <vm/seg_vn.h>
#include <vm/seg_kmem.h>
@@ -208,8 +209,17 @@ pmap_pinit_type(pmap_t pmap, enum pmap_type type, int flags)
pmap->pm_pml4 = pml4;
return (1);
}
- case PT_RVI:
- /* RVI support not yet implemented */
+ case PT_RVI: {
+ struct vmm_pt_ops *ops = &rvi_ops;
+ void *pml4, *pmi;
+
+ pmi = ops->vpo_init((uintptr_t *)&pml4);
+
+ pmap->pm_ops = ops;
+ pmap->pm_impl = pmi;
+ pmap->pm_pml4 = pml4;
+ return (1);
+ }
default:
panic("unsupported pmap type: %x", type);
break;
@@ -537,6 +547,8 @@ vm_object_deallocate(vm_object_t vmo)
kmem_free(vmo, sizeof (*vmo));
}
+CTASSERT(VM_MEMATTR_UNCACHEABLE == MTRR_TYPE_UC);
+CTASSERT(VM_MEMATTR_WRITE_BACK == MTRR_TYPE_WB);
int
vm_object_set_memattr(vm_object_t vmo, vm_memattr_t attr)
{
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_support.s b/usr/src/uts/i86pc/io/vmm/vmm_support.s
new file mode 100644
index 0000000000..5777d46959
--- /dev/null
+++ b/usr/src/uts/i86pc/io/vmm/vmm_support.s
@@ -0,0 +1,54 @@
+/*
+ * 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 2019 Joyent, Inc.
+ */
+
+#include <sys/asm_linkage.h>
+#include <sys/segments.h>
+
+/*
+ * %rdi = trapno
+ *
+ * This variant is for any explicit exception injection that we need: in this
+ * case, we can't just, for example, do a direct "int $2", as that will then
+ * trash our %cr3 via tr_nmiint due to KPTI, so we have to fake a trap frame.
+ * Both NMIs and MCEs don't push an 'err' into the frame.
+ */
+ENTRY_NP(vmm_call_trap)
+ pushq %rbp
+ movq %rsp, %rbp
+ movq %rsp, %r11
+ andq $~0xf, %rsp /* align stack */
+ pushq $KDS_SEL /* %ss */
+ pushq %r11 /* %rsp */
+ pushfq /* %rflags */
+ pushq $KCS_SEL /* %cs */
+ leaq .trap_iret_dest(%rip), %rcx
+ pushq %rcx /* %rip */
+ cli
+ cmpq $T_NMIFLT, %rdi
+ je nmiint
+ cmpq $T_MCE, %rdi
+ je mcetrap
+
+ pushq %rdi /* save our bad trapno... */
+ leaq __vmm_call_bad_trap(%rip), %rdi
+ xorl %eax, %eax
+ call panic
+ /*NOTREACHED*/
+
+.trap_iret_dest:
+ popq %rbp
+ ret
+SET_SIZE(vmm_call_trap)
+
+__vmm_call_bad_trap:
+ .string "bad trapno for vmm_call_trap()"
diff --git a/usr/src/uts/i86pc/io/vmm/x86.c b/usr/src/uts/i86pc/io/vmm/x86.c
index b02142e7e5..b126e96f2c 100644
--- a/usr/src/uts/i86pc/io/vmm/x86.c
+++ b/usr/src/uts/i86pc/io/vmm/x86.c
@@ -198,6 +198,18 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id,
/* Hide mwaitx/monitorx capability from the guest */
regs[2] &= ~AMDID2_MWAITX;
+#ifndef __FreeBSD__
+ /*
+ * Detection routines for TCE and FFXSR are missing
+ * from our vm_cpuid_capability() detection logic
+ * today. Mask them out until that is remedied.
+ * They do not appear to be in common usage, so their
+ * absence should not cause undue trouble.
+ */
+ regs[2] &= ~AMDID2_TCE;
+ regs[3] &= ~AMDID_FFXSR;
+#endif
+
/*
* Hide rdtscp/ia32_tsc_aux until we know how
* to deal with them.
diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c
index d0489a0148..cf4ee31df7 100644
--- a/usr/src/uts/i86pc/os/cpuid.c
+++ b/usr/src/uts/i86pc/os/cpuid.c
@@ -819,6 +819,23 @@
* share the same last level cache. IDs should not overlap between
* packages.
*
+ * cpi_ncore_bits
+ *
+ * This indicates the number of bits that are required to represent all of
+ * the cores in the system. As cores are derived based on their APIC IDs,
+ * we aren't guaranteed a run of APIC IDs starting from zero. It's OK for
+ * this value to be larger than the actual number of IDs that are present
+ * in the system. This is used to size tables by the CMI framework. It is
+ * only filled in for Intel and AMD CPUs.
+ *
+ * cpi_nthread_bits
+ *
+ * This indicates the number of bits required to represent all of the IDs
+ * that cover the logical CPUs that exist on a given core. It's OK for this
+ * value to be larger than the actual number of IDs that are present in the
+ * system. This is used to size tables by the CMI framework. It is
+ * only filled in for Intel and AMD CPUs.
+ *
* -----------
* Hypervisors
* -----------
@@ -1184,6 +1201,13 @@ struct cpuid_info {
int cpi_pkgcoreid; /* core number within single package */
uint_t cpi_ncore_per_chip; /* AMD: fn 0x80000008: %ecx[7-0] */
/* Intel: fn 4: %eax[31-26] */
+
+ /*
+ * These values represent the number of bits that are required to store
+ * information about the number of cores and threads.
+ */
+ uint_t cpi_ncore_bits;
+ uint_t cpi_nthread_bits;
/*
* supported feature information
*/
@@ -1704,17 +1728,30 @@ cpuid_amd_ncores(struct cpuid_info *cpi, uint_t *ncpus, uint_t *ncores)
*ncores = nthreads / nthread_per_core;
}
+/*
+ * Seed the initial values for the cores and threads for an Intel based
+ * processor. These values will be overwritten if we detect that the processor
+ * supports CPUID leaf 0xb.
+ */
static void
cpuid_intel_ncores(struct cpuid_info *cpi, uint_t *ncpus, uint_t *ncores)
{
+ /*
+ * Only seed the number of physical cores from the first level leaf 4
+ * information. The number of threads there indicate how many share the
+ * L1 cache, which may or may not have anything to do with the number of
+ * logical CPUs per core.
+ */
if (cpi->cpi_maxeax >= 4) {
*ncores = BITX(cpi->cpi_std[4].cp_eax, 31, 26) + 1;
- *ncpus = BITX(cpi->cpi_std[4].cp_eax, 25, 14) + 1;
- } else if ((cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_HTT) != 0) {
+ } else {
*ncores = 1;
+ }
+
+ if ((cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_HTT) != 0) {
*ncpus = CPI_CPU_COUNT(cpi);
} else {
- *ncpus = *ncores = 1;
+ *ncpus = *ncores;
}
}
@@ -1779,6 +1816,11 @@ cpuid_leafB_getids(cpu_t *cpu)
cpi->cpi_procnodeid = cpi->cpi_chipid;
cpi->cpi_compunitid = cpi->cpi_coreid;
+ if (coreid_shift > 0 && chipid_shift > coreid_shift) {
+ cpi->cpi_nthread_bits = coreid_shift;
+ cpi->cpi_ncore_bits = chipid_shift - coreid_shift;
+ }
+
return (B_TRUE);
} else {
return (B_FALSE);
@@ -1807,6 +1849,17 @@ cpuid_intel_getids(cpu_t *cpu, void *feature)
if (cpuid_leafB_getids(cpu))
return;
+ /*
+ * In this case, we have the leaf 1 and leaf 4 values for ncpu_per_chip
+ * and ncore_per_chip. These represent the largest power of two values
+ * that we need to cover all of the IDs in the system. Therefore, we use
+ * those values to seed the number of bits needed to cover information
+ * in the case when leaf B is not available. These values will probably
+ * be larger than required, but that's OK.
+ */
+ cpi->cpi_nthread_bits = ddi_fls(cpi->cpi_ncpu_per_chip);
+ cpi->cpi_ncore_bits = ddi_fls(cpi->cpi_ncore_per_chip);
+
for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1)
chipid_shift++;
@@ -2059,6 +2112,10 @@ cpuid_amd_getids(cpu_t *cpu, uchar_t *features)
cpi->cpi_chipid =
cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg;
+
+ cpi->cpi_ncore_bits = coreidsz;
+ cpi->cpi_nthread_bits = ddi_fls(cpi->cpi_ncpu_per_chip /
+ cpi->cpi_ncore_per_chip);
}
static void
@@ -6466,20 +6523,27 @@ patch_memops(uint_t vendor)
/*
* We're being asked to tell the system how many bits are required to represent
- * the various thread and strand IDs.
+ * the various thread and strand IDs. While it's tempting to derive this based
+ * on the values in cpi_ncore_per_chip and cpi_ncpu_per_chip, that isn't quite
+ * correct. Instead, this needs to be based on the number of bits that the APIC
+ * allows for these different configurations. We only update these to a larger
+ * value if we find one.
*/
void
cpuid_get_ext_topo(cpu_t *cpu, uint_t *core_nbits, uint_t *strand_nbits)
{
struct cpuid_info *cpi;
- uint_t nthreads;
VERIFY(cpuid_checkpass(CPU, 1));
cpi = cpu->cpu_m.mcpu_cpi;
- nthreads = cpi->cpi_ncpu_per_chip / cpi->cpi_ncore_per_chip;
- *core_nbits = ddi_fls(cpi->cpi_ncore_per_chip);
- *strand_nbits = ddi_fls(nthreads);
+ if (cpi->cpi_ncore_bits > *core_nbits) {
+ *core_nbits = cpi->cpi_ncore_bits;
+ }
+
+ if (cpi->cpi_nthread_bits > *strand_nbits) {
+ *strand_nbits = cpi->cpi_nthread_bits;
+ }
}
void
diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c
index d22f55b58e..60982a49fc 100644
--- a/usr/src/uts/i86pc/os/fakebop.c
+++ b/usr/src/uts/i86pc/os/fakebop.c
@@ -2916,10 +2916,8 @@ boot_compinfo(int fd, struct compinfo *cbp)
return (0);
}
-#define BP_MAX_STRLEN 32
-
/*
- * Get value for given boot property
+ * Get an integer value for given boot property
*/
int
bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
@@ -2929,7 +2927,7 @@ bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
u_longlong_t value;
boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
- if (boot_prop_len < 0 || boot_prop_len > sizeof (str) ||
+ if (boot_prop_len < 0 || boot_prop_len >= sizeof (str) ||
BOP_GETPROP(bootops, prop_name, str) < 0 ||
kobj_getvalue(str, &value) == -1)
return (-1);
@@ -2939,3 +2937,15 @@ bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
return (0);
}
+
+int
+bootprop_getstr(const char *prop_name, char *buf, size_t buflen)
+{
+ int boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
+
+ if (boot_prop_len < 0 || boot_prop_len >= buflen ||
+ BOP_GETPROP(bootops, prop_name, buf) < 0)
+ return (-1);
+
+ return (0);
+}
diff --git a/usr/src/uts/i86pc/os/hma.c b/usr/src/uts/i86pc/os/hma.c
index 34ae85086d..c7c0984db7 100644
--- a/usr/src/uts/i86pc/os/hma.c
+++ b/usr/src/uts/i86pc/os/hma.c
@@ -32,28 +32,39 @@ struct hma_reg {
static kmutex_t hma_lock;
static list_t hma_registrations;
+static boolean_t hma_exclusive = B_FALSE;
static boolean_t hma_vmx_ready = B_FALSE;
static const char *hma_vmx_error = NULL;
static id_space_t *hma_vmx_vpid;
-typedef enum vmx_cpu_state {
- VCS_UNINITIALIZED = 0,
- VCS_READY,
- VCS_ERROR
-} vmx_cpu_state_t;
-
/*
- * The bulk of VMX-related HMA state is protected by cpu_lock, rather than a
+ * The bulk of HMA state (VMX & SVM) is protected by cpu_lock, rather than a
* mutex specific to the module. It (cpu_lock) is already required for the
* state needed to perform setup on all CPUs, so it was a natural fit to
* protect this data too.
*/
+typedef enum hma_cpu_state {
+ HCS_UNINITIALIZED = 0,
+ HCS_READY,
+ HCS_ERROR
+} hma_cpu_state_t;
+static hma_cpu_state_t hma_cpu_status[NCPU];
+
static void *hma_vmx_vmxon_page[NCPU];
static uintptr_t hma_vmx_vmxon_pa[NCPU];
-static vmx_cpu_state_t hma_vmx_status[NCPU];
static uint32_t hma_vmx_revision;
+static boolean_t hma_svm_ready = B_FALSE;
+static const char *hma_svm_error = NULL;
+static uint32_t hma_svm_features;
+static uint32_t hma_svm_max_asid;
+
+static void *hma_svm_hsave_page[NCPU];
+static uintptr_t hma_svm_hsave_pa[NCPU];
+
+static hma_svm_asid_t hma_svm_cpu_asid[NCPU];
+
static int hma_vmx_init(void);
static int hma_svm_init(void);
@@ -77,37 +88,68 @@ hma_init(void)
}
}
-hma_reg_t *
-hma_register(const char *name)
+static hma_reg_t *
+hma_register_backend(const char *name)
{
struct hma_reg *reg;
boolean_t is_ready;
- VERIFY(name != NULL);
-
- reg = kmem_zalloc(sizeof (*reg), KM_SLEEP);
- reg->hr_name = name;
+ ASSERT(MUTEX_HELD(&hma_lock));
- mutex_enter(&hma_lock);
switch (cpuid_getvendor(CPU)) {
case X86_VENDOR_Intel:
is_ready = hma_vmx_ready;
break;
case X86_VENDOR_AMD:
- /* Punt on SVM support for now */
- is_ready = B_FALSE;
+ is_ready = hma_svm_ready;
break;
default:
is_ready = B_FALSE;
break;
}
- if (!is_ready) {
- kmem_free(reg, sizeof (*reg));
- reg = NULL;
- } else {
- list_insert_tail(&hma_registrations, reg);
+ if (!is_ready)
+ return (NULL);
+
+ reg = kmem_zalloc(sizeof (*reg), KM_SLEEP);
+ reg->hr_name = name;
+ list_insert_tail(&hma_registrations, reg);
+
+ return (reg);
+}
+
+hma_reg_t *
+hma_register(const char *name)
+{
+ struct hma_reg *reg = NULL;
+
+ VERIFY(name != NULL);
+
+ mutex_enter(&hma_lock);
+
+ if (!hma_exclusive)
+ reg = hma_register_backend(name);
+
+ mutex_exit(&hma_lock);
+
+ return (reg);
+}
+
+hma_reg_t *
+hma_register_exclusive(const char *name)
+{
+ struct hma_reg *reg = NULL;
+
+ VERIFY(name != NULL);
+
+ mutex_enter(&hma_lock);
+
+ if (list_is_empty(&hma_registrations)) {
+ reg = hma_register_backend(name);
+ if (reg != NULL)
+ hma_exclusive = B_TRUE;
}
+
mutex_exit(&hma_lock);
return (reg);
@@ -121,6 +163,8 @@ hma_unregister(hma_reg_t *reg)
mutex_enter(&hma_lock);
list_remove(&hma_registrations, reg);
+ if (hma_exclusive && list_is_empty(&hma_registrations))
+ hma_exclusive = B_FALSE;
mutex_exit(&hma_lock);
kmem_free(reg, sizeof (*reg));
}
@@ -156,9 +200,9 @@ hma_vmx_vpid_free(uint16_t vpid)
extern int hma_vmx_vmxon(uintptr_t);
-/* ARGSUSED */
static int
-hma_vmx_cpu_vmxon(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
+hma_vmx_cpu_vmxon(xc_arg_t arg1 __unused, xc_arg_t arg2 __unused,
+ xc_arg_t arg3 __unused)
{
uint64_t fctrl;
processorid_t id = CPU->cpu_seqid;
@@ -181,9 +225,9 @@ hma_vmx_cpu_vmxon(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
setcr4(getcr4() | CR4_VMXE);
if (hma_vmx_vmxon(vmxon_pa) == 0) {
- hma_vmx_status[id] = VCS_READY;
+ hma_cpu_status[id] = HCS_READY;
} else {
- hma_vmx_status[id] = VCS_ERROR;
+ hma_cpu_status[id] = HCS_ERROR;
/*
* If VMX has already been marked active and available for the
@@ -198,9 +242,8 @@ hma_vmx_cpu_vmxon(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
return (0);
}
-/* ARGSUSED2 */
static int
-hma_vmx_cpu_setup(cpu_setup_t what, int id, void *arg)
+hma_vmx_cpu_setup(cpu_setup_t what, int id, void *arg __unused)
{
ASSERT(MUTEX_HELD(&cpu_lock));
ASSERT(id >= 0 && id < NCPU);
@@ -223,8 +266,8 @@ hma_vmx_cpu_setup(cpu_setup_t what, int id, void *arg)
}
/* Perform initialization if it has not been previously attempted. */
- if (hma_vmx_status[id] != VCS_UNINITIALIZED) {
- return ((hma_vmx_status[id] == VCS_READY) ? 0 : -1);
+ if (hma_cpu_status[id] != HCS_UNINITIALIZED) {
+ return ((hma_cpu_status[id] == HCS_READY) ? 0 : -1);
}
/* Allocate the VMXON page for this CPU */
@@ -265,7 +308,7 @@ hma_vmx_cpu_setup(cpu_setup_t what, int id, void *arg)
xc_sync(0, 0, 0, CPUSET2BV(set), hma_vmx_cpu_vmxon);
}
- return (hma_vmx_status[id] != VCS_READY);
+ return (hma_cpu_status[id] != HCS_READY);
}
static int
@@ -329,10 +372,233 @@ bail:
return (-1);
}
+#define VMCB_FLUSH_NOTHING 0x0
+#define VMCB_FLUSH_ALL 0x1
+#define VMCB_FLUSH_ASID 0x3
+
+void
+hma_svm_asid_init(hma_svm_asid_t *vcp)
+{
+ /*
+ * Initialize the generation to 0, forcing an ASID allocation on first
+ * entry. Leave the ASID at 0, so if the host forgoes the call to
+ * hma_svm_asid_update(), SVM will bail on the invalid vcpu state.
+ */
+ vcp->hsa_gen = 0;
+ vcp->hsa_asid = 0;
+}
+
+uint8_t
+hma_svm_asid_update(hma_svm_asid_t *vcp, boolean_t flush_by_asid,
+ boolean_t npt_flush)
+{
+ hma_svm_asid_t *hcp = &hma_svm_cpu_asid[CPU->cpu_seqid];
+
+ ASSERT(curthread->t_preempt != 0);
+
+ /*
+ * If NPT changes dictate a TLB flush and by-ASID flushing is not
+ * supported/used, force a fresh ASID allocation.
+ */
+ if (npt_flush && !flush_by_asid) {
+ vcp->hsa_gen = 0;
+ }
+
+ if (vcp->hsa_gen != hcp->hsa_gen) {
+ hcp->hsa_asid++;
+
+ if (hcp->hsa_asid >= hma_svm_max_asid) {
+ /* Keep the ASID properly constrained */
+ hcp->hsa_asid = 1;
+ hcp->hsa_gen++;
+ if (hcp->hsa_gen == 0) {
+ /*
+ * Stay clear of the '0' sentinel value for
+ * generation, if wrapping around.
+ */
+ hcp->hsa_gen = 1;
+ }
+ }
+ vcp->hsa_gen = hcp->hsa_gen;
+ vcp->hsa_asid = hcp->hsa_asid;
+
+ ASSERT(vcp->hsa_asid != 0);
+ ASSERT3U(vcp->hsa_asid, <, hma_svm_max_asid);
+
+ if (flush_by_asid) {
+ return (VMCB_FLUSH_ASID);
+ }
+ return (VMCB_FLUSH_ALL);
+ } else if (npt_flush) {
+ ASSERT(flush_by_asid);
+ return (VMCB_FLUSH_ASID);
+ }
+ return (VMCB_FLUSH_NOTHING);
+}
+
+static int
+hma_svm_cpu_activate(xc_arg_t arg1 __unused, xc_arg_t arg2 __unused,
+ xc_arg_t arg3 __unused)
+{
+ const processorid_t id = CPU->cpu_seqid;
+ const uintptr_t hsave_pa = hma_svm_hsave_pa[id];
+ uint64_t efer;
+
+ VERIFY(hsave_pa != 0);
+
+ /* Enable SVM via EFER */
+ efer = rdmsr(MSR_AMD_EFER);
+ efer |= AMD_EFER_SVME;
+ wrmsr(MSR_AMD_EFER, efer);
+
+ /* Setup hsave area */
+ wrmsr(MSR_AMD_VM_HSAVE_PA, hsave_pa);
+
+ hma_cpu_status[id] = HCS_READY;
+ return (0);
+}
+
+static int
+hma_svm_cpu_setup(cpu_setup_t what, int id, void *arg __unused)
+{
+ ASSERT(MUTEX_HELD(&cpu_lock));
+ ASSERT(id >= 0 && id < NCPU);
+
+ switch (what) {
+ case CPU_CONFIG:
+ case CPU_ON:
+ case CPU_INIT:
+ break;
+ default:
+ /*
+ * Other events, such as CPU offlining, are of no interest.
+ * Letting the SVM state linger should not cause any harm.
+ *
+ * This logic assumes that any offlining activity is strictly
+ * administrative in nature and will not alter any existing
+ * configuration (such as EFER bits previously set).
+ */
+ return (0);
+ }
+
+ /* Perform initialization if it has not been previously attempted. */
+ if (hma_cpu_status[id] != HCS_UNINITIALIZED) {
+ return ((hma_cpu_status[id] == HCS_READY) ? 0 : -1);
+ }
+
+ /* Allocate the hsave page for this CPU */
+ if (hma_svm_hsave_page[id] == NULL) {
+ caddr_t va;
+ pfn_t pfn;
+
+ va = kmem_alloc(PAGESIZE, KM_SLEEP);
+ VERIFY0((uintptr_t)va & PAGEOFFSET);
+ hma_svm_hsave_page[id] = va;
+
+ /*
+ * Cache the physical address of the hsave page rather than
+ * looking it up later when the potential blocking of
+ * hat_getpfnum would be less acceptable.
+ */
+ pfn = hat_getpfnum(kas.a_hat, va);
+ hma_svm_hsave_pa[id] = (pfn << PAGESHIFT);
+ } else {
+ VERIFY(hma_svm_hsave_pa[id] != 0);
+ }
+
+ kpreempt_disable();
+ if (CPU->cpu_seqid == id) {
+ /* Perform svm setup directly if this CPU is the target */
+ (void) hma_svm_cpu_activate(0, 0, 0);
+ kpreempt_enable();
+ } else {
+ cpuset_t set;
+
+ /* Use a cross-call if a remote CPU is the target */
+ kpreempt_enable();
+ cpuset_zero(&set);
+ cpuset_add(&set, id);
+ xc_sync(0, 0, 0, CPUSET2BV(set), hma_svm_cpu_activate);
+ }
+
+ return (hma_cpu_status[id] != HCS_READY);
+}
static int
hma_svm_init(void)
{
- /* punt on AMD for now */
- return (ENOTSUP);
+ uint64_t msr;
+ const char *msg = NULL;
+ struct cpuid_regs regs;
+ cpu_t *cp;
+
+ if (!is_x86_feature(x86_featureset, X86FSET_SVM)) {
+ msg = "CPU does not support SVM";
+ goto bail;
+ }
+
+ msr = rdmsr(MSR_AMD_VM_CR);
+ if ((msr & AMD_VM_CR_SVMDIS) != 0) {
+ msg = "SVM disabled by BIOS";
+ goto bail;
+ }
+
+ regs.cp_eax = 0x8000000a;
+ (void) cpuid_insn(NULL, &regs);
+ const uint32_t nasid = regs.cp_ebx;
+ const uint32_t feat = regs.cp_edx;
+
+ if (nasid == 0) {
+ msg = "Not enough ASIDs for guests";
+ goto bail;
+ }
+ if ((feat & CPUID_AMD_EDX_NESTED_PAGING) == 0) {
+ msg = "CPU does not support nested paging";
+ goto bail;
+ }
+ if ((feat & CPUID_AMD_EDX_NRIPS) == 0) {
+ msg = "CPU does not support NRIP save";
+ goto bail;
+ }
+
+ hma_svm_features = feat;
+ hma_svm_max_asid = nasid;
+
+ mutex_enter(&cpu_lock);
+ /* Perform SVM configuration for already-online CPUs. */
+ cp = cpu_active;
+ do {
+ int err = hma_svm_cpu_setup(CPU_ON, cp->cpu_seqid, NULL);
+ if (err != 0) {
+ msg = "failure during SVM setup";
+ mutex_exit(&cpu_lock);
+ goto bail;
+ }
+ } while ((cp = cp->cpu_next_onln) != cpu_active);
+
+ /*
+ * Register callback for later-onlined CPUs and perform other remaining
+ * resource allocation.
+ */
+ register_cpu_setup_func(hma_svm_cpu_setup, NULL);
+ mutex_exit(&cpu_lock);
+
+ /* Initialize per-CPU ASID state. */
+ for (uint_t i = 0; i < NCPU; i++) {
+ /*
+ * Skip past sentinel 0 value for generation. Doing so for
+ * ASID is unneeded, since it will be incremented during the
+ * first allocation.
+ */
+ hma_svm_cpu_asid[i].hsa_gen = 1;
+ hma_svm_cpu_asid[i].hsa_asid = 0;
+ }
+
+ hma_svm_ready = B_TRUE;
+ return (0);
+
+bail:
+ hma_svm_error = msg;
+ cmn_err(CE_NOTE, "hma_svm_init: %s", msg);
+ return (-1);
}
diff --git a/usr/src/uts/i86pc/os/mlsetup.c b/usr/src/uts/i86pc/os/mlsetup.c
index 7c17aab541..94d4695141 100644
--- a/usr/src/uts/i86pc/os/mlsetup.c
+++ b/usr/src/uts/i86pc/os/mlsetup.c
@@ -23,7 +23,7 @@
*
* Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
*/
/*
* Copyright (c) 2010, Intel Corporation.
@@ -61,6 +61,8 @@
#include <sys/archsystm.h>
#include <sys/promif.h>
#include <sys/pci_cfgspace.h>
+#include <sys/apic.h>
+#include <sys/apic_common.h>
#include <sys/bootvfs.h>
#include <sys/tsc.h>
#ifdef __xpv
@@ -79,6 +81,8 @@ extern uint32_t cpuid_feature_ecx_exclude;
extern uint32_t cpuid_feature_edx_include;
extern uint32_t cpuid_feature_edx_exclude;
+int nmi_action = NMI_ACTION_UNSET;
+
/*
* Set console mode
*/
@@ -103,6 +107,7 @@ void
mlsetup(struct regs *rp)
{
u_longlong_t prop_value;
+ char prop_str[BP_MAX_STRLEN];
extern struct classfuncs sys_classfuncs;
extern disp_t cpu0_disp;
extern char t0stack[];
@@ -149,6 +154,19 @@ mlsetup(struct regs *rp)
cpuid_feature_edx_exclude = (uint32_t)prop_value;
#if !defined(__xpv)
+ if (bootprop_getstr("nmi", prop_str, sizeof (prop_str)) == 0) {
+ if (strcmp(prop_str, "ignore") == 0) {
+ nmi_action = NMI_ACTION_IGNORE;
+ } else if (strcmp(prop_str, "panic") == 0) {
+ nmi_action = NMI_ACTION_PANIC;
+ } else if (strcmp(prop_str, "kmdb") == 0) {
+ nmi_action = NMI_ACTION_KMDB;
+ } else {
+ prom_printf("unix: ignoring unknown nmi=%s\n",
+ prop_str);
+ }
+ }
+
/*
* Check to see if KPTI has been explicitly enabled or disabled.
* We have to check this before init_desctbls().
diff --git a/usr/src/uts/i86pc/sys/Makefile b/usr/src/uts/i86pc/sys/Makefile
index e6ea573d0b..ecd87a9538 100644
--- a/usr/src/uts/i86pc/sys/Makefile
+++ b/usr/src/uts/i86pc/sys/Makefile
@@ -46,6 +46,7 @@ CHKHDRS= \
ddi_subrdefs.h \
debug_info.h \
fastboot.h \
+ hma.h \
ht.h \
mach_mmu.h \
machclock.h \
diff --git a/usr/src/uts/i86pc/sys/apic_common.h b/usr/src/uts/i86pc/sys/apic_common.h
index 03e851a4dc..58b9bb93a6 100644
--- a/usr/src/uts/i86pc/sys/apic_common.h
+++ b/usr/src/uts/i86pc/sys/apic_common.h
@@ -23,7 +23,7 @@
* Copyright (c) 2017 by Delphix. All rights reserved.
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
*/
#ifndef _SYS_APIC_COMMON_H
@@ -155,7 +155,6 @@ extern lock_t apic_nmi_lock;
extern lock_t apic_error_lock;
/* Patchable global variables. */
-extern int apic_kmdb_on_nmi; /* 0 - no, 1 - yes enter kmdb */
extern uint32_t apic_divide_reg_init; /* 0 - divide by 2 */
extern apic_intrmap_ops_t *apic_vt_ops;
@@ -202,6 +201,13 @@ extern int apic_msix_enable;
extern uint32_t apic_get_localapicid(uint32_t cpuid);
extern uchar_t apic_get_ioapicid(uchar_t ioapicindex);
+#define NMI_ACTION_UNSET (0)
+#define NMI_ACTION_PANIC (1)
+#define NMI_ACTION_IGNORE (2)
+#define NMI_ACTION_KMDB (3)
+
+extern int nmi_action;
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/i86pc/sys/hma.h b/usr/src/uts/i86pc/sys/hma.h
index 0c6161fdfc..0f4beb0452 100644
--- a/usr/src/uts/i86pc/sys/hma.h
+++ b/usr/src/uts/i86pc/sys/hma.h
@@ -38,6 +38,7 @@ extern "C" {
*/
typedef struct hma_reg hma_reg_t;
extern hma_reg_t *hma_register(const char *);
+extern hma_reg_t *hma_register_exclusive(const char *);
extern void hma_unregister(hma_reg_t *);
/*
@@ -49,6 +50,15 @@ extern void hma_unregister(hma_reg_t *);
extern uint16_t hma_vmx_vpid_alloc(void);
extern void hma_vmx_vpid_free(uint16_t);
+struct hma_svm_asid {
+ uint64_t hsa_gen;
+ uint32_t hsa_asid;
+};
+typedef struct hma_svm_asid hma_svm_asid_t;
+
+extern void hma_svm_asid_init(hma_svm_asid_t *);
+extern uint8_t hma_svm_asid_update(hma_svm_asid_t *, boolean_t, boolean_t);
+
/*
* FPU related management. These functions provide a set of APIs to manage the
* FPU state and switch between host and guest management of this state.
diff --git a/usr/src/uts/i86pc/sys/vmm.h b/usr/src/uts/i86pc/sys/vmm.h
index 163c0781cf..e5e5460211 100644
--- a/usr/src/uts/i86pc/sys/vmm.h
+++ b/usr/src/uts/i86pc/sys/vmm.h
@@ -38,7 +38,7 @@
* http://www.illumos.org/license/CDDL.
*
* Copyright 2015 Pluribus Networks Inc.
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _VMM_H_
@@ -741,6 +741,8 @@ void vmm_sol_glue_cleanup(void);
int vmm_mod_load(void);
int vmm_mod_unload(void);
+void vmm_call_trap(uint64_t);
+
/*
* Because of tangled headers, these are mirrored by vmm_drv.h to present the
* interface to driver consumers.
diff --git a/usr/src/uts/intel/ip/ip.global-objs.debug64 b/usr/src/uts/intel/ip/ip.global-objs.debug64
index d189c7a47c..691b7da537 100644
--- a/usr/src/uts/intel/ip/ip.global-objs.debug64
+++ b/usr/src/uts/intel/ip/ip.global-objs.debug64
@@ -21,7 +21,7 @@
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2011 Nexenta Systems, Inc. All rights reserved
-# Copyright 2017 Joyent, Inc.
+# Copyright 2019 Joyent, Inc. All rights reserved
#
arp_m_tbl
@@ -119,11 +119,13 @@ ip_g_all_ones
ip_helper_stream_info
ip_helper_stream_rinit
ip_helper_stream_winit
+ip_ill_mcast_reclaim
ip_ioctl_ftbl
ip_loopback_mtu_v6plus
ip_loopback_mtuplus
ip_m_tbl
ip_max_frag_dups
+ip_max_ill_mcast_nces
ip_min_frag_prune_time
ip_minor_arena_la
ip_minor_arena_sa
diff --git a/usr/src/uts/intel/ip/ip.global-objs.obj64 b/usr/src/uts/intel/ip/ip.global-objs.obj64
index e2b81e66a0..624f9984f0 100644
--- a/usr/src/uts/intel/ip/ip.global-objs.obj64
+++ b/usr/src/uts/intel/ip/ip.global-objs.obj64
@@ -21,7 +21,7 @@
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2011 Nexenta Systems, Inc. All rights reserved
-# Copyright 2017 Joyent, Inc.
+# Copyright 2019 Joyent, Inc. All rights reserved
#
arp_m_tbl
@@ -119,11 +119,13 @@ ip_g_all_ones
ip_helper_stream_info
ip_helper_stream_rinit
ip_helper_stream_winit
+ip_ill_mcast_reclaim
ip_ioctl_ftbl
ip_loopback_mtu_v6plus
ip_loopback_mtuplus
ip_m_tbl
ip_max_frag_dups
+ip_max_ill_mcast_nces
ip_min_frag_prune_time
ip_minor_arena_la
ip_minor_arena_sa
diff --git a/usr/src/uts/intel/nsmb/ioc_check.ref b/usr/src/uts/intel/nsmb/ioc_check.ref
index 9d670f24c3..7476bc696d 100644
--- a/usr/src/uts/intel/nsmb/ioc_check.ref
+++ b/usr/src/uts/intel/nsmb/ioc_check.ref
@@ -3,10 +3,12 @@
#define ID_DOMAIN_INCR 0x1
#define ID_USER 0x120
#define ID_USER_INCR 0x1
-#define SSN_VOPT 0x0
-#define SSN_OWNER 0x4
-#define SSN_ID 0x8
-#define SSN_SRVNAME 0x228
+#define SSN_OWNER 0x0
+#define SSN_VOPT 0x4
+#define SSN_MINVER 0x8
+#define SSN_MAXVER 0xa
+#define SSN_ID 0xc
+#define SSN_SRVNAME 0x22c
#define SSN_SRVNAME_INCR 0x1
#define SH_USE 0x0
#define SH_TYPE 0x4
@@ -17,70 +19,27 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#define WK_CL_GUID 0x28
+#define WK_CL_GUID_INCR 0x1
#define SIZEOF_SMBIOC_RW 0x18
-#define IOC_FH 0x0
-#define IOC_CNT 0x4
+#define IOC_CNT 0x0
+#define IOC_FLAGS 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_TDLEN 0x0
+#define IOC_RDLEN 0x4
+#define IOC_MORE 0x8
+#define IOC_PAD1 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_NTCREATE 0x114
#define IOC_REQ_ACC 0x0
#define IOC_EFATTR 0x4
diff --git a/usr/src/uts/intel/pcbe/core_pcbe.c b/usr/src/uts/intel/pcbe/core_pcbe.c
index 7424e2526b..ad92c2f62f 100644
--- a/usr/src/uts/intel/pcbe/core_pcbe.c
+++ b/usr/src/uts/intel/pcbe/core_pcbe.c
@@ -994,7 +994,8 @@ core_pcbe_event_coverage(char *event)
} else {
if (find_generic_events(event, cmn_generic_events) != NULL) {
bitmap |= BITMASK_XBITS(num_gpc);
- } if (find_generic_events(event, generic_events_pic0) != NULL) {
+ } else if (find_generic_events(event,
+ generic_events_pic0) != NULL) {
bitmap |= 1ULL;
} else if (find_gpcevent_core_uarch(event,
cmn_gpc_events_core_uarch) != NULL) {
diff --git a/usr/src/uts/intel/sys/bootconf.h b/usr/src/uts/intel/sys/bootconf.h
index 27a89206cf..f0ade9d94d 100644
--- a/usr/src/uts/intel/sys/bootconf.h
+++ b/usr/src/uts/intel/sys/bootconf.h
@@ -23,6 +23,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2019, Joyent, Inc.
*/
#ifndef _SYS_BOOTCONF_H
@@ -46,6 +47,8 @@
extern "C" {
#endif
+#define BP_MAX_STRLEN 32
+
/*
* Boot property names
*/
@@ -243,6 +246,7 @@ extern void bop_panic(const char *, ...)
extern void boot_prop_finish(void);
extern int bootprop_getval(const char *, u_longlong_t *);
+extern int bootprop_getstr(const char *, char *, size_t);
/*
* Back door to fakebop.c to get physical memory allocated.
diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h
index babf036e0b..0be7b3b650 100644
--- a/usr/src/uts/intel/sys/controlregs.h
+++ b/usr/src/uts/intel/sys/controlregs.h
@@ -200,6 +200,18 @@ extern "C" {
#define MSR_AMD_KGSBASE 0xc0000102 /* swapgs swaps this with gsbase */
#define MSR_AMD_TSCAUX 0xc0000103 /* %ecx value on rdtscp insn */
+
+/* AMD's SVM MSRs */
+
+#define MSR_AMD_VM_CR 0xc0010114 /* SVM global control */
+#define MSR_AMD_VM_HSAVE_PA 0xc0010117 /* SVM host save area address */
+
+#define AMD_VM_CR_DPD (1 << 0)
+#define AMD_VM_CR_R_INIT (1 << 1)
+#define AMD_VM_CR_DIS_A20M (1 << 2)
+#define AMD_VM_CR_LOCK (1 << 3)
+#define AMD_VM_CR_SVMDIS (1 << 4)
+
/* AMD's configuration MSRs, weakly documented in the revision guide */
#define MSR_AMD_DC_CFG 0xc0011022
diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h
index 943bdd8203..59a974dfd2 100644
--- a/usr/src/uts/intel/sys/x86_archext.h
+++ b/usr/src/uts/intel/sys/x86_archext.h
@@ -210,6 +210,18 @@ extern "C" {
#define CPUID_AMD_EBX_SSB_NO 0x004000000 /* AMD: SSB Fixed */
/*
+ * AMD SVM features (extended function 0x8000000A).
+ */
+#define CPUID_AMD_EDX_NESTED_PAGING 0x000000001 /* AMD: SVM NP */
+#define CPUID_AMD_EDX_LBR_VIRT 0x000000002 /* AMD: LBR virt. */
+#define CPUID_AMD_EDX_SVML 0x000000004 /* AMD: SVM lock */
+#define CPUID_AMD_EDX_NRIPS 0x000000008 /* AMD: NRIP save */
+#define CPUID_AMD_EDX_TSC_RATE_MSR 0x000000010 /* AMD: MSR TSC ctrl */
+#define CPUID_AMD_EDX_VMCB_CLEAN 0x000000020 /* AMD: VMCB clean bits */
+#define CPUID_AMD_EDX_FLUSH_ASID 0x000000040 /* AMD: flush by ASID */
+#define CPUID_AMD_EDX_DECODE_ASSISTS 0x000000080 /* AMD: decode assists */
+
+/*
* Intel now seems to have claimed part of the "extended" function
* space that we previously for non-Intel implementors to use.
* More excitingly still, they've claimed bit 20 to mean LAHF/SAHF
diff --git a/usr/src/uts/sparc/ip/ip.global-objs.debug64 b/usr/src/uts/sparc/ip/ip.global-objs.debug64
index d189c7a47c..691b7da537 100644
--- a/usr/src/uts/sparc/ip/ip.global-objs.debug64
+++ b/usr/src/uts/sparc/ip/ip.global-objs.debug64
@@ -21,7 +21,7 @@
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2011 Nexenta Systems, Inc. All rights reserved
-# Copyright 2017 Joyent, Inc.
+# Copyright 2019 Joyent, Inc. All rights reserved
#
arp_m_tbl
@@ -119,11 +119,13 @@ ip_g_all_ones
ip_helper_stream_info
ip_helper_stream_rinit
ip_helper_stream_winit
+ip_ill_mcast_reclaim
ip_ioctl_ftbl
ip_loopback_mtu_v6plus
ip_loopback_mtuplus
ip_m_tbl
ip_max_frag_dups
+ip_max_ill_mcast_nces
ip_min_frag_prune_time
ip_minor_arena_la
ip_minor_arena_sa
diff --git a/usr/src/uts/sparc/ip/ip.global-objs.obj64 b/usr/src/uts/sparc/ip/ip.global-objs.obj64
index e2b81e66a0..624f9984f0 100644
--- a/usr/src/uts/sparc/ip/ip.global-objs.obj64
+++ b/usr/src/uts/sparc/ip/ip.global-objs.obj64
@@ -21,7 +21,7 @@
#
# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2011 Nexenta Systems, Inc. All rights reserved
-# Copyright 2017 Joyent, Inc.
+# Copyright 2019 Joyent, Inc. All rights reserved
#
arp_m_tbl
@@ -119,11 +119,13 @@ ip_g_all_ones
ip_helper_stream_info
ip_helper_stream_rinit
ip_helper_stream_winit
+ip_ill_mcast_reclaim
ip_ioctl_ftbl
ip_loopback_mtu_v6plus
ip_loopback_mtuplus
ip_m_tbl
ip_max_frag_dups
+ip_max_ill_mcast_nces
ip_min_frag_prune_time
ip_minor_arena_la
ip_minor_arena_sa
diff --git a/usr/src/uts/sparc/nsmb/ioc_check.ref b/usr/src/uts/sparc/nsmb/ioc_check.ref
index 9d670f24c3..7476bc696d 100644
--- a/usr/src/uts/sparc/nsmb/ioc_check.ref
+++ b/usr/src/uts/sparc/nsmb/ioc_check.ref
@@ -3,10 +3,12 @@
#define ID_DOMAIN_INCR 0x1
#define ID_USER 0x120
#define ID_USER_INCR 0x1
-#define SSN_VOPT 0x0
-#define SSN_OWNER 0x4
-#define SSN_ID 0x8
-#define SSN_SRVNAME 0x228
+#define SSN_OWNER 0x0
+#define SSN_VOPT 0x4
+#define SSN_MINVER 0x8
+#define SSN_MAXVER 0xa
+#define SSN_ID 0xc
+#define SSN_SRVNAME 0x22c
#define SSN_SRVNAME_INCR 0x1
#define SH_USE 0x0
#define SH_TYPE 0x4
@@ -17,70 +19,27 @@
#define TC_FLAGS 0x0
#define TC_OPT 0x4
#define TC_SH 0x8
-#define SV_PROTO 0x0
-#define SV_SM 0x2
-#define SV_TZ 0x4
-#define SV_MAXMUX 0x6
-#define SV_MAXVCS 0x8
-#define SV_RAWMODE 0xa
-#define SV_MAXTX 0xc
-#define SV_MAXRAW 0x10
-#define SV_SKEY 0x14
-#define SV_CAPS 0x18
-#define IS_TRAN_FD 0x0
-#define IS_VCFLAGS 0x4
-#define IS_HFLAGS 0x8
-#define IS_HFLAGS2 0xa
-#define IS_SMBUID 0xc
-#define IS_NEXT_MID 0xe
-#define IS_TXMAX 0x10
-#define IS_RWMAX 0x14
-#define IS_RXMAX 0x18
-#define IS_WXMAX 0x1c
-#define IS_SSN_KEY 0x20
-#define IS_SSN_KEY_INCR 0x1
-#define IS_NEXT_SEQ 0x30
-#define IS_U_MACLEN 0x34
-#define IS_U_MACKEY 0x38
-#define WK_IODS 0x0
-#define WK_SOPT 0x40
-#define WK_OUT_STATE 0x5c
-#define SIZEOF_SMBIOC_RQ 0x20
-#define IOC_CMD 0x0
-#define IOC_RQ_ERRCLASS 0x1
-#define IOC_RQ_SERROR 0x2
-#define IOC_RQ_ERROR 0x4
-#define IOC_TBUFSZ 0x8
-#define IOC_RBUFSZ 0xc
-#define _IOC_TBUF 0x10
-#define _IOC_RBUF 0x18
-#define SIZEOF_SMBIOC_T2RQ 0xc0
-#define IOC_SETUP 0x0
-#define IOC_SETUP_INCR 0x2
-#define IOC_SETUPCNT 0x8
-#define IOC_T2_NAME 0xc
-#define IOC_T2_NAME_INCR 0x1
-#define IOC_TPARAMCNT 0x8c
-#define IOC_TDATACNT 0x8e
-#define IOC_RPARAMCNT 0x90
-#define IOC_RDATACNT 0x92
-#define IOC_T2_ERRCLASS 0x95
-#define IOC_T2_SERROR 0x96
-#define IOC_T2_ERROR 0x98
-#define IOC_RPFLAGS2 0x9c
-#define _IOC_TPARAM 0xa0
-#define _IOC_TDATA 0xa8
-#define _IOC_RPARAM 0xb0
-#define _IOC_RDATA 0xb8
-#define SIZEOF_SMBIOC_FLAGS 0xc
-#define IOC_LEVEL 0x0
-#define IOC_MASK 0x8
-#define IOC_FLAGS 0x4
+#define WK_OUT_STATE 0x0
+#define WK_U_SSNKEY_LEN 0x4
+#define WK_U_SSNKEY_BUF 0x8
+#define WK_U_AUTH_RLEN 0x10
+#define WK_U_AUTH_WLEN 0x14
+#define WK_U_AUTH_RBUF 0x18
+#define WK_U_AUTH_WBUF 0x20
+#define WK_CL_GUID 0x28
+#define WK_CL_GUID_INCR 0x1
#define SIZEOF_SMBIOC_RW 0x18
-#define IOC_FH 0x0
-#define IOC_CNT 0x4
+#define IOC_CNT 0x0
+#define IOC_FLAGS 0x4
#define _IOC_OFFSET 0x8
#define _IOC_BASE 0x10
+#define SIZEOF_SMBIOC_XNP 0x20
+#define IOC_TDLEN 0x0
+#define IOC_RDLEN 0x4
+#define IOC_MORE 0x8
+#define IOC_PAD1 0xc
+#define _IOC_TDATA 0x10
+#define _IOC_RDATA 0x18
#define SIZEOF_NTCREATE 0x114
#define IOC_REQ_ACC 0x0
#define IOC_EFATTR 0x4