# # 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 # testoplock is always 32-bit setenv LD_LIBRARY_PATH ${ROOT}/usr/lib/smbsrv:${ROOT}/usr/lib:${ROOT}/lib echo 'Do one of: attach ${PID}' echo 'or: debug ${ROOT}/usr/lib/smbsrv/testoplock' # # 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. # PROG= testoplock OBJS_LOCAL= tol_main.o tol_misc.o OBJS_SMBSRV= smb_cmn_oplock.o OBJS_LIBSMB= smb_status_tbl.o OBJS= ${OBJS_LOCAL} ${OBJS_SMBSRV} ${OBJS_LIBSMB} SMBSRV_SRCDIR=../../../uts/common/fs/smbsrv SRCS= ${OBJS_LOCAL:.o=.c} \ ${OBJS_SMBSRV:%.o=${SMBSRV_SRCDIR}/%.c} include ../../Makefile.cmd include ../../Makefile.ctf # Note: need our sys includes _before_ ENVCPPFLAGS, proto etc. CPPFLAGS.first += -I. CPPFLAGS.first += -I../../../lib/libfakekernel/common CPPFLAGS.first += -I../../../lib/smbsrv/libfksmbsrv/common INCS += -I../../../uts/common CSTD= $(CSTD_GNU99) CFLAGS += $(CCVERBOSE) CFLAGS64 += $(CCVERBOSE) CPPFLAGS.master=$(DTEXTDOM) $(DTS_ERRNO) # CPPFLAGS is deliberatly set with a "=" and not a "+="... CPPFLAGS= $(CPPFLAGS.first) $(CPPFLAGS.master) CPPFLAGS += -D_REENTRANT CPPFLAGS += -DTESTJIG CPPFLAGS += -Dsyslog=smb_syslog CPPFLAGS += -D_LARGEFILE64_SOURCE=1 # Always debug here CPPFLAGS += -DDEBUG CPPFLAGS += $(INCS) LDFLAGS += $(ZNOLAZYLOAD) LDFLAGS += '-R$$ORIGIN/..' LDLIBS += -lfakekernel -lcmdutils LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2 LINTFLAGS += -xerroff=E_NAME_USED_NOT_DEF2 LINTFLAGS += -xerroff=E_INCONS_ARG_DECL2 LINTFLAGS += -xerroff=E_INCONS_VAL_TYPE_DECL2 ROOTSMBDDIR = $(ROOTLIB)/smbsrv ROOTSMBDFILE = $(PROG:%=$(ROOTSMBDDIR)/%) .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS) $(POST_PROCESS) clean: -$(RM) $(OBJS) lint: # lint_SRCS include ../../Makefile.targ install: all $(ROOTSMBDFILE) tol_main.o : tol_main.c $(CC) $(CFLAGS) $(CPPFLAGS) -D_KMEMUSER -c tol_main.c $(POST_PROCESS_O) tol_misc.o : tol_misc.c $(CC) $(CFLAGS) $(CPPFLAGS) -D_FAKE_KERNEL \ -I../../../uts/common/smbsrv \ -I../../../common/smbsrv -c tol_misc.c $(POST_PROCESS_O) # OBJS_SMBSRV %.o: ../../../uts/common/fs/smbsrv/%.c $(CC) $(CFLAGS) $(CPPFLAGS) -D_FAKE_KERNEL \ -I../../../uts/common/smbsrv \ -I../../../common/smbsrv -c $< $(POST_PROCESS_O) # Hammerhead: Generate smb_status_tbl.h before compiling smb_status_tbl.c LIBSMB_SRCDIR = ../../../lib/smbsrv/libsmb/common SMB_STATUS_HDR = $(LIBSMB_SRCDIR)/smb_status_tbl.h smb_status_tbl.o: $(SMB_STATUS_HDR) $(SMB_STATUS_HDR): $(LIBSMB_SRCDIR)/smb_status_gen.awk $(SRC)/uts/common/smb/ntstatus.h $(AWK) -f $(LIBSMB_SRCDIR)/smb_status_gen.awk \ $(SRC)/uts/common/smb/ntstatus.h > $@ # OBJS_LIBSMB %.o: $(LIBSMB_SRCDIR)/%.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $< $(POST_PROCESS_O) $(ROOTSMBDDIR)/%: % $(INS.file) #!/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:$ROOT/lib export LD_LIBRARY_PATH # run with the passed options exec $ROOT/usr/lib/smbsrv/testoplock "$@" #!/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:$ROOT/lib export LD_LIBRARY_PATH TOL=$ROOT/usr/lib/smbsrv/testoplock TESTS=${@:-case??.txt} # run the test cases for t in $TESTS do name=${t%.txt} $TOL < $name.txt > $name.tmp if diff -u $name.tmp $name.ref >/dev/null 2>&1 ; then echo "$name PASS" rm $name.tmp else echo "$name FAIL" diff -u $name.tmp $name.ref fi done open 1 open 1 OK req 1 req oplock fid=1 ret oplock=0x400 status=0x0 (SUCCESS) show ol_state=0x410 ( BATCH_OPLOCK EXCLUSIVE ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease= State=0x400 Excl=Y onlist: brk-open 2 *smb_oplock_ind_break fid=1 NewLevel=0x100, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x100, OldLevel=0x400, AckReq=1) brk-open 2 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) show ol_state=0x100410 ( BREAK_TO_TWO BATCH_OPLOCK EXCLUSIVE ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease= State=0x400 BreakTo=0x100 Excl=Y onlist: ack 1 ack: break fid=1, newstate=0x100, status=0x0 (SUCCESS) open 2 open 2 OK req 2 0x100 req oplock fid=2 ret oplock=0x100 status=0x0 (SUCCESS) show ol_state=0x100 ( LEVEL_TWO_OPLOCK ) Excl=n cnt_II=2 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease= State=0x100 Excl=N onlist: II fid=2 Lease= State=0x100 Excl=N onlist: II # Input for testoplock, case 01 open 1 req 1 show brk-open 2 show ack 1 open 2 req 2 0x100 show open 1 open 1 OK req 1 0x807 req oplock fid=1 ret oplock=0x807 status=0x0 (SUCCESS) show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease= State=0x807 Excl=Y onlist: brk-open 2 *smb_oplock_ind_break fid=1 NewLevel=0x3, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x803, OldLevel=0x807, AckReq=1) brk-open 2 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) show ol_state=0x30017 ( BREAK_TO_HANDLE_CACHING BREAK_TO_READ_CACHING EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease= State=0x807 BreakTo=0x803 Excl=Y onlist: ack 1 ack: break fid=1, newstate=0x803, status=0x0 (SUCCESS) open 2 open 2 OK req 2 0x803 req oplock fid=2 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=2 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease= State=0x803 Excl=N onlist: RH fid=2 Lease= State=0x803 Excl=N onlist: RH # Input for testoplock, case 02 open 1 req 1 0x807 show brk-open 2 show ack 1 open 2 req 2 0x803 show open 1 3 open 1 OK req 1 0x803 req oplock fid=1 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=3 State=0x803 Excl=N onlist: RH open 2 3 open 2 OK req 2 0x803 *smb_oplock_ind_break fid=1 NewLevel=0x3, AckReq=0, ComplStatus=0x215 (OPLOCK_SWITCHED_TO_NEW_HANDLE) req oplock fid=2 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=3 State=0x0 Excl=N onlist: fid=2 Lease=3 State=0x803 Excl=N onlist: RH # Input for testoplock, case 03 open 1 3 req 1 0x803 show open 2 3 req 2 0x803 show open 1 3 open 1 OK req 1 0x801 req oplock fid=1 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=3 State=0x801 Excl=N onlist: R open 2 3 open 2 OK req 2 0x801 *smb_oplock_ind_break fid=1 NewLevel=0x1, AckReq=0, ComplStatus=0x215 (OPLOCK_SWITCHED_TO_NEW_HANDLE) req oplock fid=2 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=3 State=0x0 Excl=N onlist: fid=2 Lease=3 State=0x801 Excl=N onlist: R # Input for testoplock, case 04 open 1 3 req 1 0x801 show open 2 3 req 2 0x801 show open 2 4 open 2 OK req 2 0x803 req oplock fid=2 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=1 fid=2 Lease=4 State=0x803 Excl=N onlist: RH open 3 4 open 3 OK req 3 0x803 *smb_oplock_ind_break fid=2 NewLevel=0x3, AckReq=0, ComplStatus=0x215 (OPLOCK_SWITCHED_TO_NEW_HANDLE) req oplock fid=3 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=2 Lease=4 State=0x0 Excl=N onlist: fid=3 Lease=4 State=0x803 Excl=N onlist: RH open 1 open 1 OK brk-write 1 *smb_oplock_ind_break fid=3 NewLevel=0x0, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=3 NewLevel=0x800, OldLevel=0x803, AckReq=1) brk-write 1 ret status=0x0 (SUCCESS) show ol_state=0x80003 ( BREAK_TO_NO_CACHING HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=1 ofile_cnt=3 fid=2 Lease=4 State=0x0 Excl=N onlist: fid=3 Lease=4 State=0x803 BreakTo=0x800 Excl=N onlist: RHBQ(to none) fid=1 Lease= State=0x0 Excl=N onlist: ack 3 ack: break fid=3, newstate=0x800, status=0x0 (SUCCESS) show ol_state=0x10000000 ( NO_OPLOCK ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=3 fid=2 Lease=4 State=0x0 Excl=N onlist: fid=3 Lease=4 State=0x800 Excl=N onlist: fid=1 Lease= State=0x0 Excl=N onlist: open 4 4 open 4 OK req 4 0x803 req oplock fid=4 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=4 fid=2 Lease=4 State=0x0 Excl=N onlist: fid=3 Lease=4 State=0x800 Excl=N onlist: fid=1 Lease= State=0x0 Excl=N onlist: fid=4 Lease=4 State=0x803 Excl=N onlist: RH close 4 *smb_oplock_ind_break fid=4 NewLevel=0x0, AckReq=0, ComplStatus=0x216 (OPLOCK_HANDLE_CLOSED) close OK req 3 0x803 req oplock fid=3 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=3 fid=2 Lease=4 State=0x0 Excl=N onlist: fid=3 Lease=4 State=0x803 Excl=N onlist: RH fid=1 Lease= State=0x0 Excl=N onlist: # Input for testoplock, case 05 open 2 4 req 2 0x803 show open 3 4 req 3 0x803 show open 1 brk-write 1 show ack 3 show open 4 4 req 4 0x803 show close 4 req 3 0x803 show open 1 1 open 1 OK req 1 0x801 req oplock fid=1 ret oplock=0x801 status=0x0 (SUCCESS) open 2 2 open 2 OK req 2 0x801 req oplock fid=2 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=2 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x801 Excl=N onlist: R fid=2 Lease=2 State=0x801 Excl=N onlist: R brk-write 1 *smb_oplock_ind_break fid=2 NewLevel=0x0, AckReq=0, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=2 NewLevel=0x800, OldLevel=0x801, AckReq=0) brk-write 1 ret status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x801 Excl=N onlist: R fid=2 Lease=2 State=0x800 Excl=N onlist: open 3 2 open 3 OK req 3 0x801 req oplock fid=3 ret oplock=0x801 status=0x0 (SUCCESS) close 3 *smb_oplock_ind_break fid=3 NewLevel=0x0, AckReq=0, ComplStatus=0x216 (OPLOCK_HANDLE_CLOSED) close OK req 2 0x801 req oplock fid=2 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=2 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x801 Excl=N onlist: R fid=2 Lease=2 State=0x801 Excl=N onlist: R brk-write 2 *smb_oplock_ind_break fid=1 NewLevel=0x0, AckReq=0, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x800, OldLevel=0x801, AckReq=0) brk-write 2 ret status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x800 Excl=N onlist: fid=2 Lease=2 State=0x801 Excl=N onlist: R brk-write 1 *smb_oplock_ind_break fid=2 NewLevel=0x0, AckReq=0, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=2 NewLevel=0x800, OldLevel=0x801, AckReq=0) brk-write 1 ret status=0x0 (SUCCESS) show ol_state=0x10000000 ( NO_OPLOCK ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x800 Excl=N onlist: fid=2 Lease=2 State=0x800 Excl=N onlist: # Input for testoplock, case 06 # Modeled after smbtorture smb2.lease.nobreakself open 1 1 req 1 0x801 open 2 2 req 2 0x801 # both 1,2 should have R show # write 1 should leave 1:R 2:none brk-write 1 show # upgrade 2 back to R open 3 2 req 3 0x801 close 3 # ind_break will "move" the lease to h2 (1:R 2:R) req 2 0x801 show # write 2 should leave 1:none 2:R brk-write 2 show # write 1 should leave 1:none 2:none brk-write 1 show open 1 3 open 1 OK req 1 0x803 req oplock fid=1 ret oplock=0x803 status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=3 State=0x803 Excl=N onlist: RH open 2 3 open 2 OK req 2 0x807 *smb_oplock_ind_break fid=1 NewLevel=0x7, AckReq=0, ComplStatus=0x215 (OPLOCK_SWITCHED_TO_NEW_HANDLE) req oplock fid=2 ret oplock=0x807 status=0x0 (SUCCESS) show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=2) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=3 State=0x0 Excl=N onlist: fid=2 Lease=3 State=0x807 Excl=Y onlist: # Input for testoplock, case 07 # Modeled after smbtorture smb2.lease.upgrade open 1 3 req 1 0x803 show open 2 3 req 2 0x807 show open 1 1 open 1 OK req 1 0x805 req oplock fid=1 ret oplock=0x805 status=0x0 (SUCCESS) show ol_state=0x15 ( EXCLUSIVE WRITE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=1 State=0x805 Excl=Y onlist: open 2 2 open 2 OK brk-open 2 *smb_oplock_ind_break fid=1 NewLevel=0x1, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x801, OldLevel=0x805, AckReq=1) brk-open 2 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) show ol_state=0x10015 ( BREAK_TO_READ_CACHING EXCLUSIVE WRITE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x805 BreakTo=0x801 Excl=Y onlist: fid=2 Lease=2 State=0x0 Excl=N onlist: ack 1 ack: break fid=1, newstate=0x801, status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x801 Excl=N onlist: R fid=2 Lease=2 State=0x0 Excl=N onlist: req 2 0x801 req oplock fid=2 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=2 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x801 Excl=N onlist: R fid=2 Lease=2 State=0x801 Excl=N onlist: R # Input for testoplock, case 08 # Modeled after smbtorture smb2.lease.upgrade3 # sub-case: "R" "RH" "RW" "R" open 1 1 req 1 0x805 show open 2 2 brk-open 2 show ack 1 show req 2 0x801 show open 1 open 1 OK req 1 0x100 req oplock fid=1 ret oplock=0x100 status=0x0 (SUCCESS) show ol_state=0x100 ( LEVEL_TWO_OPLOCK ) Excl=n cnt_II=1 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease= State=0x100 Excl=N onlist: II open 2 2 open 2 OK brk-open 2 brk-open 2 ret status=0x0 (SUCCESS) show ol_state=0x100 ( LEVEL_TWO_OPLOCK ) Excl=n cnt_II=1 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease= State=0x100 Excl=N onlist: II fid=2 Lease=2 State=0x0 Excl=N onlist: req 2 0x803 req oplock fid=2 ret oplock=0x0 status=0xc00000e2 (OPLOCK_NOT_GRANTED) show ol_state=0x100 ( LEVEL_TWO_OPLOCK ) Excl=n cnt_II=1 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease= State=0x100 Excl=N onlist: II fid=2 Lease=2 State=0x0 Excl=N onlist: # Input for testoplock, case 09 # Modeled after smbtorture smb2.lease.oplock open 1 req 1 0x100 show open 2 2 brk-open 2 show req 2 0x803 show open 1 open 1 OK req 1 0x100 req oplock fid=1 ret oplock=0x100 status=0x0 (SUCCESS) show ol_state=0x100 ( LEVEL_TWO_OPLOCK ) Excl=n cnt_II=1 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease= State=0x100 Excl=N onlist: II open 2 2 open 2 OK brk-open 2 brk-open 2 ret status=0x0 (SUCCESS) show ol_state=0x100 ( LEVEL_TWO_OPLOCK ) Excl=n cnt_II=1 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease= State=0x100 Excl=N onlist: II fid=2 Lease=2 State=0x0 Excl=N onlist: req 2 0x807 req oplock fid=2 ret oplock=0x0 status=0xc00000e2 (OPLOCK_NOT_GRANTED) req 2 0x803 req oplock fid=2 ret oplock=0x0 status=0xc00000e2 (OPLOCK_NOT_GRANTED) req 2 0x801 req oplock fid=2 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x101 ( LEVEL_TWO_OPLOCK READ_CACHING ) Excl=n cnt_II=1 cnt_R=1 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease= State=0x100 Excl=N onlist: II fid=2 Lease=2 State=0x801 Excl=N onlist: R # Input for testoplock, case 10 # Modeled after smbtorture smb2.lease.oplock open 1 req 1 0x100 show open 2 2 brk-open 2 show req 2 0x807 req 2 0x803 req 2 0x801 show open 1 1 open 1 OK req 1 0x807 req oplock fid=1 ret oplock=0x807 status=0x0 (SUCCESS) show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=1 State=0x807 Excl=Y onlist: open 2 open 2 OK brk-open 2 *smb_oplock_ind_break fid=1 NewLevel=0x3, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x803, OldLevel=0x807, AckReq=1) brk-open 2 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) ack 1 ack: break fid=1, newstate=0x803, status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x803 Excl=N onlist: RH fid=2 Lease= State=0x0 Excl=N onlist: req 2 0x100 req oplock fid=2 ret oplock=0x0 status=0xc00000e2 (OPLOCK_NOT_GRANTED) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x803 Excl=N onlist: RH fid=2 Lease= State=0x0 Excl=N onlist: # Input for testoplock, case 11 # Modeled after smbtorture smb2.lease.break2 open 1 1 req 1 0x807 show open 2 brk-open 2 ack 1 show req 2 0x100 show open 1 1 open 1 OK req 1 0x807 req oplock fid=1 ret oplock=0x807 status=0x0 (SUCCESS) show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=1 State=0x807 Excl=Y onlist: open 2 open 2 OK brk-open 2 *smb_oplock_ind_break fid=1 NewLevel=0x3, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x803, OldLevel=0x807, AckReq=1) brk-open 2 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) waiters 2 1 waiters 0 -> 1 show ol_state=0x30017 ( BREAK_TO_HANDLE_CACHING BREAK_TO_READ_CACHING EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x807 BreakTo=0x803 Excl=Y onlist: fid=2 Lease= State=0x0 Excl=N onlist: open 3 open 3 OK brk-open 3 4 brk-open 3 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) waiters 3 2 waiters 1 -> 2 show ol_state=0x80017 ( BREAK_TO_NO_CACHING EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=3 fid=1 Lease=1 State=0x807 BreakTo=0x803 Excl=Y onlist: fid=2 Lease= State=0x0 Excl=N onlist: fid=3 Lease= State=0x0 Excl=N onlist: ack 1 0x803 ack: break fid=1, newstate=0x803, status=0x0 (SUCCESS) *smb_oplock_ind_break_in_ack fid=1 NewLevel=0x1, AckReq=1 *smb_oplock_send_break fid=1 NewLevel=0x801, OldLevel=0x803, AckReq=1) show ol_state=0x80003 ( BREAK_TO_NO_CACHING HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=1 ofile_cnt=3 fid=1 Lease=1 State=0x803 BreakTo=0x801 Excl=N onlist: RHBQ(to none) fid=2 Lease= State=0x0 Excl=N onlist: fid=3 Lease= State=0x0 Excl=N onlist: ack 1 0x801 ack: break fid=1, newstate=0x801, status=0x0 (SUCCESS) *smb_oplock_ind_break_in_ack fid=1 NewLevel=0x0, AckReq=0 *smb_oplock_send_break fid=1 NewLevel=0x800, OldLevel=0x801, AckReq=0) show ol_state=0x10000000 ( NO_OPLOCK ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=3 fid=1 Lease=1 State=0x800 Excl=N onlist: fid=2 Lease= State=0x0 Excl=N onlist: fid=3 Lease= State=0x0 Excl=N onlist: # Input for testoplock, case 12 # simulate smbtorture smb2.lease.breaking3 # open 1 1 req 1 0x807 show # # a conflicting open (no oplock) is blocked until lease break ack open 2 brk-open 2 waiters 2 1 show # should see lease break RWH to RH, and brk-open would block. # now a conflicting open with disp=overwrite(4), no oplock open 3 brk-open 3 4 waiters 3 2 show # should see break_to_none pending (but no break ind yet) # and brk-open shoud block (break in progress) # # ack the first lease break above (RWH to RH) # should get a new break ind. (RH to R) ar=1 ack 1 0x803 show # ack the second lease break (RH to R) # should get a new break ind. (R to none) ar=0 ack 1 0x801 show open 1 1 open 1 OK req 1 0x801 req oplock fid=1 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x1 ( READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=1 State=0x801 Excl=N onlist: R open 2 1 open 2 OK brk-open 2 brk-open 2 ret status=0x0 (SUCCESS) req 2 0x807 *smb_oplock_ind_break fid=1 NewLevel=0x7, AckReq=0, ComplStatus=0x215 (OPLOCK_SWITCHED_TO_NEW_HANDLE) req oplock fid=2 ret oplock=0x807 status=0x0 (SUCCESS) show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=2) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x0 Excl=N onlist: fid=2 Lease=1 State=0x807 Excl=Y onlist: move 2 1 move 2 1 show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x807 Excl=Y onlist: fid=2 Lease=1 State=0x0 Excl=N onlist: close 2 close OK show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=1 State=0x807 Excl=Y onlist: open 3 2 open 3 OK brk-open 3 *smb_oplock_ind_break fid=1 NewLevel=0x3, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x803, OldLevel=0x807, AckReq=1) brk-open 3 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) ack 1 ack: break fid=1, newstate=0x803, status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x803 Excl=N onlist: RH fid=3 Lease=2 State=0x0 Excl=N onlist: req 3 0x801 req oplock fid=3 ret oplock=0x801 status=0x0 (SUCCESS) show ol_state=0x23 ( MIXED_R_AND_RH HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x803 Excl=N onlist: RH fid=3 Lease=2 State=0x801 Excl=N onlist: R # Input for testoplock, case 13 # simulate smbtorture smb2.lease.complex1 # open 1 1 req 1 0x801 show # upgrade lease 1 open 2 1 brk-open 2 req 2 0x807 show move 2 1 show close 2 show # contend via lease2 open 3 2 brk-open 3 ack 1 show req 3 0x801 show open 1 1 open 1 OK req 1 0x807 req oplock fid=1 ret oplock=0x807 status=0x0 (SUCCESS) show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=1 State=0x807 Excl=Y onlist: brk-setinfo 1 0xa brk-setinfo 1 0xa ret status=0x0 (SUCCESS) show ol_state=0x17 ( EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=1 fid=1 Lease=1 State=0x807 Excl=Y onlist: open 2 2 open 2 OK brk-open 2 *smb_oplock_ind_break fid=1 NewLevel=0x3, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=1 NewLevel=0x803, OldLevel=0x807, AckReq=1) brk-open 2 ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) show ol_state=0x30017 ( BREAK_TO_HANDLE_CACHING BREAK_TO_READ_CACHING EXCLUSIVE WRITE_CACHING HANDLE_CACHING READ_CACHING ) Excl=Y (FID=1) cnt_II=0 cnt_R=0 cnt_RH=0 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x807 BreakTo=0x803 Excl=Y onlist: fid=2 Lease=2 State=0x0 Excl=N onlist: ack 1 0x803 ack: break fid=1, newstate=0x803, status=0x0 (SUCCESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x803 Excl=N onlist: RH fid=2 Lease=2 State=0x0 Excl=N onlist: req 2 0x807 req oplock fid=2 ret oplock=0x0 status=0xc00000e2 (OPLOCK_NOT_GRANTED) req 2 0x803 req oplock fid=2 ret oplock=0x803 status=0x0 (SUCCESS) brk-setinfo 1 0xa *smb_oplock_ind_break fid=2 NewLevel=0x1, AckReq=1, ComplStatus=0x0 (SUCCESS) *smb_oplock_send_break fid=2 NewLevel=0x801, OldLevel=0x803, AckReq=1) brk-setinfo 1 0xa ret status=0x108 (OPLOCK_BREAK_IN_PROGRESS) show ol_state=0x3 ( HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=0 cnt_RH=1 cnt_RHBQ=1 ofile_cnt=2 fid=1 Lease=1 State=0x803 Excl=N onlist: RH fid=2 Lease=2 State=0x803 BreakTo=0x801 Excl=N onlist: RHBQ(to read) ack 2 0x801 ack: break fid=2, newstate=0x801, status=0x0 (SUCCESS) show ol_state=0x23 ( MIXED_R_AND_RH HANDLE_CACHING READ_CACHING ) Excl=n cnt_II=0 cnt_R=1 cnt_RH=1 cnt_RHBQ=0 ofile_cnt=2 fid=1 Lease=1 State=0x803 Excl=N onlist: RH fid=2 Lease=2 State=0x801 Excl=N onlist: R # Input for testoplock, case 13 # simulate smbtorture smb2.lease.v2_rename # Create (open_if, lease=e0dd(1), RWH, epoch=0x4711 ) # resp: fid=1, RWH, epoch=0x4712 # Expect no breaks, one handle, state=RWH open 1 1 req 1 0x807 show # SetInfo fid=1, newname=...dst.dat # resp OK (no breaks) brk-setinfo 1 0xa show # Create, open_if, lease=e0dd(1), RWH, epoch=0x4712 # resp fid=5 RWH, flags=0 (not breaking) # Close fid=5 / resp # This is handled without calling the common oplock layer, # by logic at the top of smb2_lease_acquire # Create, open_if, lease=feed(2), RWH, epoch=0x0044 # (resp pending, will break RWH to RH) open 2 2 brk-open 2 show # Lease Break Notify, lease=e0dd(1), RWH to RH, epoch=0x4713 # Lease Break Ack, lease=e0dd, RH # resp (same) ack 1 0x803 show # Create-resp, fid=9 lease=feed(2), state=RH, epoch=0x0045 # Now that open 2 breaking is done, it can request. # Will fail RWH, succeed RH req 2 0x807 req 2 0x803 # SetInfo fid=1, newname=...src.dat # (resp blocked -- win10 does not go pending? we do) # Should get rid of handle caching (RH to R) brk-setinfo 1 0xa show # Lease Break Notify, lease=feed(2), RH to R, epoch=0x0046 # Lease Break Ack, lease=feed(2), state=R # Break Ack Resp (same) ack 2 0x801 show # SetInfo resp, fid=1 (note: races with Break Ack resp.) /* * 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 2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2022 RackTop Systems, Inc. */ /* * Function prototypes needed by the "testoplock" program * (a small subset of what the SMB server uses) */ #ifndef _SMB_KPROTO_H_ #define _SMB_KPROTO_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include boolean_t smb_ofile_is_open(smb_ofile_t *); boolean_t smb_node_is_file(smb_node_t *); /* * SMB locked list function prototypes */ void smb_llist_init(void); void smb_llist_fini(void); void smb_llist_constructor(smb_llist_t *, size_t, size_t); void smb_llist_destructor(smb_llist_t *); void smb_llist_enter(smb_llist_t *ll, krw_t); void smb_llist_exit(smb_llist_t *); void smb_llist_post(smb_llist_t *, void *, smb_dtorproc_t); void smb_llist_flush(smb_llist_t *); void smb_llist_insert_head(smb_llist_t *ll, void *obj); void smb_llist_insert_tail(smb_llist_t *ll, void *obj); void smb_llist_remove(smb_llist_t *ll, void *obj); int smb_llist_upgrade(smb_llist_t *ll); uint32_t smb_llist_get_count(smb_llist_t *ll); #define smb_llist_head(ll) list_head(&(ll)->ll_list) #define smb_llist_next(ll, obj) list_next(&(ll)->ll_list, obj) int smb_account_connected(smb_user_t *user); /* * Common oplock functions */ uint32_t smb_oplock_request(smb_request_t *, smb_ofile_t *, uint32_t *); uint32_t smb_oplock_request_LH(smb_request_t *, smb_ofile_t *, uint32_t *); uint32_t smb_oplock_ack_break(smb_request_t *, smb_ofile_t *, uint32_t *); uint32_t smb_oplock_break_PARENT(smb_node_t *, smb_ofile_t *); uint32_t smb_oplock_break_OPEN(smb_node_t *, smb_ofile_t *, uint32_t DesiredAccess, uint32_t CreateDisposition); uint32_t smb_oplock_break_BATCH(smb_node_t *, smb_ofile_t *, uint32_t DesiredAccess, uint32_t CreateDisposition); uint32_t smb_oplock_break_HANDLE(smb_node_t *, smb_ofile_t *); void smb_oplock_break_CLOSE(smb_node_t *, smb_ofile_t *); uint32_t smb_oplock_break_READ(smb_node_t *, smb_ofile_t *); uint32_t smb_oplock_break_WRITE(smb_node_t *, smb_ofile_t *); uint32_t smb_oplock_break_SETINFO(smb_node_t *, smb_ofile_t *ofile, uint32_t InfoClass); uint32_t smb_oplock_break_DELETE(smb_node_t *, smb_ofile_t *); void smb_oplock_close(smb_ofile_t *); 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_break(smb_request_t *); uint32_t smb_oplock_wait_ack(smb_request_t *, uint32_t); uint32_t smb_oplock_wait_break(smb_request_t *, smb_node_t *, int); uint32_t smb_oplock_wait_break_fem(smb_node_t *, int); void smb_oplock_move(smb_node_t *, smb_ofile_t *, smb_ofile_t *); /* * Protocol-specific oplock functions * (not needed here) */ int smb_lock_range_access(smb_request_t *, smb_node_t *, uint64_t, uint64_t, boolean_t); int smb_fem_oplock_install(smb_node_t *); void smb_fem_oplock_uninstall(smb_node_t *); #ifdef __cplusplus } #endif #endif /* _SMB_KPROTO_H_ */ /* * 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) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2020 Nexenta by DDN, Inc. All rights reserved. * Copyright 2022 RackTop Systems, Inc. */ /* * Structures and type definitions needed by the "testoplock" program * (a small subset of what the SMB server uses) */ #ifndef _SMB_KTYPES_H #define _SMB_KTYPES_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include typedef struct smb_session smb_session_t; typedef struct smb_user smb_user_t; typedef struct smb_tree smb_tree_t; /* * Destructor object used in the locked-list delete queue. */ #define SMB_DTOR_MAGIC 0x44544F52 /* DTOR */ #define SMB_DTOR_VALID(d) \ ASSERT(((d) != NULL) && ((d)->dt_magic == SMB_DTOR_MAGIC)) typedef void (*smb_dtorproc_t)(void *); typedef struct smb_dtor { list_node_t dt_lnd; uint32_t dt_magic; void *dt_object; smb_dtorproc_t dt_proc; } smb_dtor_t; typedef struct smb_llist { krwlock_t ll_lock; list_t ll_list; uint32_t ll_count; uint64_t ll_wrop; kmutex_t ll_mutex; list_t ll_deleteq; uint32_t ll_deleteq_count; boolean_t ll_flushing; } smb_llist_t; /* * Per smb_node oplock state */ typedef struct smb_oplock { kmutex_t ol_mutex; boolean_t ol_fem; /* fem monitor installed? */ struct smb_ofile *excl_open; uint32_t ol_state; int32_t cnt_II; int32_t cnt_R; int32_t cnt_RH; int32_t cnt_RHBQ; int32_t waiters; kcondvar_t WaitingOpenCV; } smb_oplock_t; /* * Per smb_ofile oplock state */ typedef struct smb_oplock_grant { /* smb protocol-level state */ uint32_t og_state; /* what client has now */ uint32_t og_breakto; /* level breaking to */ boolean_t og_breaking; uint16_t og_dialect; /* how to send breaks */ kcondvar_t og_ack_cv; /* Wait for ACK */ /* File-system level state */ uint8_t onlist_II; uint8_t onlist_R; uint8_t onlist_RH; uint8_t onlist_RHBQ; uint8_t BreakingToRead; } smb_oplock_grant_t; #define SMB_LEASE_KEY_SZ 16 struct smb_lease; #define SMB_NODE_MAGIC 0x4E4F4445 /* 'NODE' */ #define SMB_NODE_VALID(p) ASSERT((p)->n_magic == SMB_NODE_MAGIC) typedef enum { SMB_NODE_STATE_AVAILABLE = 0, SMB_NODE_STATE_DESTROYING } smb_node_state_t; /* * waiting_event # of clients requesting FCN * n_timestamps cached timestamps * n_allocsz cached file allocation size * n_dnode directory node * n_unode unnamed stream node * delete_on_close_cred credentials for delayed delete */ typedef struct smb_node { list_node_t n_lnd; uint32_t n_magic; krwlock_t n_lock; kmutex_t n_mutex; smb_node_state_t n_state; uint32_t n_refcnt; uint32_t n_open_count; volatile int flags; smb_llist_t n_ofile_list; smb_oplock_t n_oplock; } smb_node_t; #define NODE_FLAGS_WRITE_THROUGH 0x00100000 #define NODE_FLAGS_DELETE_COMMITTED 0x20000000 #define NODE_FLAGS_DELETE_ON_CLOSE 0x40000000 /* * Some flags for ofile structure * * SMB_OFLAGS_SET_DELETE_ON_CLOSE * Set this flag when the corresponding open operation whose * DELETE_ON_CLOSE bit of the CreateOptions is set. If any * open file instance has this bit set, the NODE_FLAGS_DELETE_ON_CLOSE * will be set for the file node upon close. */ /* SMB_OFLAGS_READONLY 0x0001 (obsolete) */ #define SMB_OFLAGS_EXECONLY 0x0002 #define SMB_OFLAGS_SET_DELETE_ON_CLOSE 0x0004 #define SMB_OFLAGS_LLF_POS_VALID 0x0008 #define SMB_OFILE_MAGIC 0x4F464C45 /* 'OFLE' */ #define SMB_OFILE_VALID(p) \ ASSERT((p != NULL) && ((p)->f_magic == SMB_OFILE_MAGIC)) /* * This is the size of the per-handle "Lock Sequence" array. * See LockSequenceIndex in [MS-SMB2] 2.2.26, and smb2_lock.c */ #define SMB_OFILE_LSEQ_MAX 64 /* {arg_open,ofile}->dh_vers values */ typedef enum { SMB2_NOT_DURABLE = 0, SMB2_DURABLE_V1, SMB2_DURABLE_V2, SMB2_RESILIENT, } smb_dh_vers_t; /* * See the long "Ofile State Machine" comment in smb_ofile.c */ typedef enum { SMB_OFILE_STATE_ALLOC = 0, SMB_OFILE_STATE_OPEN, SMB_OFILE_STATE_SAVE_DH, SMB_OFILE_STATE_SAVING, SMB_OFILE_STATE_CLOSING, SMB_OFILE_STATE_CLOSED, SMB_OFILE_STATE_ORPHANED, SMB_OFILE_STATE_RECONNECT, SMB_OFILE_STATE_EXPIRED, SMB_OFILE_STATE_SENTINEL } smb_ofile_state_t; typedef struct smb_ofile { list_node_t f_tree_lnd; /* t_ofile_list */ list_node_t f_node_lnd; /* n_ofile_list */ list_node_t f_dh_lnd; /* sv_persistid_ht */ uint32_t f_magic; kmutex_t f_mutex; smb_ofile_state_t f_state; uint16_t f_fid; uint16_t f_ftype; uint32_t f_refcnt; uint32_t f_granted_access; uint32_t f_share_access; smb_node_t *f_node; smb_oplock_grant_t f_oplock; boolean_t f_oplock_closing; uint8_t TargetOplockKey[SMB_LEASE_KEY_SZ]; uint8_t ParentOplockKey[SMB_LEASE_KEY_SZ]; struct smb_lease *f_lease; } smb_ofile_t; typedef struct smb_request { list_node_t sr_session_lnd; uint32_t sr_magic; kmutex_t sr_mutex; } smb_request_t; #ifdef __cplusplus } #endif #endif /* _SMB_KTYPES_H */ #!/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 2017 Nexenta Systems, Inc. All rights reserved. */ /* * User-level dtrace for testoplock * Usage: dtrace -s tol.d -c ./testoplock */ #pragma D option flowindent self int trace; self int mask; /* * Trace almost everything */ pid$target:testoplock::entry { self->trace++; } /* * If traced and not masked, print entry/return */ pid$target:testoplock::entry /self->trace > 0 && self->mask == 0/ { printf("\t0x%x", arg0); printf("\t0x%x", arg1); printf("\t0x%x", arg2); printf("\t0x%x", arg3); printf("\t0x%x", arg4); printf("\t0x%x", arg5); } /* Skip the bsearch calls. */ pid$target:testoplock:xlate_nt_status:entry { self->mask++; } pid$target:testoplock:xlate_nt_status:return { self->mask--; } pid$target:testoplock::return /self->trace > 0 && self->mask == 0/ { printf("\t0x%x", arg1); } pid$target:testoplock::return { self->trace--; } /* ---------------------- */ pid$target::smb_oplock_request:entry { self->sr = arg0; self->of = arg1; self->statep = arg2; this->state = *(uint32_t *)copyin(self->statep, 4); printf(" entry state=0x%x\n", this->state); } pid$target::smb_oplock_request:return { this->sr = (userland pid`smb_request_t *)self->sr; this->state = *(uint32_t *)copyin(self->statep, 4); printf(" return state=0x%x\n", this->state); printf("\nsr->arg.open = "); print(this->sr->arg.open); } pid$target::smb_oplock_break_cmn:entry { this->node = (userland pid`smb_node_t *)arg0; this->ofile = (userland pid`smb_ofile_t *)arg1; printf("\nnode->n_oplock = "); print(this->node->n_oplock); printf("\nofile->f_oplock = "); print(this->ofile->f_oplock); } pid$target::smb_oplock_ind_break:entry { this->ofile = (userland pid`smb_ofile_t *)arg0; printf("\nofile->f_oplock = "); print(this->ofile->f_oplock); } /* * 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 2020 Tintri by DDN, Inc. All rights reserved. * Copyright 2019 Joyent, Inc. * Copyright 2022 RackTop Systems, Inc. */ /* * Test & debug program for oplocks * * This implements a simple command reader which accepts * commands to simulate oplock events, and prints the * state changes and actions that would happen after * each event. */ #include #include #include #include #include #include #include #include #include #include extern const char *xlate_nt_status(uint32_t); #define OPLOCK_CACHE_RWH (READ_CACHING | HANDLE_CACHING | WRITE_CACHING) #define OPLOCK_TYPE (LEVEL_TWO_OPLOCK | LEVEL_ONE_OPLOCK |\ BATCH_OPLOCK | OPLOCK_LEVEL_GRANULAR) #define MAXFID 10 smb_node_t root_node, test_node; smb_ofile_t ofile_array[MAXFID]; smb_request_t test_sr; uint32_t last_ind_break_level; char cmdbuf[100]; static void run_ind_break_in_ack(smb_ofile_t *); #define BIT_DEF(name) { name, #name } struct bit_defs { uint32_t mask; const char *name; } state_bits[] = { BIT_DEF(NO_OPLOCK), BIT_DEF(BREAK_TO_NO_CACHING), BIT_DEF(BREAK_TO_WRITE_CACHING), BIT_DEF(BREAK_TO_HANDLE_CACHING), BIT_DEF(BREAK_TO_READ_CACHING), BIT_DEF(BREAK_TO_TWO_TO_NONE), BIT_DEF(BREAK_TO_NONE), BIT_DEF(BREAK_TO_TWO), BIT_DEF(BATCH_OPLOCK), BIT_DEF(LEVEL_ONE_OPLOCK), BIT_DEF(LEVEL_TWO_OPLOCK), BIT_DEF(MIXED_R_AND_RH), BIT_DEF(EXCLUSIVE), BIT_DEF(WRITE_CACHING), BIT_DEF(HANDLE_CACHING), BIT_DEF(READ_CACHING), { 0, NULL } }; /* * Helper to print flags fields */ static void print_bits32(char *label, struct bit_defs *bit, uint32_t state) { printf("%s0x%x (", label, state); while (bit->mask != 0) { if ((state & bit->mask) != 0) printf(" %s", bit->name); bit++; } printf(" )\n"); } /* * Command language: * */ const char helpstr[] = "Commands:\n" "help\t\tList commands\n" "show\t\tShow OpLock state etc.\n" "open FID\n" "close FID\n" "req FID [OplockLevel]\n" "ack FID [OplockLevel]\n" "brk-parent FID\n" "brk-open [OverWrite]\n" "brk-handle FID\n" "brk-read FID\n" "brk-write FID\n" "brk-setinfo FID [InfoClass]\n" "move FID1 FID2\n" "waiters FID [count]\n"; /* * Command handlers */ static void do_show(void) { smb_node_t *node = &test_node; smb_oplock_t *ol = &node->n_oplock; uint32_t state = ol->ol_state; smb_ofile_t *f; print_bits32(" ol_state=", state_bits, state); if (ol->excl_open != NULL) printf(" Excl=Y (FID=%d)", ol->excl_open->f_fid); else printf(" Excl=n"); printf(" cnt_II=%d cnt_R=%d cnt_RH=%d cnt_RHBQ=%d\n", ol->cnt_II, ol->cnt_R, ol->cnt_RH, ol->cnt_RHBQ); printf(" ofile_cnt=%d\n", node->n_ofile_list.ll_count); FOREACH_NODE_OFILE(node, f) { smb_oplock_grant_t *og = &f->f_oplock; printf(" fid=%d Lease=%s State=0x%x", f->f_fid, f->TargetOplockKey, /* lease */ og->og_state); if (og->og_breaking) printf(" BreakTo=0x%x", og->og_breakto); printf(" Excl=%s onlist:", (ol->excl_open == f) ? "Y" : "N"); if (og->onlist_II) printf(" II"); if (og->onlist_R) printf(" R"); if (og->onlist_RH) printf(" RH"); if (og->onlist_RHBQ) { printf(" RHBQ(to %s)", og->BreakingToRead ? "read" : "none"); } printf("\n"); } } static void do_open(int fid, char *arg2) { smb_node_t *node = &test_node; smb_ofile_t *ofile = &ofile_array[fid]; /* * Simulate an open (minimal init) */ if (ofile->f_refcnt) { printf("open fid %d already opened\n"); return; } if (arg2 != NULL) { (void) strlcpy((char *)ofile->TargetOplockKey, arg2, SMB_LEASE_KEY_SZ); } ofile->f_refcnt++; node->n_open_count++; smb_llist_insert_tail(&node->n_ofile_list, ofile); printf(" open %d OK\n", fid); } static void do_close(int fid) { smb_node_t *node = &test_node; smb_ofile_t *ofile = &ofile_array[fid]; /* * Simulate an close */ if (ofile->f_refcnt <= 0) { printf(" close fid %d already closed\n"); return; } smb_llist_enter(&node->n_ofile_list, RW_READER); mutex_enter(&node->n_oplock.ol_mutex); smb_oplock_break_CLOSE(ofile->f_node, ofile); smb_llist_remove(&node->n_ofile_list, ofile); node->n_open_count--; mutex_exit(&node->n_oplock.ol_mutex); smb_llist_exit(&node->n_ofile_list); ofile->f_refcnt--; bzero(ofile->TargetOplockKey, SMB_LEASE_KEY_SZ); printf(" close OK\n"); } static void do_req(int fid, char *arg2) { smb_ofile_t *ofile = &ofile_array[fid]; uint32_t oplock = BATCH_OPLOCK; uint32_t status; if (arg2 != NULL) oplock = strtol(arg2, NULL, 16); /* * Request an oplock */ status = smb_oplock_request(&test_sr, ofile, &oplock); if (status == 0 || status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { ofile->f_oplock.og_state = oplock; /* When no break pending, breakto=state */ ofile->f_oplock.og_breakto = oplock; ofile->f_oplock.og_breaking = B_FALSE; } printf(" req oplock fid=%d ret oplock=0x%x status=0x%x (%s)\n", fid, oplock, status, xlate_nt_status(status)); } static void do_ack(int fid, char *arg2) { smb_node_t *node = &test_node; smb_ofile_t *ofile = &ofile_array[fid]; uint32_t oplock; uint32_t status; /* Default to level in last smb_oplock_ind_break() */ oplock = last_ind_break_level; if (arg2 != NULL) oplock = strtol(arg2, NULL, 16); smb_llist_enter(&node->n_ofile_list, RW_READER); mutex_enter(&node->n_oplock.ol_mutex); ofile->f_oplock.og_breaking = 0; status = smb_oplock_ack_break(&test_sr, ofile, &oplock); if (status == 0) ofile->f_oplock.og_state = oplock; mutex_exit(&node->n_oplock.ol_mutex); smb_llist_exit(&node->n_ofile_list); if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { /* should not get this status */ printf(" ack: break fid=%d, break-in-progress\n", fid); ASSERT(0); } printf(" ack: break fid=%d, newstate=0x%x, status=0x%x (%s)\n", fid, oplock, status, xlate_nt_status(status)); run_ind_break_in_ack(ofile); } static void do_brk_parent(int fid) { smb_ofile_t *ofile = &ofile_array[fid]; uint32_t status; status = smb_oplock_break_PARENT(&test_node, ofile); printf(" brk-parent %d ret status=0x%x (%s)\n", fid, status, xlate_nt_status(status)); } static void do_brk_open(int fid, char *arg2) { smb_ofile_t *ofile = &ofile_array[fid]; uint32_t status; int disp = FILE_OPEN; if (arg2 != NULL) disp = strtol(arg2, NULL, 16); status = smb_oplock_break_OPEN(&test_node, ofile, 7, disp); printf(" brk-open %d ret status=0x%x (%s)\n", fid, status, xlate_nt_status(status)); } static void do_brk_handle(int fid) { smb_ofile_t *ofile = &ofile_array[fid]; uint32_t status; status = smb_oplock_break_HANDLE(&test_node, ofile); printf(" brk-handle %d ret status=0x%x (%s)\n", fid, status, xlate_nt_status(status)); } static void do_brk_read(int fid) { smb_ofile_t *ofile = &ofile_array[fid]; uint32_t status; status = smb_oplock_break_READ(ofile->f_node, ofile); printf(" brk-read %d ret status=0x%x (%s)\n", fid, status, xlate_nt_status(status)); } static void do_brk_write(int fid) { smb_ofile_t *ofile = &ofile_array[fid]; uint32_t status; status = smb_oplock_break_WRITE(ofile->f_node, ofile); printf(" brk-write %d ret status=0x%x (%s)\n", fid, status, xlate_nt_status(status)); } static void do_brk_setinfo(int fid, char *arg2) { smb_ofile_t *ofile = &ofile_array[fid]; uint32_t status; int infoclass = FileEndOfFileInformation; /* 20 */ if (arg2 != NULL) infoclass = strtol(arg2, NULL, 16); status = smb_oplock_break_SETINFO( &test_node, ofile, infoclass); printf(" brk-setinfo %d 0x%x ret status=0x%x (%s)\n", fid, infoclass, status, xlate_nt_status(status)); } /* * Move oplock to another FD, as specified, * or any other available open */ static void do_move(int fid, char *arg2) { smb_node_t *node = &test_node; smb_ofile_t *ofile = &ofile_array[fid]; smb_ofile_t *of2; int fid2; if (arg2 == NULL) { fprintf(stderr, "move: FID2 required\n"); return; } fid2 = atoi(arg2); if (fid2 <= 0 || fid2 >= MAXFID) { fprintf(stderr, "move: bad FID2 %d\n", fid2); return; } of2 = &ofile_array[fid2]; mutex_enter(&node->n_oplock.ol_mutex); smb_oplock_move(&test_node, ofile, of2); mutex_exit(&node->n_oplock.ol_mutex); printf(" move %d %d\n", fid, fid2); } /* * Set/clear oplock.waiters, which affects ack-break */ static void do_waiters(int fid, char *arg2) { smb_node_t *node = &test_node; smb_oplock_t *ol = &node->n_oplock; int old, new = 0; if (arg2 != NULL) new = atoi(arg2); old = ol->waiters; ol->waiters = new; printf(" waiters %d -> %d\n", old, new); } int main(int argc, char *argv[]) { smb_node_t *node = &test_node; char *cmd; char *arg1; char *arg2; char *savep; char *sep = " \t\n"; char *prompt = NULL; int fid; if (isatty(0)) prompt = "> "; mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), offsetof(smb_ofile_t, f_node_lnd)); for (fid = 0; fid < MAXFID; fid++) { smb_ofile_t *f = &ofile_array[fid]; f->f_magic = SMB_OFILE_MAGIC; mutex_init(&f->f_mutex, NULL, MUTEX_DEFAULT, NULL); f->f_fid = fid; f->f_ftype = SMB_FTYPE_DISK; f->f_node = &test_node; } for (;;) { if (prompt) { (void) fputs(prompt, stdout); (void) 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. */ (void) fputs(cmdbuf, stdout); } cmd = strtok_r(cmd, sep, &savep); if (cmd == NULL) continue; /* * Commands with no args */ if (0 == strcmp(cmd, "help")) { (void) fputs(helpstr, stdout); continue; } if (0 == strcmp(cmd, "show")) { do_show(); continue; } /* * Commands with one arg (the FID) */ arg1 = strtok_r(NULL, sep, &savep); if (arg1 == NULL) { fprintf(stderr, "%s missing arg1\n", cmd); continue; } fid = atoi(arg1); if (fid <= 0 || fid >= MAXFID) { fprintf(stderr, "%s bad FID %d\n", cmd, fid); continue; } if (0 == strcmp(cmd, "close")) { do_close(fid); continue; } if (0 == strcmp(cmd, "brk-parent")) { do_brk_parent(fid); continue; } if (0 == strcmp(cmd, "brk-handle")) { do_brk_handle(fid); continue; } if (0 == strcmp(cmd, "brk-read")) { do_brk_read(fid); continue; } if (0 == strcmp(cmd, "brk-write")) { do_brk_write(fid); continue; } /* * Commands with an (optional) arg2. */ arg2 = strtok_r(NULL, sep, &savep); if (0 == strcmp(cmd, "open")) { do_open(fid, arg2); continue; } if (0 == strcmp(cmd, "req")) { do_req(fid, arg2); continue; } if (0 == strcmp(cmd, "ack")) { do_ack(fid, arg2); continue; } if (0 == strcmp(cmd, "brk-open")) { do_brk_open(fid, arg2); continue; } if (0 == strcmp(cmd, "brk-setinfo")) { do_brk_setinfo(fid, arg2); continue; } if (0 == strcmp(cmd, "move")) { do_move(fid, arg2); continue; } if (0 == strcmp(cmd, "waiters")) { do_waiters(fid, arg2); continue; } fprintf(stderr, "%s unknown command. Try help\n", cmd); } return (0); } /* * A few functions called by the oplock code * Stubbed out, and/or just print a message. */ boolean_t smb_node_is_file(smb_node_t *node) { return (B_TRUE); } boolean_t smb_ofile_is_open(smb_ofile_t *ofile) { return (ofile->f_refcnt != 0); } int smb_lock_range_access( smb_request_t *sr, smb_node_t *node, uint64_t start, uint64_t length, boolean_t will_write) { return (0); } /* * Test code replacement for combination of: * smb_oplock_hdl_update() * smb_oplock_send_break() * * In a real server, we would send a break to the client, * and keep track (at the SMB level) whether this oplock * was obtained via a lease or an old-style oplock. */ static void test_oplock_send_break(smb_ofile_t *ofile, uint32_t NewLevel, boolean_t AckReq) { smb_oplock_grant_t *og = &ofile->f_oplock; uint32_t OldLevel; /* Skip building a message. */ if ((og->og_state & OPLOCK_LEVEL_GRANULAR) != 0) NewLevel |= OPLOCK_LEVEL_GRANULAR; OldLevel = og->og_state; og->og_breakto = NewLevel; og->og_breaking = B_TRUE; printf("*smb_oplock_send_break fid=%d " "NewLevel=0x%x, OldLevel=0x%x, AckReq=%d)\n", ofile->f_fid, NewLevel, OldLevel, AckReq); if (!AckReq) { og->og_state = NewLevel; og->og_breaking = B_FALSE; } /* Next, smb_oplock_send_break() would send a break. */ last_ind_break_level = NewLevel; } /* * Simplified version of what's in smb_srv_oplock.c */ void smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel, boolean_t AckReq, uint32_t status) { smb_oplock_grant_t *og = &ofile->f_oplock; printf("*smb_oplock_ind_break fid=%d NewLevel=0x%x," " AckReq=%d, ComplStatus=0x%x (%s)\n", ofile->f_fid, NewLevel, AckReq, status, xlate_nt_status(status)); /* * Note that the CompletionStatus from the FS level * (smb_cmn_oplock.c) encodes what kind of action we * need to take at the SMB level. */ switch (status) { case NT_STATUS_SUCCESS: case NT_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK: test_oplock_send_break(ofile, NewLevel, AckReq); break; case NT_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE: case NT_STATUS_OPLOCK_HANDLE_CLOSED: og->og_state = OPLOCK_LEVEL_NONE; og->og_breakto = OPLOCK_LEVEL_NONE; og->og_breaking = B_FALSE; break; default: ASSERT(0); break; } } /* Arrange for break_in_ack to run after ack completes. */ static uint32_t break_in_ack_NewLevel; static boolean_t break_in_ack_AckReq; static boolean_t break_in_ack_called; void smb_oplock_ind_break_in_ack(smb_request_t *sr, smb_ofile_t *ofile, uint32_t NewLevel, boolean_t AckRequired) { ASSERT(sr == &test_sr); /* Process these after ack */ ASSERT(!break_in_ack_called); break_in_ack_called = B_TRUE; break_in_ack_NewLevel = NewLevel; break_in_ack_AckReq = AckRequired; } static void run_ind_break_in_ack(smb_ofile_t *ofile) { uint32_t NewLevel; boolean_t AckReq; /* Process these after ack */ if (!break_in_ack_called) return; break_in_ack_called = B_FALSE; NewLevel = break_in_ack_NewLevel; AckReq = break_in_ack_AckReq; printf("*smb_oplock_ind_break_in_ack fid=%d NewLevel=0x%x," " AckReq=%d\n", ofile->f_fid, NewLevel, AckReq); test_oplock_send_break(ofile, NewLevel, AckReq); } uint32_t smb_oplock_wait_break(smb_request_t *sr, smb_node_t *node, int timeout) { printf("*smb_oplock_wait_break (state=0x%x)\n", node->n_oplock.ol_state); return (0); } int smb_fem_oplock_install(smb_node_t *node) { return (0); } void smb_fem_oplock_uninstall(smb_node_t *node) { } /* * There are a couple DTRACE_PROBE* in smb_cmn_oplock.c but we're * not linking with the user-level dtrace support, so just * stub these out. */ void __dtrace_fksmb___probe1(char *n, unsigned long a) { } void __dtrace_fksmb___probe2(char *n, unsigned long a, unsigned long b) { } /* * 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. */ /* * A few excerpts from smb_kutil.c */ #include #include #include #include #include #include #include /* * smb_llist_constructor * * This function initializes a locked list. */ void smb_llist_constructor( smb_llist_t *ll, size_t size, size_t offset) { rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL); mutex_init(&ll->ll_mutex, NULL, MUTEX_DEFAULT, NULL); list_create(&ll->ll_list, size, offset); list_create(&ll->ll_deleteq, sizeof (smb_dtor_t), offsetof(smb_dtor_t, dt_lnd)); ll->ll_count = 0; ll->ll_wrop = 0; ll->ll_deleteq_count = 0; ll->ll_flushing = B_FALSE; } /* * Flush the delete queue and destroy a locked list. */ void smb_llist_destructor( smb_llist_t *ll) { /* smb_llist_flush(ll); */ ASSERT(ll->ll_count == 0); ASSERT(ll->ll_deleteq_count == 0); rw_destroy(&ll->ll_lock); list_destroy(&ll->ll_list); list_destroy(&ll->ll_deleteq); mutex_destroy(&ll->ll_mutex); } void smb_llist_enter(smb_llist_t *ll, krw_t mode) { rw_enter(&ll->ll_lock, mode); } /* * Exit the list lock and process the delete queue. */ void smb_llist_exit(smb_llist_t *ll) { rw_exit(&ll->ll_lock); /* smb_llist_flush(ll); */ } /* * smb_llist_upgrade * * This function tries to upgrade the lock of the locked list. It assumes the * locked has already been entered in RW_READER mode. It first tries using the * Solaris function rw_tryupgrade(). If that call fails the lock is released * and reentered in RW_WRITER mode. In that last case a window is opened during * which the contents of the list may have changed. The return code indicates * whether or not the list was modified when the lock was exited. */ int smb_llist_upgrade( smb_llist_t *ll) { uint64_t wrop; if (rw_tryupgrade(&ll->ll_lock) != 0) { return (0); } wrop = ll->ll_wrop; rw_exit(&ll->ll_lock); rw_enter(&ll->ll_lock, RW_WRITER); return (wrop != ll->ll_wrop); } /* * smb_llist_insert_head * * This function inserts the object passed a the beginning of the list. This * function assumes the lock of the list has already been entered. */ void smb_llist_insert_head( smb_llist_t *ll, void *obj) { list_insert_head(&ll->ll_list, obj); ++ll->ll_wrop; ++ll->ll_count; } /* * smb_llist_insert_tail * * This function appends to the object passed to the list. This function assumes * the lock of the list has already been entered. * */ void smb_llist_insert_tail( smb_llist_t *ll, void *obj) { list_insert_tail(&ll->ll_list, obj); ++ll->ll_wrop; ++ll->ll_count; } /* * smb_llist_remove * * This function removes the object passed from the list. This function assumes * the lock of the list has already been entered. */ void smb_llist_remove( smb_llist_t *ll, void *obj) { list_remove(&ll->ll_list, obj); ++ll->ll_wrop; --ll->ll_count; } /* * smb_llist_get_count * * This function returns the number of elements in the specified list. */ uint32_t smb_llist_get_count( smb_llist_t *ll) { return (ll->ll_count); }