diff options
author | Dan McDonald <danmcd@mnx.io> | 2022-09-15 11:19:27 -0400 |
---|---|---|
committer | Dan McDonald <danmcd@mnx.io> | 2022-09-15 11:19:27 -0400 |
commit | db0cb290d073dbba1632b614bc34fd2f446379fd (patch) | |
tree | b5a33effb2617c6cee46f8bdcc69f5a5ac188dd8 /usr/src | |
parent | 9408eb512c875e72c3e2903446e2da2c2ce74386 (diff) | |
parent | 8bcd8eea9270aef5b19ce4303b2a7f4f0bc6bbba (diff) | |
download | illumos-joyent-db0cb290d073dbba1632b614bc34fd2f446379fd.tar.gz |
[illumos-gate merge]
commit 8bcd8eea9270aef5b19ce4303b2a7f4f0bc6bbba
14967 dladm create-overlay fails with IPs that end in the range 224-239
commit aff6a0f8b30f58d0b494eb98f8f3e01983acecc4
14949 Convert find_elf(1ONBLD) to mandoc
commit 1baeef3013bd4a2bff922e272ea7cd6da5a99908
14868 SMB reconnect fails when previous session still disconnecting
commit 36afce5d646a7506053384370adfe4c6ac1a6047
14847 illumos should default to python 3.9
commit 0ae0ab6f6ac7a567d495b1daad2f6e229d097a21
14944 xhci silently drops ugen transfers sometimes but not always
commit 525641e8e46b2b8beffe3f067f910178ffa06377
14867 panic in smb_request_alloc / smb_oplock_ind_break during shutdown
Diffstat (limited to 'usr/src')
28 files changed, 817 insertions, 320 deletions
diff --git a/usr/src/Makefile.master b/usr/src/Makefile.master index 3ed49bc303..071e5dcab1 100644 --- a/usr/src/Makefile.master +++ b/usr/src/Makefile.master @@ -210,16 +210,16 @@ $(SPARC_BLD)PERL_MACH= sun4 PERL_VARIANT= PERL_ARCH= $(PERL_MACH)-solaris$(PERL_VARIANT)-64int PERL_ARCH64= $(PERL_MACH)-solaris$(PERL_VARIANT)-64 -PYTHON3_VERSION= 3.5 -PYTHON3_PKGVERS= -35 -PYTHON3_SUFFIX= m +PYTHON3_VERSION= 3.9 +PYTHON3_PKGVERS= -39 +PYTHON3_SUFFIX= PYTHON3= /usr/bin/python$(PYTHON3_VERSION) # BUILDPY3b should be overridden in the env file in order to build python # modules with a secondary python to aid migration between versions. BUILDPY3b= $(POUND_SIGN) -PYTHON3b_VERSION= 3.9 -PYTHON3b_PKGVERS= -39 -PYTHON3b_SUFFIX= +PYTHON3b_VERSION= 3.5 +PYTHON3b_PKGVERS= -35 +PYTHON3b_SUFFIX= m # $(BUILDPY3b)PYTHON3b= /usr/bin/python$(PYTHON3b_VERSION) TOOLS_PYTHON= $(PYTHON3) diff --git a/usr/src/tools/env/illumos.sh b/usr/src/tools/env/illumos.sh index 30148be6ef..25e897154f 100644 --- a/usr/src/tools/env/illumos.sh +++ b/usr/src/tools/env/illumos.sh @@ -19,8 +19,8 @@ # CDDL HEADER END # # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2015 Nexenta Systems, Inc. All rights reserved. # Copyright 2012 Joshua M. Clulow <josh@sysmgr.org> +# Copyright 2015 Nexenta Systems, Inc. All rights reserved. # Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2016 RackTop Systems. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. @@ -106,9 +106,9 @@ export ENABLE_SMB_PRINTING= # If your distro uses certain versions of Python, make sure either # Makefile.master contains your new defaults OR your .env file sets them. -#export PYTHON3_VERSION=3.5 -#export PYTHON3_PKGVERS=-35 -#export PYTHON3_SUFFIX=m +#export PYTHON3_VERSION=3.9 +#export PYTHON3_PKGVERS=-39 +#export PYTHON3_SUFFIX= # Set console color scheme either by build type: # diff --git a/usr/src/tools/find_elf/find_elf.1onbld b/usr/src/tools/find_elf/find_elf.1onbld index 8fe9b7713b..0f9eacad5e 100644 --- a/usr/src/tools/find_elf/find_elf.1onbld +++ b/usr/src/tools/find_elf/find_elf.1onbld @@ -21,124 +21,159 @@ .\" .\" Copyright 2022 Jason King .\" -.TH FIND_ELF 1ONBLD "May 29, 2022" -.SH NAME -find_elf \- Locate ELF objects -.SH SYNOPSIS -\fBfind_elf [-afhnrs] path\fP -.SH DESCRIPTION +.Dd September 6, 2022 +.Dt FIND_ELF 1ONBLD +.Os +.Sh NAME +.Nm find_elf +.Nd Locate ELF objects +.Sh SYNOPSIS +.Nm +.Op Fl afhnrs +.Ar path +.Sh DESCRIPTION The -.I find_elf +.Nm command descends a directory hierarchy and produces one line of output on stdout for each ELF object found. -.SH OPTIONS +.Sh OPTIONS The following options are supported: -.TP 4 -.B \-a -Disable alias processing. Symbolic links are treated as independent -files, each such link results in a separate OBJECT output line, -and ALIAS lines are not issued. -.TP 4 -.B \-f -Fast Mode. When reading directories, the file name and modes are +.Bl -tag -width Fl +.It Fl a +Disable alias processing. +Symbolic links are treated as independent +files, each such link results in a separate +.Sy OBJECT +output line, and +.Sy ALIAS +lines are not issued. +.It Fl f +Fast Mode. +When reading directories, the file name and modes are used to eliminate files from consideration and speed up the search: -Directories with names that start with a '.' character are skipped. +Directories with names that start with a +.Ql \&. +character are skipped. Executables must have the execute bit set, and -shared objects must end with a .so extension. Files that do not -meet these requirements are silently eliminated from consideration without -further analysis. -.TP 4 -.B \-h +shared objects must end with a +.Ql .so +extension. +Files that do not meet these requirements are silently eliminated from +consideration without further analysis. +.It Fl h Show usage message. -.TP 4 -.B \-n -Do not treat well known hard-linked binaries as special. Certain well known -binaries (currently \fBalias\fP and \fBisaexec\fP) are hard linked to many -other names in a proto directory tree. -.P +.It Fl n +Do not treat well known hard-linked binaries as special. +Certain well known binaries +.Po +currently +.Pa alias +and +.Pa isaexec +.Pc +are hard linked to many other names in a proto directory tree. +.Pp By default, -.I find_elf +.Nm will use these well known names as the initial name and all other hard links -to those binaries are treated as aliases. Disabling this behavior with the -\fB-n\fR option will choose the first name encountered during directory -traversal as the name, and all other hard links to the binary as aliases. -.TP 4 -.B \-r +to those binaries are treated as aliases. +Disabling this behavior with the +.Fl n +option will choose the first name encountered during directory traversal as +the name, and all other hard links to the binary as aliases. +.It Fl r Report file names as relative paths, relative to the given file or directory, instead of fully qualified. -.TP 4 -.B \-s +.It Fl s Only report shared objects. -.SH OUTPUT -.I find_elf -produces a series of PREFIX, OBJECT, and ALIAS lines, which collectively -describe the ELF objects located. Whitespace is used within each +.El +.Sh OUTPUT +.Nm +produces a series of +.Sy PREFIX , +.Sy OBJECT , +and +.Sy ALIAS +lines, which collectively describe the ELF objects located. +Whitespace is used within each line to delimit the various fields of information provided. -.P -If the \fB-r\fP option is used to specify that file names be reported -as relative paths, a PREFIX line is output to provide the base path from +.Pp +If the +.Fl r +option is used to specify that file names be reported +as relative paths, a +.Sy PREFIX +line is output to provide the base path from which the relative names should be interpreted. -There can only be one PREFIX line, and it is output first, before any -OBJECT or ALIAS lines. -.sp -.in +4 -.nf +There can only be one +.Sy PREFIX +line, and it is output first, before any +.Sy OBJECT +or +.Sy ALIAS +lines. +.Bd -literal -offset indent PREFIX path -.fi -.in -4 -.sp -For each object found, an OBJECT line is produced to describe it: -.sp -.in +4 -.nf +.Ed +.Pp +For each object found, an +.Sy OBJECT +line is produced to describe it: +.Bd -literal -offset indent OBJECT [32 | 64] [DYN | EXEC | REL] [VERDEF | NOVERDEF] object-path -.fi -.in -4 -.sp +.Ed +.Pp The first field provides the ELF class of the object, and will be either 32 or 64. The second field provides the type of object, either -a shared object (DYN), an executable (EXEC), or a relocatable object (REL). -The third field will be VERDEF if the object contains ELF -version definitions, and NOVERDEF if the object is not versioned. +a shared object +.Ql DYN , +an executable +.Ql EXEC , +or a relocatable object +.Ql REL . +The third field will be +.Ql VERDEF +if the object contains ELF version definitions, and +.Ql NOVERDEF +if the object is not versioned. The final field gives the path to the object. -.P -Under Unix, a file can have multiple names. In the context of ELF -objects, this often happens for one of two reasons: -.RS +4 -.TP -.ie t \(bu -.el o +.Pp +Under Unix, a file can have multiple names. +In the context of ELF objects, this often happens for one of two reasons: +.Bl -bullet -offset indent +.It Compilation symlinks, used to provide a non-versioned name for a shared object. -.RE -.RS +4 -.TP -.ie t \(bu -.el o -Symlinks such as '32' and '64' used to provide alternative -non-machine specific paths to objects. -.RE -.sp +.It +Symlinks such as +.Ql 32 +and +.Ql 64 +used to provide alternative non-machine specific paths to objects. +.El +.Pp When -.I find_elf -identifies an object via such an aliased name, it issues an ALIAS line -mapping it to the main name for the object: -.sp -.in +4 -.nf +.Nm +identifies an object via such an aliased name, it issues an +.Sy ALIAS +line mapping it to the main name for the object: +.Bd -literal -offset indent ALIAS object-path alias-path -.fi -.in -4 -.sp -The \fB-a\fP option alters the handling of aliased names. When \fB-a\fP is -specified, each file results in a separate OBJECT line, as if they were +.Ed +.Pp +The +.Fl a +option alters the handling of aliased names. +When +.Fl a +is specified, each file results in a separate +.Sy OBJECT +line, as if they were independent files rather than the same file with different names. -.sp -.SH EXAMPLES -Assume the following hierarchy of files exist under /usr/lib/foo: -.sp -.in +4 -.nf +.Sh EXAMPLES +Assume the following hierarchy of files exist under +.Pa /usr/lib/foo : +.Bd -literal -offset indent % /bin/ls -alRF /usr/lib/foo /usr/lib/foo: total 111 @@ -156,17 +191,22 @@ drwxr-xr-x 2 root root 4 Jul 16 17:35 ./ drwxr-xr-x 3 root root 7 Jul 16 17:35 ../ lrwxrwxrwx 1 root bin 11 Jul 16 17:35 libfoo.so -> libfoo.so.1* -rwxr-xr-x 1 root bin 72536 Jul 16 17:35 libfoo.so.1* -.fi -.in -4 -.sp -This hierarchy contains compilation symlinks (libfoo.so) and -path alias symlinks (32, 64), as discussed in OUTPUT. -.P -.I find_elf +.Ed +.Pp +This hierarchy contains compilation symlinks +.Po +.Pa libfoo.so +.Pc +and path alias symlinks +.Po +32, 64 +.Pc , +as discussed in +.Sx OUTPUT . +.Pp +.Nm produces the following output for the above hierarchy: -.sp -.in +4 -.nf +.Bd -literal -offset indent % find_elf -r /usr/lib/foo PREFIX /usr/lib/foo OBJECT 64 DYN VERDEF amd64/libfoo.so.1 @@ -177,14 +217,12 @@ OBJECT 32 DYN VERDEF libfoo.so.1 ALIAS libfoo.so.1 32/libfoo.so ALIAS libfoo.so.1 32/libfoo.so.1 ALIAS libfoo.so.1 libfoo.so -.fi -.in -4 -.sp -Contrast this with the output when \fB-a\fP is used to treat -each name as an independent file: -.sp -.in +4 -.nf +.Ed +.Pp +Contrast this with the output when +.Fl a +is used to treat each name as an independent file: +.Bd -literal -offset indent % find_elf -ar /usr/lib/foo PREFIX /usr/lib/foo OBJECT 32 DYN VERDEF 32/libfoo.so @@ -195,40 +233,32 @@ OBJECT 64 DYN VERDEF amd64/libfoo.so.1 OBJECT 64 DYN VERDEF amd64/libfoo.so OBJECT 32 DYN VERDEF libfoo.so.1 OBJECT 32 DYN VERDEF libfoo.so -.fi -.in -4 -.sp +.Ed +.Pp When -.I find_elf +.Nm is used to process an alias for which no target object is given, -there will be no output. For example, using /lib/libc.so, which -is a compilation symlink for /lib/libc.so.1: -.sp -.in +4 -.nf +there will be no output. +For example, using +.Pa /lib/libc.so , +which is a compilation symlink for +.Pa /lib/libc.so.1 : +.Bd -literal -offset indent % find_elf /lib/libc.so -.fi -.in -4 -.sp -In such situations, the \fB-a\fP option can be used to produce -the desired output: -.sp -.in +4 -.nf +.Ed +.Pp +In such situations, the +.Fl a +option can be used to produce the desired output: +.Bd -literal -offset indent % find_elf -a /lib/libc.so OBJECT 32 DYN VERDEF /lib/libc.so -.fi -.in -4 -.sp -.PP -.RS -.nf -.SH SEE ALSO -.BR check_rtime (1ONBLD), -.BR interface_check (1ONBLD), -.BR interface_cmp (1ONBLD), -.BR ld (1), -.BR ldd (1), -.BR elfdump (1), -.BR pvs (1). - +.Ed +.Sh SEE ALSO +.Xr elfdump 1 , +.Xr ld 1 , +.Xr ldd 1 , +.Xr pvs 1 , +.Xr check_rtime 1ONBLD , +.Xr interface_check 1ONBLD , +.Xr interface_cmp 1ONBLD diff --git a/usr/src/uts/common/fs/smbsrv/smb2_cancel.c b/usr/src/uts/common/fs/smbsrv/smb2_cancel.c index 1116a432f7..df97015aac 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_cancel.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_cancel.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. */ /* @@ -96,8 +96,8 @@ smb2_cancel_sync(smb_request_t *sr) struct smb_session *session = sr->session; int cnt = 0; - if (sr->smb2_messageid == 0) - goto failure; + if (sr->smb2_messageid == 0 || sr->smb2_messageid == UINT64_MAX) + return; smb_slist_enter(&session->s_req_list); for (req = smb_slist_head(&session->s_req_list); req != NULL; @@ -117,7 +117,6 @@ smb2_cancel_sync(smb_request_t *sr) smb_slist_exit(&session->s_req_list); if (cnt != 1) { - failure: DTRACE_PROBE2(smb2__cancel__error, uint64_t, sr->smb2_messageid, int, cnt); #ifdef DEBUG @@ -148,6 +147,9 @@ smb2_cancel_async(smb_request_t *sr) struct smb_session *session = sr->session; int cnt = 0; + if (sr->smb2_async_id == 0) + return; + smb_slist_enter(&session->s_req_list); req = smb_slist_head(&session->s_req_list); while (req) { diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c index fe748bbd62..6a9040a5db 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c @@ -308,6 +308,8 @@ smb2_fsctl_odx_read(smb_request_t *sr, smb_fsctl_t *fsctl) */ data = in_file_off; tok_type = STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1; + if (sr->sr_state != SMB_REQ_STATE_ACTIVE) + return (NT_STATUS_SUCCESS); rc = smb_fsop_next_alloc_range(ofile->f_cr, ofile->f_node, &data, &hole); switch (rc) { diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c index 90bb254670..91f13a150e 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_sparse.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. */ /* @@ -306,6 +306,9 @@ smb2_sparse_copy( while (*residp > 0) { + if (sr->sr_state != SMB_REQ_STATE_ACTIVE) + break; + data = src_off; rc = smb_fsop_next_alloc_range(src_ofile->f_cr, src_ofile->f_node, &data, &hole); diff --git a/usr/src/uts/common/fs/smbsrv/smb2_lease.c b/usr/src/uts/common/fs/smbsrv/smb2_lease.c index 7b7247fad8..b8bed20f91 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_lease.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_lease.c @@ -365,7 +365,7 @@ smb2_lease_break_ack(smb_request_t *sr) status = smb_oplock_ack_break(sr, ofile, &LeaseState); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(ofile->f_node, 0); + (void) smb_oplock_wait_break(sr, ofile->f_node, 0); status = NT_STATUS_SUCCESS; } @@ -641,7 +641,7 @@ done: */ if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(ofile->f_node, 0); + (void) smb_oplock_wait_break(sr, ofile->f_node, 0); status = NT_STATUS_SUCCESS; } ASSERT(status == NT_STATUS_SUCCESS); diff --git a/usr/src/uts/common/fs/smbsrv/smb2_oplock.c b/usr/src/uts/common/fs/smbsrv/smb2_oplock.c index f3f96c2b21..f8317b2e81 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_oplock.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_oplock.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2019 RackTop Systems. */ @@ -131,7 +131,7 @@ smb2_oplock_break_ack(smb_request_t *sr) status = smb2sr_go_async(sr); if (status != 0) goto errout; - (void) smb_oplock_wait_break(ofile->f_node, 0); + (void) smb_oplock_wait_break(sr, ofile->f_node, 0); status = 0; } if (status != 0) { @@ -320,7 +320,7 @@ smb2_oplock_acquire(smb_request_t *sr) */ if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(ofile->f_node, 0); + (void) smb_oplock_wait_break(sr, ofile->f_node, 0); status = 0; } diff --git a/usr/src/uts/common/fs/smbsrv/smb_cmn_rename.c b/usr/src/uts/common/fs/smbsrv/smb_cmn_rename.c index 098e203fe0..578d01aa07 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_cmn_rename.c +++ b/usr/src/uts/common/fs/smbsrv/smb_cmn_rename.c @@ -20,7 +20,8 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2013-2020 Tintri by DDN, Inc. All rights reserved. + * Copyright 2019 RackTop Systems. */ #include <sys/synch.h> @@ -253,7 +254,7 @@ smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(dst_fnode, 0); + (void) smb_oplock_wait_break(sr, dst_fnode, 0); status = 0; } if (status != 0) { @@ -610,7 +611,7 @@ smb_rename_check_src(smb_request_t *sr, smb_fqi_t *src_fqi) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(src_node, 0); + (void) smb_oplock_wait_break(sr, src_node, 0); status = 0; } @@ -634,7 +635,7 @@ smb_rename_check_src(smb_request_t *sr, smb_fqi_t *src_fqi) ASSERT(sr->session->dialect < SMB_VERS_2_BASE); status = smb_oplock_break_DELETE(src_node, NULL); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { - (void) smb_oplock_wait_break(src_node, 0); + (void) smb_oplock_wait_break(sr, src_node, 0); } /* @@ -651,7 +652,7 @@ smb_rename_check_src(smb_request_t *sr, smb_fqi_t *src_fqi) status = smb_oplock_break_SETINFO(src_node, NULL, FileRenameInformation); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { - (void) smb_oplock_wait_break(src_node, 0); + (void) smb_oplock_wait_break(sr, src_node, 0); } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb_cmn_setfile.c b/usr/src/uts/common/fs/smbsrv/smb_cmn_setfile.c index 53ff9b3cf6..304eb93a39 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_cmn_setfile.c +++ b/usr/src/uts/common/fs/smbsrv/smb_cmn_setfile.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. */ /* @@ -122,7 +122,7 @@ smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *si) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(node, 0); + (void) smb_oplock_wait_break(sr, node, 0); status = 0; } if (status != 0) @@ -164,7 +164,7 @@ smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *si) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(node, 0); + (void) smb_oplock_wait_break(sr, node, 0); status = 0; } if (status != 0) @@ -245,7 +245,7 @@ smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *si) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(node, 0); + (void) smb_oplock_wait_break(sr, node, 0); status = 0; } if (status != 0) diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c index fb4d46f599..59c892ee88 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c +++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c @@ -715,8 +715,7 @@ smb_common_open(smb_request_t *sr) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(fnode, 0); - status = 0; + status = smb_oplock_wait_break(sr, fnode, 0); } if (status != NT_STATUS_SUCCESS) goto errout; @@ -751,8 +750,7 @@ smb_common_open(smb_request_t *sr) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(fnode, 0); - status = 0; + status = smb_oplock_wait_break(sr, fnode, 0); } else { /* * Even when the oplock layer does NOT @@ -820,8 +818,7 @@ smb_common_open(smb_request_t *sr) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(fnode, 0); - status = 0; + status = smb_oplock_wait_break(sr, fnode, 0); } if (status != NT_STATUS_SUCCESS) goto errout; diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c index f0159fc971..53ff4600c2 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_delete.c +++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. */ #include <sys/sunddi.h> @@ -486,7 +486,7 @@ smb_delete_remove_file(smb_request_t *sr, smb_error_t *err) */ status = smb_oplock_break_DELETE(node, NULL); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { - (void) smb_oplock_wait_break(node, 0); + (void) smb_oplock_wait_break(sr, node, 0); status = 0; } if (status != 0) { diff --git a/usr/src/uts/common/fs/smbsrv/smb_fem.c b/usr/src/uts/common/fs/smbsrv/smb_fem.c index b68466edaa..4204830afd 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_fem.c +++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c @@ -659,7 +659,7 @@ smb_fem_oplock_wait(smb_node_t *node, caller_context_t *ct) ct->cc_flags |= CC_WOULDBLOCK; rc = EAGAIN; } else { - (void) smb_oplock_wait_break(node, + (void) smb_oplock_wait_break_fem(node, smb_fem_oplock_timeout); rc = 0; } diff --git a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c index 8028cfe8c9..b58d3f9f0f 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c +++ b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. */ /* @@ -295,7 +295,7 @@ smb_com_locking_andx(smb_request_t *sr) NewLevel = OPLOCK_LEVEL_TWO; status = smb_oplock_ack_break(sr, ofile, &NewLevel); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { - (void) smb_oplock_wait_break(ofile->f_node, 0); + (void) smb_oplock_wait_break(sr, ofile->f_node, 0); status = 0; } if (unlock_num == 0 && lock_num == 0) diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c index 70c546228c..d3f2bad47c 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c +++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c @@ -20,9 +20,9 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011-2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2016 Syneto S.R.L. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. - * Copyright 2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2021 RackTop Systems, Inc. */ @@ -798,6 +798,22 @@ smb_ofile_hold(smb_ofile_t *of) } /* + * Void arg variant of smb_ofile_release for use with smb_llist_post. + * This is needed because smb_ofile_release may need to enter the + * smb_llist as writer when it drops the last reference, so when + * we're in the llist as reader, use smb_llist_post with this + * function to arrange for the release call at llist_exit. + */ +void +smb_ofile_release_LL(void *arg) +{ + smb_ofile_t *of = arg; + + SMB_OFILE_VALID(of); + smb_ofile_release(of); +} + +/* * Release a reference on a file. If the reference count falls to * zero and the file has been closed, post the object for deletion. * Object deletion is deferred to avoid modifying a list while an @@ -1772,7 +1788,7 @@ smb_ofile_set_delete_on_close(smb_request_t *sr, smb_ofile_t *of) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { if (sr->session->dialect >= SMB_VERS_2_BASE) (void) smb2sr_go_async(sr); - (void) smb_oplock_wait_break(of->f_node, 0); + (void) smb_oplock_wait_break(sr, of->f_node, 0); } mutex_enter(&of->f_mutex); diff --git a/usr/src/uts/common/fs/smbsrv/smb_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_oplock.c index 7be36ebf42..5215da8693 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c +++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. */ /* @@ -110,7 +110,7 @@ smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok) * status code that says we should wait. */ if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { - (void) smb_oplock_wait_break(ofile->f_node, 0); + (void) smb_oplock_wait_break(sr, ofile->f_node, 0); status = 0; } diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c index 5988f121eb..af568986c9 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_server.c +++ b/usr/src/uts/common/fs/smbsrv/smb_server.c @@ -1532,6 +1532,7 @@ smb_server_shutdown(smb_server_t *sv) sv->sv_rootuser = NULL; } if (sv->sv_session != NULL) { + smb_session_cancel_requests(sv->sv_session, NULL, NULL); smb_slist_wait_for_empty(&sv->sv_session->s_req_list); /* Just in case import left users and trees */ @@ -2013,6 +2014,10 @@ smb_server_fclose(smb_server_t *sv, uint32_t uniqid) * so it can force a logoff that we haven't noticed yet. * This is not called frequently, so we just walk the list of * connections searching for the user. + * + * Note that this must wait for any durable handles (ofiles) + * owned by this user to become "orphaned", so that a reconnect + * that may immediately follow can find and use such ofiles. */ void smb_server_logoff_ssnid(smb_request_t *sr, uint64_t ssnid) @@ -2020,6 +2025,9 @@ smb_server_logoff_ssnid(smb_request_t *sr, uint64_t ssnid) smb_server_t *sv = sr->sr_server; smb_llist_t *sess_list; smb_session_t *sess; + smb_user_t *user = NULL; + + SMB_SERVER_VALID(sv); if (sv->sv_state != SMB_SERVER_STATE_RUNNING) return; @@ -2031,38 +2039,77 @@ smb_server_logoff_ssnid(smb_request_t *sr, uint64_t ssnid) sess != NULL; sess = smb_llist_next(sess_list, sess)) { - smb_user_t *user; - SMB_SESSION_VALID(sess); if (sess->dialect < SMB_VERS_2_BASE) continue; - if (sess->s_state != SMB_SESSION_STATE_NEGOTIATED) + switch (sess->s_state) { + case SMB_SESSION_STATE_NEGOTIATED: + case SMB_SESSION_STATE_TERMINATED: + case SMB_SESSION_STATE_DISCONNECTED: + break; + default: continue; + } - user = smb_session_lookup_ssnid(sess, ssnid); - if (user == NULL) - continue; + /* + * Normal situation is to find a LOGGED_ON user. + */ + user = smb_session_lookup_uid_st(sess, ssnid, 0, + SMB_USER_STATE_LOGGED_ON); + if (user != NULL) { + + if (smb_is_same_user(user->u_cred, sr->user_cr)) { + /* Treat this as if we lost the connection */ + user->preserve_opens = SMB2_DH_PRESERVE_SOME; + smb_user_logoff(user); + break; + } + smb_user_release(user); + user = NULL; + } - if (!smb_is_same_user(user->u_cred, sr->user_cr)) { + /* + * If we raced with disconnect, may find LOGGING_OFF, + * in which case we want to just wait for it. + */ + user = smb_session_lookup_uid_st(sess, ssnid, 0, + SMB_USER_STATE_LOGGING_OFF); + if (user != NULL) { + if (smb_is_same_user(user->u_cred, sr->user_cr)) + break; smb_user_release(user); - continue; + user = NULL; } + } - /* Treat this as if we lost the connection */ - user->preserve_opens = SMB2_DH_PRESERVE_SOME; - smb_user_logoff(user); - smb_user_release(user); + smb_llist_exit(sess_list); + if (user != NULL) { /* - * The above may have left work on the delete queues + * Wait for durable handles to be orphaned. + * Note: not holding the sess list rwlock. */ + smb_user_wait_trees(user); + + /* + * Could be doing the last release on a user below, + * which can leave work on the delete queues for + * s_user_list or s_tree_list so flush those. + * Must hold the session list after the user release + * so that the session can't go away while we flush. + */ + smb_llist_enter(sess_list, RW_READER); + + sess = user->u_session; + smb_user_release(user); + smb_llist_flush(&sess->s_tree_list); smb_llist_flush(&sess->s_user_list); - } - smb_llist_exit(sess_list); + smb_llist_exit(sess_list); + } } /* See also: libsmb smb_kmod_setcfg */ diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c index 6739fee326..89ab25ae02 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2019 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2020 RackTop Systems, Inc. */ @@ -444,6 +444,7 @@ smb_request_cancel(smb_request_t *sr) case SMB_REQ_STATE_WAITING_FCN1: case SMB_REQ_STATE_WAITING_LOCK: case SMB_REQ_STATE_WAITING_PIPE: + case SMB_REQ_STATE_WAITING_OLBRK: /* * These are states that have a cancel_method. * Make the state change now, to ensure that diff --git a/usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c index 538b57b7ba..e7bf15ff56 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c +++ b/usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c @@ -74,6 +74,7 @@ int smb_oplock_timeout_def = 45000; /* mSec. */ static void smb_oplock_async_break(void *); static void smb_oplock_hdl_clear(smb_ofile_t *); +static void smb_oplock_wait_break_cancel(smb_request_t *sr); /* @@ -237,6 +238,7 @@ smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel, boolean_t AckRequired, uint32_t CompletionStatus) { smb_server_t *sv = ofile->f_server; + smb_node_t *node = ofile->f_node; smb_request_t *sr = NULL; /* @@ -293,6 +295,18 @@ smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel, sr = smb_request_alloc(ofile->f_session, 0); if (sr == NULL) sr = smb_request_alloc(sv->sv_session, 0); + if (sr == NULL) { + /* + * Server must be shutting down. We took a + * hold on the ofile that must be released, + * but we can't release here because we're + * called with the node ofile list entered. + * See smb_ofile_release_LL. + */ + smb_llist_post(&node->n_ofile_list, ofile, + smb_ofile_release_LL); + return; + } sr->sr_state = SMB_REQ_STATE_SUBMITTED; sr->smb2_async = B_TRUE; @@ -512,7 +526,7 @@ smb_oplock_send_brk(smb_request_t *sr) */ #ifdef DEBUG if (smb_oplock_debug_wait > 0) { - status = smb_oplock_wait_break(ofile->f_node, + status = smb_oplock_wait_break(sr, ofile->f_node, smb_oplock_debug_wait); if (status == 0) return; @@ -521,7 +535,7 @@ smb_oplock_send_brk(smb_request_t *sr) debug_enter("oplock_wait"); } #endif - status = smb_oplock_wait_break(ofile->f_node, + status = smb_oplock_wait_break(sr, ofile->f_node, smb_oplock_timeout_ack); if (status == 0) return; @@ -608,7 +622,7 @@ smb_oplock_send_brk(smb_request_t *sr) if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { /* Not expecting this status return. */ cmn_err(CE_NOTE, "clnt local oplock ack wait?"); - (void) smb_oplock_wait_break(ofile->f_node, + (void) smb_oplock_wait_break(sr, ofile->f_node, smb_oplock_timeout_ack); status = 0; } @@ -648,6 +662,24 @@ smb_oplock_hdl_clear(smb_ofile_t *ofile) } /* + * Called by smb_request_cancel() via sr->cancel_method + * Arg is the smb_node_t with the breaking oplock. + */ +static void +smb_oplock_wait_break_cancel(smb_request_t *sr) +{ + smb_node_t *node = sr->cancel_arg2; + smb_oplock_t *ol; + + SMB_NODE_VALID(node); + ol = &node->n_oplock; + + mutex_enter(&ol->ol_mutex); + cv_broadcast(&ol->WaitingOpenCV); + mutex_exit(&ol->ol_mutex); +} + +/* * Wait up to "timeout" mSec. for the current oplock "breaking" flags * to be cleared (by smb_oplock_ack_break or smb_oplock_break_CLOSE). * @@ -663,7 +695,84 @@ smb_oplock_hdl_clear(smb_ofile_t *ofile) * we're about to do something that invalidates some cache. */ uint32_t -smb_oplock_wait_break(smb_node_t *node, int timeout) /* mSec. */ +smb_oplock_wait_break(smb_request_t *sr, smb_node_t *node, int timeout) +{ + smb_oplock_t *ol; + clock_t time, rv; + uint32_t status = 0; + smb_req_state_t srstate; + + SMB_NODE_VALID(node); + ol = &node->n_oplock; + + if (timeout == 0) + timeout = smb_oplock_timeout_def; + time = MSEC_TO_TICK(timeout) + ddi_get_lbolt(); + + mutex_enter(&sr->sr_mutex); + if (sr->sr_state != SMB_REQ_STATE_ACTIVE) { + mutex_exit(&sr->sr_mutex); + return (NT_STATUS_CANCELLED); + } + sr->sr_state = SMB_REQ_STATE_WAITING_OLBRK; + sr->cancel_method = smb_oplock_wait_break_cancel; + sr->cancel_arg2 = node; + mutex_exit(&sr->sr_mutex); + + mutex_enter(&ol->ol_mutex); + while ((ol->ol_state & BREAK_ANY) != 0) { + ol->waiters++; + rv = cv_timedwait(&ol->WaitingOpenCV, + &ol->ol_mutex, time); + ol->waiters--; + if (rv < 0) { + /* cv_timewait timeout */ + status = NT_STATUS_CANNOT_BREAK_OPLOCK; + break; + } + + /* + * Check if we were woken by smb_request_cancel, + * which sets state SMB_REQ_STATE_CANCEL_PENDING + * and signals WaitingOpenCV. + */ + mutex_enter(&sr->sr_mutex); + srstate = sr->sr_state; + mutex_exit(&sr->sr_mutex); + if (srstate != SMB_REQ_STATE_WAITING_OLBRK) { + break; + } + } + + mutex_exit(&ol->ol_mutex); + + mutex_enter(&sr->sr_mutex); + sr->cancel_method = NULL; + sr->cancel_arg2 = NULL; + switch (sr->sr_state) { + case SMB_REQ_STATE_WAITING_OLBRK: + sr->sr_state = SMB_REQ_STATE_ACTIVE; + /* status from above */ + break; + case SMB_REQ_STATE_CANCEL_PENDING: + sr->sr_state = SMB_REQ_STATE_CANCELLED; + status = NT_STATUS_CANCELLED; + break; + default: + status = NT_STATUS_INTERNAL_ERROR; + break; + } + mutex_exit(&sr->sr_mutex); + + return (status); +} + +/* + * Simplified version used in smb_fem.c, like above, + * but no smb_request_cancel stuff. + */ +uint32_t +smb_oplock_wait_break_fem(smb_node_t *node, int timeout) /* mSec. */ { smb_oplock_t *ol; clock_t time, rv; diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c index 45f381ffb1..2aadc3bf38 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_tree.c +++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c @@ -963,6 +963,7 @@ smb_tree_alloc(smb_request_t *sr, const smb_kshare_t *si, /* grab a ref for tree->t_owner */ smb_user_hold_internal(sr->uid_user); + smb_user_inc_trees(sr->uid_user); tree->t_owner = sr->uid_user; /* if FS is readonly, enforce that here */ @@ -1031,6 +1032,7 @@ smb_tree_dealloc(void *arg) smb_idpool_destructor(&tree->t_odid_pool); SMB_USER_VALID(tree->t_owner); + smb_user_dec_trees(tree->t_owner); smb_user_release(tree->t_owner); kmem_cache_free(smb_cache_tree, tree); diff --git a/usr/src/uts/common/fs/smbsrv/smb_user.c b/usr/src/uts/common/fs/smbsrv/smb_user.c index 8934a213eb..a5dc57315f 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_user.c +++ b/usr/src/uts/common/fs/smbsrv/smb_user.c @@ -662,6 +662,55 @@ smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) return (rc); } +/* + * Count references by trees this user owns, + * and allow waiting for them to go away. + */ +void +smb_user_inc_trees(smb_user_t *user) +{ + mutex_enter(&user->u_mutex); + user->u_owned_tree_cnt++; + mutex_exit(&user->u_mutex); +} + +void +smb_user_dec_trees(smb_user_t *user) +{ + mutex_enter(&user->u_mutex); + user->u_owned_tree_cnt--; + if (user->u_owned_tree_cnt == 0) + cv_broadcast(&user->u_owned_tree_cv); + mutex_exit(&user->u_mutex); +} + +int smb_user_wait_tree_tmo = 30; + +/* + * Wait (up to 30 sec.) for trees to go away. + * Should happen in less than a second. + */ +void +smb_user_wait_trees(smb_user_t *user) +{ + clock_t time; + + time = SEC_TO_TICK(smb_user_wait_tree_tmo) + ddi_get_lbolt(); + mutex_enter(&user->u_mutex); + while (user->u_owned_tree_cnt != 0) { + if (cv_timedwait(&user->u_owned_tree_cv, + &user->u_mutex, time) < 0) + break; + } + mutex_exit(&user->u_mutex); +#ifdef DEBUG + if (user->u_owned_tree_cnt != 0) { + cmn_err(CE_NOTE, "smb_user_wait_trees failed"); + debug_enter("smb_user_wait_trees debug"); + } +#endif +} + /* *************************** Static Functions ***************************** */ /* diff --git a/usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c b/usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c index 92144b3985..60ee264050 100644 --- a/usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c +++ b/usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c @@ -11,6 +11,7 @@ /* * Copyright 2018 Joyent, Inc. + * Copyright 2022 MNX Cloud, Inc. */ /* @@ -273,7 +274,7 @@ vxlan_o_setprop(void *arg, const char *pr_name, const void *buf, if (IN6_IS_ADDR_V4MAPPED(ipv6)) { ipaddr_t v4; IN6_V4MAPPED_TO_IPADDR(ipv6, v4); - if (IN_MULTICAST(v4)) + if (IN_MULTICAST(ntohl(v4))) return (EINVAL); } diff --git a/usr/src/uts/common/io/usb/hcd/xhci/xhci.c b/usr/src/uts/common/io/usb/hcd/xhci/xhci.c index a28b1fa0d3..45401aaa1d 100644 --- a/usr/src/uts/common/io/usb/hcd/xhci/xhci.c +++ b/usr/src/uts/common/io/usb/hcd/xhci/xhci.c @@ -11,6 +11,7 @@ /* * Copyright (c) 2019, Joyent, Inc. + * Copyright 2022 Oxide Computer Company */ /* @@ -387,11 +388,23 @@ * * Endpoint management is one of the key parts to the xhci driver as every * endpoint is a pipe that a device driver uses, so they are our primary - * currency. Endpoints are enabled and disabled when the client device drivers - * open and close a pipe. When an endpoint is enabled, we have to fill in an - * endpoint's context structure with information about the endpoint. These - * basically tell the controller important properties which it uses to ensure - * that there is adequate bandwidth for the device. + * currency. An endpoint is enabled when the client device driver opens the + * associated pipe for the first time. When an endpoint is enabled, we have to + * fill in an endpoint's context structure with information about the endpoint. + * These basically tell the controller important properties which it uses to + * ensure that there is adequate bandwidth for the device. + * + * If the client device closes the pipe again we explicitly stop the endpoint, + * moving it to the Halted state, and take ownership of any transfers + * previously submitted to the ring but which have not yet completed. A client + * may open and close a pipe several times -- ugen(4D) in particular is known + * for this -- and we will stop and start the ring accordingly. + * + * It is tempting to fully unconfigure an endpoint when a pipe is closed, but + * some host controllers appear to exhibit undefined behaviour each time the + * endpoint is re-enabled this way; e.g., silently dropped transfers. As such, + * we wait until the whole device is being torn down to disable all previously + * enabled endpoints at once, as part of disabling the device slot. * * Each endpoint has its own ring as described in the previous section. We place * TRBs (transfer request blocks) onto a given ring to request I/O be performed. @@ -701,7 +714,7 @@ * disappearing, we generally attempt to load the xHCI controller before the * EHCI controller. This logic is not done in the driver; however, it is done in * other parts of the kernel like in uts/common/io/consconfig_dacf.c in the - * function consconfig_load_drivres(). + * function consconfig_load_drivers(). * * ----------- * Future Work diff --git a/usr/src/uts/common/io/usb/hcd/xhci/xhci_endpoint.c b/usr/src/uts/common/io/usb/hcd/xhci/xhci_endpoint.c index 560facefcc..fc08238d4b 100644 --- a/usr/src/uts/common/io/usb/hcd/xhci/xhci_endpoint.c +++ b/usr/src/uts/common/io/usb/hcd/xhci/xhci_endpoint.c @@ -12,6 +12,7 @@ /* * Copyright (c) 2018, Joyent, Inc. * Copyright (c) 2019 by Western Digital Corporation + * Copyright 2022 Oxide Computer Company */ /* @@ -63,6 +64,34 @@ xhci_endpoint_pipe_to_epid(usba_pipe_handle_data_t *ph) return (ep); } +void +xhci_endpoint_timeout_cancel(xhci_t *xhcip, xhci_endpoint_t *xep) +{ + xep->xep_state |= XHCI_ENDPOINT_TEARDOWN; + if (xep->xep_timeout != 0) { + mutex_exit(&xhcip->xhci_lock); + (void) untimeout(xep->xep_timeout); + mutex_enter(&xhcip->xhci_lock); + xep->xep_timeout = 0; + } +} + +void +xhci_endpoint_release(xhci_t *xhcip, xhci_endpoint_t *xep) +{ + VERIFY(MUTEX_HELD(&xhcip->xhci_lock)); + VERIFY3U(xep->xep_num, !=, XHCI_DEFAULT_ENDPOINT); + VERIFY(list_is_empty(&xep->xep_transfers)); + + VERIFY(xep->xep_pipe != NULL); + xep->xep_pipe = NULL; + + VERIFY(xep->xep_state & XHCI_ENDPOINT_OPEN); + xep->xep_state &= ~XHCI_ENDPOINT_OPEN; + + xhci_endpoint_timeout_cancel(xhcip, xep); +} + /* * The assumption is that someone calling this owns this endpoint / device and * that it's in a state where it's safe to zero out that information. @@ -75,6 +104,10 @@ xhci_endpoint_fini(xhci_device_t *xd, int endpoint) VERIFY(xep != NULL); xd->xd_endpoints[endpoint] = NULL; + if (endpoint != XHCI_DEFAULT_ENDPOINT) { + VERIFY(!(xep->xep_state & XHCI_ENDPOINT_OPEN)); + } + xhci_ring_free(&xep->xep_ring); cv_destroy(&xep->xep_state_cv); list_destroy(&xep->xep_transfers); @@ -429,15 +462,27 @@ xhci_endpoint_avg_trb(xhci_t *xhcip, usb_ep_descr_t *ep, int mps) /* LINTED: E_FUNC_NO_RET_VAL */ } +/* + * Set up the input context for this endpoint. If this endpoint is already + * open, just confirm that the current parameters and the originally programmed + * parameters match. + */ int xhci_endpoint_setup_context(xhci_t *xhcip, xhci_device_t *xd, xhci_endpoint_t *xep) { - uint_t eptype, burst, ival, max_esit, avgtrb, mps, mult, cerr; + xhci_endpoint_params_t new_xepp; xhci_endpoint_context_t *ectx; uint64_t deq; /* + * Explicitly zero this entire struct to start so that we can compare + * it with bcmp(). + */ + bzero(&new_xepp, sizeof (new_xepp)); + new_xepp.xepp_configured = B_TRUE; + + /* * For a USB >=3.0 device we should always have its companion descriptor * provided for us by USBA. If it's not here, complain loudly and fail. */ @@ -464,9 +509,10 @@ xhci_endpoint_setup_context(xhci_t *xhcip, xhci_device_t *xd, VERIFY(xd->xd_usbdev->usb_dev_descr != NULL); VERIFY(xep->xep_pipe != NULL); - mps = xep->xep_pipe->p_ep.wMaxPacketSize & XHCI_CONTEXT_MPS_MASK; - mult = XHCI_CONTEXT_DEF_MULT; - cerr = XHCI_CONTEXT_DEF_CERR; + new_xepp.xepp_mps = + xep->xep_pipe->p_ep.wMaxPacketSize & XHCI_CONTEXT_MPS_MASK; + new_xepp.xepp_mult = XHCI_CONTEXT_DEF_MULT; + new_xepp.xepp_cerr = XHCI_CONTEXT_DEF_CERR; switch (xep->xep_type) { case USB_EP_ATTR_ISOCH: @@ -484,12 +530,13 @@ xhci_endpoint_setup_context(xhci_t *xhcip, xhci_device_t *xd, if (xd->xd_usbdev->usb_port_status >= USBA_SUPER_SPEED_DEV) { ASSERT(xep->xep_pipe->p_xep.uex_flags & USB_EP_XFLAGS_SS_COMP); - mult = xep->xep_pipe->p_xep.uex_ep_ss.bmAttributes & + new_xepp.xepp_mult = + xep->xep_pipe->p_xep.uex_ep_ss.bmAttributes & USB_EP_SS_COMP_ISOC_MULT_MASK; } - mps &= XHCI_CONTEXT_MPS_MASK; - cerr = XHCI_CONTEXT_ISOCH_CERR; + new_xepp.xepp_mps &= XHCI_CONTEXT_MPS_MASK; + new_xepp.xepp_cerr = XHCI_CONTEXT_ISOCH_CERR; break; default: /* @@ -500,37 +547,69 @@ xhci_endpoint_setup_context(xhci_t *xhcip, xhci_device_t *xd, break; } - eptype = xhci_endpoint_epdesc_to_type(&xep->xep_pipe->p_xep.uex_ep); - burst = xhci_endpoint_determine_burst(xd, xep); - ival = xhci_endpoint_interval(xd, &xep->xep_pipe->p_xep.uex_ep); - max_esit = xhci_endpoint_max_esit(xd, xep, mps, burst); - avgtrb = xhci_endpoint_avg_trb(xhcip, &xep->xep_pipe->p_xep.uex_ep, - mps); + new_xepp.xepp_eptype = xhci_endpoint_epdesc_to_type( + &xep->xep_pipe->p_xep.uex_ep); + new_xepp.xepp_burst = xhci_endpoint_determine_burst(xd, xep); + new_xepp.xepp_ival = xhci_endpoint_interval(xd, + &xep->xep_pipe->p_xep.uex_ep); + new_xepp.xepp_max_esit = xhci_endpoint_max_esit(xd, xep, + new_xepp.xepp_mps, new_xepp.xepp_burst); + new_xepp.xepp_avgtrb = xhci_endpoint_avg_trb(xhcip, + &xep->xep_pipe->p_xep.uex_ep, new_xepp.xepp_mps); /* * The multi field may be reserved as zero if the LEC feature flag is * set. See the description of mult in xHCI 1.1 / 6.2.3. */ if (xhcip->xhci_caps.xcap_flags2 & XCAP2_LEC) - mult = 0; + new_xepp.xepp_mult = 0; + + if (xep->xep_params.xepp_configured) { + /* + * The endpoint context has been configured already. We are + * reopening the pipe, so just confirm that the parameters are + * the same. + */ + if (bcmp(&xep->xep_params, &new_xepp, sizeof (new_xepp)) == 0) { + /* + * Everything matches up. + */ + return (0); + } + + DTRACE_PROBE3(xhci__context__mismatch, + xhci_t *, xhcip, + xhci_endpoint_t *, xep, + xhci_endpoint_params_t *, &new_xepp); + + xhci_error(xhcip, "device input context on slot %d and " + "port %d for endpoint %u was already initialized but " + "with incompatible parameters", + xd->xd_slot, xd->xd_port, xep->xep_num); + return (EINVAL); + } bzero(ectx, sizeof (xhci_endpoint_context_t)); - ectx->xec_info = LE_32(XHCI_EPCTX_SET_MULT(mult) | - XHCI_EPCTX_SET_IVAL(ival)); - if (xhcip->xhci_caps.xcap_flags2 & XCAP2_LEC) - ectx->xec_info |= LE_32(XHCI_EPCTX_SET_MAX_ESIT_HI(max_esit)); + ectx->xec_info = LE_32(XHCI_EPCTX_SET_MULT(new_xepp.xepp_mult) | + XHCI_EPCTX_SET_IVAL(new_xepp.xepp_ival)); + if (xhcip->xhci_caps.xcap_flags2 & XCAP2_LEC) { + ectx->xec_info |= + LE_32(XHCI_EPCTX_SET_MAX_ESIT_HI(new_xepp.xepp_max_esit)); + } - ectx->xec_info2 = LE_32(XHCI_EPCTX_SET_CERR(cerr) | - XHCI_EPCTX_SET_EPTYPE(eptype) | XHCI_EPCTX_SET_MAXB(burst) | - XHCI_EPCTX_SET_MPS(mps)); + ectx->xec_info2 = LE_32(XHCI_EPCTX_SET_CERR(new_xepp.xepp_cerr) | + XHCI_EPCTX_SET_EPTYPE(new_xepp.xepp_eptype) | + XHCI_EPCTX_SET_MAXB(new_xepp.xepp_burst) | + XHCI_EPCTX_SET_MPS(new_xepp.xepp_mps)); deq = xhci_dma_pa(&xep->xep_ring.xr_dma) + sizeof (xhci_trb_t) * xep->xep_ring.xr_tail; ectx->xec_dequeue = LE_64(deq | xep->xep_ring.xr_cycle); - ectx->xec_txinfo = LE_32(XHCI_EPCTX_MAX_ESIT_PAYLOAD(max_esit) | - XHCI_EPCTX_AVG_TRB_LEN(avgtrb)); + ectx->xec_txinfo = LE_32( + XHCI_EPCTX_MAX_ESIT_PAYLOAD(new_xepp.xepp_max_esit) | + XHCI_EPCTX_AVG_TRB_LEN(new_xepp.xepp_avgtrb)); XHCI_DMA_SYNC(xd->xd_ictx, DDI_DMA_SYNC_FORDEV); if (xhci_check_dma_handle(xhcip, &xd->xd_ictx) != DDI_FM_OK) { @@ -542,6 +621,8 @@ xhci_endpoint_setup_context(xhci_t *xhcip, xhci_device_t *xd, return (EIO); } + bcopy(&new_xepp, &xep->xep_params, sizeof (new_xepp)); + VERIFY(xep->xep_params.xepp_configured); return (0); } @@ -613,10 +694,69 @@ xhci_endpoint_init(xhci_t *xhcip, xhci_device_t *xd, return (ret); } + xep->xep_state |= XHCI_ENDPOINT_OPEN; + return (0); +} + +int +xhci_endpoint_reinit(xhci_t *xhcip, xhci_device_t *xd, xhci_endpoint_t *xep, + usba_pipe_handle_data_t *ph) +{ + VERIFY(MUTEX_HELD(&xhcip->xhci_lock)); + VERIFY(ph != NULL); + VERIFY3U(xhci_endpoint_pipe_to_epid(ph), ==, xep->xep_num); + VERIFY3U(xep->xep_num, !=, XHCI_DEFAULT_ENDPOINT); + + if (xep->xep_type != (ph->p_ep.bmAttributes & USB_EP_ATTR_MASK)) { + /* + * The endpoint type should not change unless the device has + * been torn down and recreated by the framework. + */ + return (EINVAL); + } + + if (xep->xep_state & XHCI_ENDPOINT_OPEN) { + return (EBUSY); + } + + VERIFY(xep->xep_state & XHCI_ENDPOINT_TEARDOWN); + xep->xep_state &= ~XHCI_ENDPOINT_TEARDOWN; + + VERIFY3U(xep->xep_timeout, ==, 0); + VERIFY(list_is_empty(&xep->xep_transfers)); + + VERIFY3P(xep->xep_pipe, ==, NULL); + xep->xep_pipe = ph; + + /* + * Verify that the endpoint context parameters have not changed in a + * way that requires us to tell the controller about it. + */ + int ret; + if ((ret = xhci_endpoint_setup_context(xhcip, xd, xep)) != 0) { + xep->xep_pipe = NULL; + xhci_endpoint_timeout_cancel(xhcip, xep); + return (ret); + } + + xep->xep_state |= XHCI_ENDPOINT_OPEN; return (0); } /* + * Wait until any ongoing resets or time outs are completed. + */ +void +xhci_endpoint_serialize(xhci_t *xhcip, xhci_endpoint_t *xep) +{ + VERIFY(MUTEX_HELD(&xhcip->xhci_lock)); + + while ((xep->xep_state & XHCI_ENDPOINT_SERIALIZE) != 0) { + cv_wait(&xep->xep_state_cv, &xhcip->xhci_lock); + } +} + +/* * Attempt to quiesce an endpoint. Depending on the state of the endpoint, we * may need to simply stop it. Alternatively, we may need to explicitly reset * the endpoint. Once done, this endpoint should be stopped and can be diff --git a/usr/src/uts/common/io/usb/hcd/xhci/xhci_usba.c b/usr/src/uts/common/io/usb/hcd/xhci/xhci_usba.c index cd03bf2d32..114bd716c0 100644 --- a/usr/src/uts/common/io/usb/hcd/xhci/xhci_usba.c +++ b/usr/src/uts/common/io/usb/hcd/xhci/xhci_usba.c @@ -12,6 +12,7 @@ /* * Copyright (c) 2018, Joyent, Inc. * Copyright (c) 2019 by Western Digital Corporation + * Copyright 2022 Oxide Computer Company */ /* @@ -58,7 +59,7 @@ xhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) { xhci_t *xhcip = xhci_hcdi_get_xhcip(ph); xhci_pipe_t *pipe; - xhci_endpoint_t *xep; + xhci_endpoint_t *xep = NULL; xhci_device_t *xd; int kmflags = usb_flags & USB_FLAGS_SLEEP ? KM_SLEEP : KM_NOSLEEP; int ret; @@ -131,8 +132,21 @@ xhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) goto add; } - if (xd->xd_endpoints[epid] != NULL) { + /* + * If we're opening an endpoint other than the default control endpoint, + * then the device should have had a USB address assigned by the + * controller. Sanity check that before continuing. + */ + VERIFY(xd->xd_addressed == B_TRUE); + + /* + * We may have already initialized the endpoint with a previous pipe + * open. + */ + if ((xep = xd->xd_endpoints[epid]) != NULL && + (xep->xep_state & XHCI_ENDPOINT_OPEN)) { mutex_exit(&xhcip->xhci_lock); + kmem_free(pipe, sizeof (xhci_pipe_t)); xhci_log(xhcip, "!asked to open endpoint %d on slot %d and " "port %d, but endpoint already exists", epid, xd->xd_slot, @@ -140,19 +154,75 @@ xhci_hcdi_pipe_open(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) return (USB_FAILURE); } - /* - * If we're opening an endpoint other than the default control endpoint, - * then the device should have had a USB address assigned by the - * controller. Sanity check that before continuing. - */ - if (epid != XHCI_DEFAULT_ENDPOINT) { - VERIFY(xd->xd_addressed == B_TRUE); + if (xep != NULL) { + /* + * The endpoint is already initialized but is not presently + * open so we can take it over here. + */ + if ((ret = xhci_endpoint_reinit(xhcip, xd, xep, ph) != 0)) { + mutex_exit(&xhcip->xhci_lock); + + kmem_free(pipe, sizeof (xhci_pipe_t)); + xhci_log(xhcip, "!asked to reopen endpoint %d on " + "slot %d and port %d, but reinit failed (%d)", + epid, xd->xd_slot, xd->xd_port, ret); + return (ret); + } + + /* + * We need to ensure the endpoint is stopped before we try to + * reset the transfer ring. + */ + xep->xep_state |= XHCI_ENDPOINT_QUIESCE; + if ((ret = xhci_endpoint_quiesce(xhcip, xd, xep)) != + USB_SUCCESS) { + /* + * If we could not quiesce the endpoint, release it so + * that another open can try again. + */ + xep->xep_state &= ~XHCI_ENDPOINT_QUIESCE; + xhci_endpoint_release(xhcip, xep); + mutex_exit(&xhcip->xhci_lock); + + kmem_free(pipe, sizeof (xhci_pipe_t)); + xhci_log(xhcip, "!asked to reopen endpoint %d on " + "slot %d and port %d, but quiesce failed (%d)", + epid, xd->xd_slot, xd->xd_port, ret); + return (ret); + } + + /* + * Reset the transfer ring dequeue pointer. The initial + * Configure Endpoint command leaves the endpoint in the + * Running state (xHCI 1.2 / 4.6.6), so even though the ring is + * still empty we ring the doorbell to end up in the same state + * (Running but Inactive). + */ + mutex_exit(&xhcip->xhci_lock); + if ((ret = xhci_command_set_tr_dequeue(xhcip, xd, xep)) != 0 || + (ret = xhci_endpoint_ring(xhcip, xd, xep)) != 0) { + mutex_enter(&xhcip->xhci_lock); + xep->xep_state &= ~XHCI_ENDPOINT_QUIESCE; + xhci_endpoint_release(xhcip, xep); + mutex_exit(&xhcip->xhci_lock); + + kmem_free(pipe, sizeof (xhci_pipe_t)); + xhci_log(xhcip, "!asked to open endpoint %d on " + "slot %d and port %d, but restart failed (%d)", + epid, xd->xd_slot, xd->xd_port, ret); + return (USB_FAILURE); + } + mutex_enter(&xhcip->xhci_lock); + xep->xep_state &= ~XHCI_ENDPOINT_QUIESCE; + mutex_exit(&xhcip->xhci_lock); + + goto add; } /* - * Okay, at this point we need to go create and set up an endpoint. - * Once we're done, we'll try to install it and make sure that it - * doesn't conflict with something else going on. + * Okay, at this point we need to go create and set up an endpoint from + * scratch. Once we're done, we'll try to install it and make sure + * that it doesn't conflict with something else going on. */ ret = xhci_endpoint_init(xhcip, xd, ph); if (ret != 0) { @@ -337,9 +407,7 @@ xhci_hcdi_pipe_poll_fini(usba_pipe_handle_data_t *ph, boolean_t is_close) /* * Ensure that no other resets or time outs are going on right now. */ - while ((xep->xep_state & (XHCI_ENDPOINT_SERIALIZE)) != 0) { - cv_wait(&xep->xep_state_cv, &xhcip->xhci_lock); - } + xhci_endpoint_serialize(xhcip, xep); if (xpp->xpp_poll_state == XHCI_PERIODIC_POLL_IDLE) { mutex_exit(&xhcip->xhci_lock); @@ -417,7 +485,6 @@ xhci_hcdi_pipe_poll_fini(usba_pipe_handle_data_t *ph, boolean_t is_close) * Tear down everything that we did in open. After this, the consumer of this * USB device is done. */ -/* ARGSUSED */ static int xhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) { @@ -425,8 +492,7 @@ xhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) xhci_pipe_t *xp; xhci_device_t *xd; xhci_endpoint_t *xep; - uint32_t info; - int ret, i; + int ret; uint_t epid; if ((ph->p_ep.bmAttributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR && @@ -467,53 +533,29 @@ xhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) } /* - * We need to clean up the endpoint. So the first thing we need to do is - * stop it with a configure endpoint command. Once it's stopped, we can - * free all associated resources. - */ - mutex_enter(&xd->xd_imtx); - - /* - * Potentially update the slot input context about the current max - * endpoint. Make sure to set that the slot context is being updated - * here as it may be changing and some hardware requires it. + * We clean up the endpoint by stopping it and cancelling any transfers + * that were in flight at the time. The endpoint is not unconfigured + * until the device is torn down later. */ - xd->xd_input->xic_drop_flags = LE_32(XHCI_INCTX_MASK_DCI(epid + 1)); - xd->xd_input->xic_add_flags = LE_32(XHCI_INCTX_MASK_DCI(0)); - for (i = XHCI_NUM_ENDPOINTS - 1; i >= 0; i--) { - if (xd->xd_endpoints[i] != NULL && - xd->xd_endpoints[i] != xep) - break; + xhci_endpoint_timeout_cancel(xhcip, xep); + xep->xep_state |= XHCI_ENDPOINT_QUIESCE; + if ((ret = xhci_endpoint_quiesce(xhcip, xd, xep)) != USB_SUCCESS) { + /* + * If we cannot stop the ring, it is not safe to proceed and we + * must keep the pipe open. + */ + xep->xep_state &= + ~(XHCI_ENDPOINT_TEARDOWN | XHCI_ENDPOINT_QUIESCE); + cv_broadcast(&xep->xep_state_cv); + mutex_exit(&xhcip->xhci_lock); + xhci_error(xhcip, "asked to do close pipe on slot %d, " + "port %d, endpoint: %d, but quiesce failed %d", + xd->xd_slot, xd->xd_port, epid, ret); + return (USB_FAILURE); } - info = xd->xd_slotin->xsc_info; - info &= ~XHCI_SCTX_DCI_MASK; - info |= XHCI_SCTX_SET_DCI(i + 1); - xd->xd_slotin->xsc_info = info; - - /* - * Also zero out our context for this endpoint. Note that we don't - * bother with syncing DMA memory here as it's not required to be synced - * for this operation. - */ - bzero(xd->xd_endin[xep->xep_num], sizeof (xhci_endpoint_context_t)); - - /* - * Stop the device and kill our timeout. Note, it is safe to hold the - * device's input mutex across the untimeout, this lock should never be - * referenced by the timeout code. - */ - xep->xep_state |= XHCI_ENDPOINT_TEARDOWN; - mutex_exit(&xhcip->xhci_lock); - (void) untimeout(xep->xep_timeout); - - ret = xhci_command_configure_endpoint(xhcip, xd); - mutex_exit(&xd->xd_imtx); - if (ret != USB_SUCCESS) - return (ret); - mutex_enter(&xhcip->xhci_lock); /* - * Now that we've unconfigured the endpoint. See if we need to flush any + * Now that we've stopped the endpoint, see if we need to flush any * transfers. */ xhci_hcdi_pipe_flush(xhcip, xep, USB_CR_PIPE_CLOSING); @@ -521,7 +563,7 @@ xhci_hcdi_pipe_close(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) xhci_hcdi_periodic_free(xhcip, xp); } - xhci_endpoint_fini(xd, epid); + xhci_endpoint_release(xhcip, xep); remove: ph->p_hcd_private = NULL; @@ -579,9 +621,7 @@ xhci_hcdi_pipe_reset(usba_pipe_handle_data_t *ph, usb_flags_t usb_flags) /* * Ensure that no other resets or time outs are going on right now. */ - while ((xep->xep_state & (XHCI_ENDPOINT_SERIALIZE)) != 0) { - cv_wait(&xep->xep_state_cv, &xhcip->xhci_lock); - } + xhci_endpoint_serialize(xhcip, xep); xep->xep_state |= XHCI_ENDPOINT_QUIESCE; ret = xhci_endpoint_quiesce(xhcip, xd, xep); @@ -1679,8 +1719,7 @@ xhci_hcdi_device_init(usba_device_t *ud, usb_port_t port, void **hcdpp) } /* - * We're tearing down a device now. That means that the only endpoint context - * that's still valid would be endpoint zero. + * We're tearing down a device now. */ static void xhci_hcdi_device_fini(usba_device_t *ud, void *hcdp) @@ -1726,7 +1765,16 @@ xhci_hcdi_device_fini(usba_device_t *ud, void *hcdp) } xhci_context_slot_output_fini(xhcip, xd); - xhci_endpoint_fini(xd, XHCI_DEFAULT_ENDPOINT); + + /* + * Once the slot is disabled, we can free any endpoints that were + * opened. + */ + for (uint_t n = 0; n < XHCI_NUM_ENDPOINTS; n++) { + if (xd->xd_endpoints[n] != NULL) { + xhci_endpoint_fini(xd, n); + } + } mutex_enter(&xhcip->xhci_lock); list_remove(&xhcip->xhci_usba.xa_devices, xd); diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h index a77a697f85..f61b9aa9a2 100644 --- a/usr/src/uts/common/smbsrv/smb_kproto.h +++ b/usr/src/uts/common/smbsrv/smb_kproto.h @@ -294,7 +294,8 @@ void smb_oplock_ind_break(smb_ofile_t *, uint32_t, boolean_t, uint32_t); void smb_oplock_ind_break_in_ack(smb_request_t *, smb_ofile_t *, uint32_t, boolean_t); void smb_oplock_send_brk(smb_request_t *); -uint32_t smb_oplock_wait_break(smb_node_t *, int); +uint32_t smb_oplock_wait_break(smb_request_t *, smb_node_t *, int); +uint32_t smb_oplock_wait_break_fem(smb_node_t *, int); /* * range lock functions - node operations @@ -664,6 +665,7 @@ void smb_ofile_flush(smb_request_t *, smb_ofile_t *); boolean_t smb_ofile_hold(smb_ofile_t *); boolean_t smb_ofile_hold_olbrk(smb_ofile_t *); void smb_ofile_release(smb_ofile_t *); +void smb_ofile_release_LL(void *); void smb_ofile_close_all(smb_tree_t *, uint32_t); void smb_ofile_set_flags(smb_ofile_t *, uint32_t); boolean_t smb_ofile_is_open(smb_ofile_t *); @@ -740,6 +742,9 @@ cred_t *smb_kcred_create(void); void smb_user_setcred(smb_user_t *, cred_t *, uint32_t); boolean_t smb_is_same_user(cred_t *, cred_t *); boolean_t smb_user_has_security_priv(smb_user_t *, cred_t *); +void smb_user_inc_trees(smb_user_t *); +void smb_user_dec_trees(smb_user_t *); +void smb_user_wait_trees(smb_user_t *); /* * SMB tree functions (file smb_tree.c) diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h index 5c083b6873..89b057ff91 100644 --- a/usr/src/uts/common/smbsrv/smb_ktypes.h +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2020 Tintri by DDN, Inc. All rights reserved. + * Copyright 2011-2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2022 RackTop Systems, Inc. */ @@ -1077,6 +1077,8 @@ typedef struct smb_user { uint32_t u_privileges; uint16_t u_uid; /* unique per-session */ uint32_t u_audit_sid; + uint32_t u_owned_tree_cnt; + kcondvar_t u_owned_tree_cv; uint32_t u_sign_flags; struct smb_key u_sign_key; /* SMB2 signing */ @@ -1799,6 +1801,7 @@ typedef enum smb_req_state { SMB_REQ_STATE_WAITING_FCN2, SMB_REQ_STATE_WAITING_LOCK, SMB_REQ_STATE_WAITING_PIPE, + SMB_REQ_STATE_WAITING_OLBRK, SMB_REQ_STATE_COMPLETED, SMB_REQ_STATE_CANCEL_PENDING, SMB_REQ_STATE_CANCELLED, diff --git a/usr/src/uts/common/sys/usb/hcd/xhci/xhci.h b/usr/src/uts/common/sys/usb/hcd/xhci/xhci.h index c226019105..ddc1e09e1a 100644 --- a/usr/src/uts/common/sys/usb/hcd/xhci/xhci.h +++ b/usr/src/uts/common/sys/usb/hcd/xhci/xhci.h @@ -12,6 +12,7 @@ /* * Copyright (c) 2018, Joyent, Inc. * Copyright (c) 2019 by Western Digital Corporation + * Copyright 2022 Oxide Computer Company */ #ifndef _SYS_USB_XHCI_XHCI_H @@ -497,17 +498,6 @@ typedef enum xhci_endpoint_state { XHCI_ENDPOINT_QUIESCE = 0x04, XHCI_ENDPOINT_TIMED_OUT = 0x08, /* - * This is a composite of states that we need to watch for. We don't - * want to allow ourselves to set one of these flags while one of them - * is currently active. - */ - XHCI_ENDPOINT_SERIALIZE = 0x0c, - /* - * This is a composite of states that we need to make sure that if set, - * we do not schedule activity on the ring. - */ - XHCI_ENDPOINT_DONT_SCHEDULE = 0x0e, - /* * This enpdoint is being torn down and should make sure it de-schedules * itself. */ @@ -516,15 +506,47 @@ typedef enum xhci_endpoint_state { * This endpoint is currently used in polled I/O mode by the * kernel debugger. */ - XHCI_ENDPOINT_POLLED = 0x20 + XHCI_ENDPOINT_POLLED = 0x20, + /* + * This endpoint is open and in use by a pipe. + */ + XHCI_ENDPOINT_OPEN = 0x40, } xhci_endpoint_state_t; /* + * This is a composite of states that we need to watch for. We don't + * want to allow ourselves to set one of these flags while one of them + * is currently active. + */ +#define XHCI_ENDPOINT_SERIALIZE (XHCI_ENDPOINT_QUIESCE | \ + XHCI_ENDPOINT_TIMED_OUT) + +/* + * This is a composite of states that we need to make sure that if set, we do + * not schedule activity on the ring. + */ +#define XHCI_ENDPOINT_DONT_SCHEDULE (XHCI_ENDPOINT_HALTED | \ + XHCI_ENDPOINT_QUIESCE | \ + XHCI_ENDPOINT_TIMED_OUT) + +/* * Forwards required for the endpoint */ struct xhci_device; struct xhci; +typedef struct xhci_endpoint_params { + boolean_t xepp_configured; + uint_t xepp_eptype; + uint_t xepp_burst; + uint_t xepp_ival; + uint_t xepp_max_esit; + uint_t xepp_avgtrb; + uint_t xepp_mps; + uint_t xepp_mult; + uint_t xepp_cerr; +} xhci_endpoint_params_t; + typedef struct xhci_endpoint { struct xhci *xep_xhci; struct xhci_device *xep_xd; @@ -536,6 +558,7 @@ typedef struct xhci_endpoint { list_t xep_transfers; usba_pipe_handle_data_t *xep_pipe; xhci_ring_t xep_ring; + xhci_endpoint_params_t xep_params; } xhci_endpoint_t; typedef struct xhci_device { @@ -828,9 +851,13 @@ extern void xhci_fm_runtime_reset(xhci_t *); */ extern int xhci_endpoint_init(xhci_t *, xhci_device_t *, usba_pipe_handle_data_t *); +extern int xhci_endpoint_reinit(xhci_t *, xhci_device_t *, + xhci_endpoint_t *, usba_pipe_handle_data_t *); +extern void xhci_endpoint_release(xhci_t *, xhci_endpoint_t *); extern void xhci_endpoint_fini(xhci_device_t *, int); extern int xhci_endpoint_update_default(xhci_t *, xhci_device_t *, xhci_endpoint_t *); +extern void xhci_endpoint_timeout_cancel(xhci_t *, xhci_endpoint_t *); extern int xhci_endpoint_setup_default_context(xhci_t *, xhci_device_t *, xhci_endpoint_t *); @@ -838,6 +865,7 @@ extern int xhci_endpoint_setup_default_context(xhci_t *, xhci_device_t *, extern uint_t xhci_endpoint_pipe_to_epid(usba_pipe_handle_data_t *); extern boolean_t xhci_endpoint_is_periodic_in(xhci_endpoint_t *); +extern void xhci_endpoint_serialize(xhci_t *, xhci_endpoint_t *); extern int xhci_endpoint_quiesce(xhci_t *, xhci_device_t *, xhci_endpoint_t *); extern int xhci_endpoint_schedule(xhci_t *, xhci_device_t *, xhci_endpoint_t *, xhci_transfer_t *, boolean_t); |