summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <gwr@racktopsystems.com>2022-02-23 09:25:16 -0500
committerToomas Soome <tsoome@me.com>2022-12-14 00:03:52 +0200
commit7f6a299e282ed51917878b84744774a6634e5dc6 (patch)
treed86a52cd10c6433fc30ec9602adeb727c22ed97b
parent72b35b0568511bf35ca88532dff910dc0f16847f (diff)
downloadillumos-joyent-7f6a299e282ed51917878b84744774a6634e5dc6.tar.gz
15210 smbtorture lease and oplock failures
Reviewed by: Joyce McIntosh <jmcintosh@racktopsystems.com> Reviewed by: Andy Stormont <andyjstormont@gmail.com> Reviewed by: Matt Barden <mbarden@racktopsystems.com> Approved by: Dan McDonald <danmcd@mnx.io>
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case01.ref9
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case02.ref9
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case03.ref6
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case04.ref6
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case05.ref33
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case06.ref23
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case07.ref6
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case08.ref15
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case09.ref10
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case10.ref10
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case11.ref11
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case12.ref34
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case12.txt7
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case13.ref24
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case13.txt2
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case14.ref66
-rw-r--r--usr/src/cmd/smbsrv/testoplock/case14.txt51
-rw-r--r--usr/src/cmd/smbsrv/testoplock/smbsrv/smb_kproto.h2
-rw-r--r--usr/src/cmd/smbsrv/testoplock/smbsrv/smb_ktypes.h10
-rw-r--r--usr/src/cmd/smbsrv/testoplock/tol_main.c123
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_lease.c68
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_oplock.c13
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_cmn_oplock.c86
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_oplock.c11
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c117
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h2
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h12
27 files changed, 525 insertions, 241 deletions
diff --git a/usr/src/cmd/smbsrv/testoplock/case01.ref b/usr/src/cmd/smbsrv/testoplock/case01.ref
index 6327c46b7e..f7bf8e0773 100644
--- a/usr/src/cmd/smbsrv/testoplock/case01.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case01.ref
@@ -6,15 +6,16 @@ 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= OgState=0x400 Brk=0x0 Excl=Y onlist:
+ 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= OgState=0x400 Brk=0x100000 Excl=Y onlist:
+ fid=1 Lease= State=0x400 BreakTo=0x100 Excl=Y onlist:
ack 1
ack: break fid=1, newstate=0x100, status=0x0 (SUCCESS)
open 2
@@ -25,5 +26,5 @@ 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= OgState=0x100 Brk=0x0 Excl=N onlist: II
- fid=2 Lease= OgState=0x100 Brk=0x0 Excl=N onlist: II
+ fid=1 Lease= State=0x100 Excl=N onlist: II
+ fid=2 Lease= State=0x100 Excl=N onlist: II
diff --git a/usr/src/cmd/smbsrv/testoplock/case02.ref b/usr/src/cmd/smbsrv/testoplock/case02.ref
index 73488cbf27..ef251aafd5 100644
--- a/usr/src/cmd/smbsrv/testoplock/case02.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case02.ref
@@ -6,15 +6,16 @@ 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= OgState=0x807 Brk=0x0 Excl=Y onlist:
+ 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= OgState=0x807 Brk=0x30000 Excl=Y onlist:
+ fid=1 Lease= State=0x807 BreakTo=0x803 Excl=Y onlist:
ack 1
ack: break fid=1, newstate=0x803, status=0x0 (SUCCESS)
open 2
@@ -25,5 +26,5 @@ 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= OgState=0x803 Brk=0x0 Excl=N onlist: RH
- fid=2 Lease= OgState=0x803 Brk=0x0 Excl=N onlist: RH
+ fid=1 Lease= State=0x803 Excl=N onlist: RH
+ fid=2 Lease= State=0x803 Excl=N onlist: RH
diff --git a/usr/src/cmd/smbsrv/testoplock/case03.ref b/usr/src/cmd/smbsrv/testoplock/case03.ref
index cdc7fe0089..0549760a2c 100644
--- a/usr/src/cmd/smbsrv/testoplock/case03.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case03.ref
@@ -6,7 +6,7 @@ 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 OgState=0x803 Brk=0x0 Excl=N onlist: RH
+ fid=1 Lease=3 State=0x803 Excl=N onlist: RH
open 2 3
open 2 OK
req 2 0x803
@@ -16,5 +16,5 @@ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=2 Lease=3 OgState=0x803 Brk=0x0 Excl=N onlist: RH
+ fid=1 Lease=3 State=0x0 Excl=N onlist:
+ fid=2 Lease=3 State=0x803 Excl=N onlist: RH
diff --git a/usr/src/cmd/smbsrv/testoplock/case04.ref b/usr/src/cmd/smbsrv/testoplock/case04.ref
index 32df3767a9..c7eed6cafb 100644
--- a/usr/src/cmd/smbsrv/testoplock/case04.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case04.ref
@@ -6,7 +6,7 @@ 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 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ fid=1 Lease=3 State=0x801 Excl=N onlist: R
open 2 3
open 2 OK
req 2 0x801
@@ -16,5 +16,5 @@ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=2 Lease=3 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ fid=1 Lease=3 State=0x0 Excl=N onlist:
+ fid=2 Lease=3 State=0x801 Excl=N onlist: R
diff --git a/usr/src/cmd/smbsrv/testoplock/case05.ref b/usr/src/cmd/smbsrv/testoplock/case05.ref
index 639bf0023b..cad3575fa8 100644
--- a/usr/src/cmd/smbsrv/testoplock/case05.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case05.ref
@@ -6,7 +6,7 @@ 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 OgState=0x803 Brk=0x0 Excl=N onlist: RH
+ fid=2 Lease=4 State=0x803 Excl=N onlist: RH
open 3 4
open 3 OK
req 3 0x803
@@ -16,29 +16,30 @@ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease=4 OgState=0x803 Brk=0x0 Excl=N onlist: RH
+ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease=4 OgState=0x803 Brk=0x80000 Excl=N onlist: RHBQ(to none)
- fid=1 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease=4 OgState=0x800 Brk=0x0 Excl=N onlist:
- fid=1 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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
@@ -47,10 +48,10 @@ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease=4 OgState=0x800 Brk=0x0 Excl=N onlist:
- fid=1 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=4 Lease=4 OgState=0x803 Brk=0x0 Excl=N onlist: RH
+ 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
@@ -60,6 +61,6 @@ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease=4 OgState=0x803 Brk=0x0 Excl=N onlist: RH
- fid=1 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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:
diff --git a/usr/src/cmd/smbsrv/testoplock/case06.ref b/usr/src/cmd/smbsrv/testoplock/case06.ref
index daa69c3dd1..15a588219d 100644
--- a/usr/src/cmd/smbsrv/testoplock/case06.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case06.ref
@@ -10,17 +10,18 @@ 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 OgState=0x801 Brk=0x0 Excl=N onlist: R
- fid=2 Lease=2 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ 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 OgState=0x801 Brk=0x0 Excl=N onlist: R
- fid=2 Lease=2 OgState=0x800 Brk=0x0 Excl=N onlist:
+ 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
@@ -34,23 +35,25 @@ 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 OgState=0x801 Brk=0x0 Excl=N onlist: R
- fid=2 Lease=2 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ 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 OgState=0x800 Brk=0x0 Excl=N onlist:
- fid=2 Lease=2 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ 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 OgState=0x800 Brk=0x0 Excl=N onlist:
- fid=2 Lease=2 OgState=0x800 Brk=0x0 Excl=N onlist:
+ fid=1 Lease=1 State=0x800 Excl=N onlist:
+ fid=2 Lease=2 State=0x800 Excl=N onlist:
diff --git a/usr/src/cmd/smbsrv/testoplock/case07.ref b/usr/src/cmd/smbsrv/testoplock/case07.ref
index 11b1fa415d..0427292339 100644
--- a/usr/src/cmd/smbsrv/testoplock/case07.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case07.ref
@@ -6,7 +6,7 @@ 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 OgState=0x803 Brk=0x0 Excl=N onlist: RH
+ fid=1 Lease=3 State=0x803 Excl=N onlist: RH
open 2 3
open 2 OK
req 2 0x807
@@ -16,5 +16,5 @@ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=2 Lease=3 OgState=0x807 Brk=0x0 Excl=Y onlist:
+ fid=1 Lease=3 State=0x0 Excl=N onlist:
+ fid=2 Lease=3 State=0x807 Excl=Y onlist:
diff --git a/usr/src/cmd/smbsrv/testoplock/case08.ref b/usr/src/cmd/smbsrv/testoplock/case08.ref
index 7f28032990..1bc366958d 100644
--- a/usr/src/cmd/smbsrv/testoplock/case08.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case08.ref
@@ -6,31 +6,32 @@ 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 OgState=0x805 Brk=0x0 Excl=Y onlist:
+ 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 OgState=0x805 Brk=0x10000 Excl=Y onlist:
- fid=2 Lease=2 OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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 OgState=0x801 Brk=0x0 Excl=N onlist: R
- fid=2 Lease=2 OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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 OgState=0x801 Brk=0x0 Excl=N onlist: R
- fid=2 Lease=2 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ fid=1 Lease=1 State=0x801 Excl=N onlist: R
+ fid=2 Lease=2 State=0x801 Excl=N onlist: R
diff --git a/usr/src/cmd/smbsrv/testoplock/case09.ref b/usr/src/cmd/smbsrv/testoplock/case09.ref
index 4003b133db..9eb3e85230 100644
--- a/usr/src/cmd/smbsrv/testoplock/case09.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case09.ref
@@ -6,7 +6,7 @@ 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= OgState=0x100 Brk=0x0 Excl=N onlist: II
+ fid=1 Lease= State=0x100 Excl=N onlist: II
open 2 2
open 2 OK
brk-open 2
@@ -15,13 +15,13 @@ 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= OgState=0x100 Brk=0x0 Excl=N onlist: II
- fid=2 Lease=2 OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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= OgState=0x100 Brk=0x0 Excl=N onlist: II
- fid=2 Lease=2 OgState=0x0 Brk=0x0 Excl=N onlist:
+ fid=1 Lease= State=0x100 Excl=N onlist: II
+ fid=2 Lease=2 State=0x0 Excl=N onlist:
diff --git a/usr/src/cmd/smbsrv/testoplock/case10.ref b/usr/src/cmd/smbsrv/testoplock/case10.ref
index 9e0275d258..c3e4fdae96 100644
--- a/usr/src/cmd/smbsrv/testoplock/case10.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case10.ref
@@ -6,7 +6,7 @@ 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= OgState=0x100 Brk=0x0 Excl=N onlist: II
+ fid=1 Lease= State=0x100 Excl=N onlist: II
open 2 2
open 2 OK
brk-open 2
@@ -15,8 +15,8 @@ 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= OgState=0x100 Brk=0x0 Excl=N onlist: II
- fid=2 Lease=2 OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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
@@ -27,5 +27,5 @@ 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= OgState=0x100 Brk=0x0 Excl=N onlist: II
- fid=2 Lease=2 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ fid=1 Lease= State=0x100 Excl=N onlist: II
+ fid=2 Lease=2 State=0x801 Excl=N onlist: R
diff --git a/usr/src/cmd/smbsrv/testoplock/case11.ref b/usr/src/cmd/smbsrv/testoplock/case11.ref
index 05bae87e04..d1a88b4518 100644
--- a/usr/src/cmd/smbsrv/testoplock/case11.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case11.ref
@@ -6,11 +6,12 @@ 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 OgState=0x807 Brk=0x0 Excl=Y onlist:
+ 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)
@@ -18,13 +19,13 @@ 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 OgState=0x803 Brk=0x0 Excl=N onlist: RH
- fid=2 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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 OgState=0x803 Brk=0x0 Excl=N onlist: RH
- fid=2 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ fid=1 Lease=1 State=0x803 Excl=N onlist: RH
+ fid=2 Lease= State=0x0 Excl=N onlist:
diff --git a/usr/src/cmd/smbsrv/testoplock/case12.ref b/usr/src/cmd/smbsrv/testoplock/case12.ref
index bc36b7b6de..ebbe5d4c18 100644
--- a/usr/src/cmd/smbsrv/testoplock/case12.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case12.ref
@@ -6,11 +6,12 @@ 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 OgState=0x807 Brk=0x0 Excl=Y onlist:
+ 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
@@ -18,8 +19,8 @@ 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 OgState=0x807 Brk=0x30000 Excl=Y onlist:
- fid=2 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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
@@ -30,25 +31,28 @@ 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 OgState=0x807 Brk=0x30000 Excl=Y onlist:
- fid=2 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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
-*smb_oplock_ind_break fid=1 NewLevel=0x0, AckReq=1, ComplStatus=0x8000002e (CANNOT_GRANT_REQUESTED_OPLOCK)
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 OgState=0x803 Brk=0x80000 Excl=N onlist: RHBQ(to none)
- fid=2 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
-ack 1 0x800
- ack: break fid=1, newstate=0x800, status=0x0 (SUCCESS)
+ 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 OgState=0x800 Brk=0x0 Excl=N onlist:
- fid=2 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=3 Lease= OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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:
diff --git a/usr/src/cmd/smbsrv/testoplock/case12.txt b/usr/src/cmd/smbsrv/testoplock/case12.txt
index 23b4f63092..1cbaed4d72 100644
--- a/usr/src/cmd/smbsrv/testoplock/case12.txt
+++ b/usr/src/cmd/smbsrv/testoplock/case12.txt
@@ -20,9 +20,10 @@ show
# 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 none)
+# should get a new break ind. (RH to R) ar=1
ack 1 0x803
show
-# got break ind?
-ack 1 0x800
+# ack the second lease break (RH to R)
+# should get a new break ind. (R to none) ar=0
+ack 1 0x801
show
diff --git a/usr/src/cmd/smbsrv/testoplock/case13.ref b/usr/src/cmd/smbsrv/testoplock/case13.ref
index a35a5992ce..9dc00b5ce6 100644
--- a/usr/src/cmd/smbsrv/testoplock/case13.ref
+++ b/usr/src/cmd/smbsrv/testoplock/case13.ref
@@ -6,7 +6,7 @@ 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 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ fid=1 Lease=1 State=0x801 Excl=N onlist: R
open 2 1
open 2 OK
@@ -19,23 +19,31 @@ 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 OgState=0x0 Brk=0x0 Excl=N onlist:
- fid=2 Lease=1 OgState=0x807 Brk=0x0 Excl=Y onlist:
+ 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 OgState=0x807 Brk=0x0 Excl=Y onlist:
+ 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)
@@ -43,8 +51,8 @@ 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 OgState=0x803 Brk=0x0 Excl=N onlist: RH
- fid=3 Lease=2 OgState=0x0 Brk=0x0 Excl=N onlist:
+ 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)
@@ -52,5 +60,5 @@ 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 OgState=0x803 Brk=0x0 Excl=N onlist: RH
- fid=3 Lease=2 OgState=0x801 Brk=0x0 Excl=N onlist: R
+ fid=1 Lease=1 State=0x803 Excl=N onlist: RH
+ fid=3 Lease=2 State=0x801 Excl=N onlist: R
diff --git a/usr/src/cmd/smbsrv/testoplock/case13.txt b/usr/src/cmd/smbsrv/testoplock/case13.txt
index c8d012690d..f7af15d5c9 100644
--- a/usr/src/cmd/smbsrv/testoplock/case13.txt
+++ b/usr/src/cmd/smbsrv/testoplock/case13.txt
@@ -12,6 +12,8 @@ req 2 0x807
show
move 2 1
+show
+
close 2
show
diff --git a/usr/src/cmd/smbsrv/testoplock/case14.ref b/usr/src/cmd/smbsrv/testoplock/case14.ref
new file mode 100644
index 0000000000..b019488ae9
--- /dev/null
+++ b/usr/src/cmd/smbsrv/testoplock/case14.ref
@@ -0,0 +1,66 @@
+
+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
diff --git a/usr/src/cmd/smbsrv/testoplock/case14.txt b/usr/src/cmd/smbsrv/testoplock/case14.txt
new file mode 100644
index 0000000000..685d4d3637
--- /dev/null
+++ b/usr/src/cmd/smbsrv/testoplock/case14.txt
@@ -0,0 +1,51 @@
+# 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.)
diff --git a/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_kproto.h b/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_kproto.h
index 5ecc17210a..2a7c31235a 100644
--- a/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_kproto.h
+++ b/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_kproto.h
@@ -92,7 +92,7 @@ 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 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);
diff --git a/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_ktypes.h b/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_ktypes.h
index 416c7b2ba4..95eab0f824 100644
--- a/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_ktypes.h
+++ b/usr/src/cmd/smbsrv/testoplock/smbsrv/smb_ktypes.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2020 Nexenta by DDN, Inc. All rights reserved.
- * Copyright 2021 RackTop Systems, Inc.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -96,9 +96,11 @@ typedef struct smb_oplock {
*/
typedef struct smb_oplock_grant {
/* smb protocol-level state */
- uint32_t og_state; /* latest sent to client */
- uint32_t og_breaking; /* BREAK_TO... flags */
+ 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;
@@ -109,6 +111,8 @@ typedef struct smb_oplock_grant {
#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)
diff --git a/usr/src/cmd/smbsrv/testoplock/tol_main.c b/usr/src/cmd/smbsrv/testoplock/tol_main.c
index 7691edbca3..8cc81a4343 100644
--- a/usr/src/cmd/smbsrv/testoplock/tol_main.c
+++ b/usr/src/cmd/smbsrv/testoplock/tol_main.c
@@ -36,6 +36,8 @@
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_oplock.h>
+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)
@@ -48,7 +50,7 @@ smb_request_t test_sr;
uint32_t last_ind_break_level;
char cmdbuf[100];
-extern const char *xlate_nt_status(uint32_t);
+static void run_ind_break_in_ack(smb_ofile_t *);
#define BIT_DEF(name) { name, #name }
@@ -134,16 +136,20 @@ do_show(void)
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 OgState=0x%x Brk=0x%x",
+ printf(" fid=%d Lease=%s State=0x%x",
f->f_fid,
f->TargetOplockKey, /* lease */
- f->f_oplock.og_state,
- f->f_oplock.og_breaking);
- printf(" Excl=%s onlist: %s %s %s",
- (ol->excl_open == f) ? "Y" : "N",
- og->onlist_II ? "II" : "",
- og->onlist_R ? "R" : "",
- og->onlist_RH ? "RH" : "");
+ 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 ?
@@ -224,8 +230,13 @@ do_req(int fid, char *arg2)
* Request an oplock
*/
status = smb_oplock_request(&test_sr, ofile, &oplock);
- if (status == 0)
+ 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));
}
@@ -249,18 +260,22 @@ do_ack(int fid, char *arg2)
ofile->f_oplock.og_breaking = 0;
status = smb_oplock_ack_break(&test_sr, ofile, &oplock);
- if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_SUCCESS)
+ 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
@@ -335,8 +350,8 @@ do_brk_setinfo(int fid, char *arg2)
status = smb_oplock_break_SETINFO(
&test_node, ofile, infoclass);
- printf(" brk-setinfo %d ret status=0x%x (%s)\n",
- fid, status, xlate_nt_status(status));
+ printf(" brk-setinfo %d 0x%x ret status=0x%x (%s)\n",
+ fid, infoclass, status, xlate_nt_status(status));
}
@@ -559,47 +574,35 @@ smb_lock_range_access(
/*
* Test code replacement for combination of:
* smb_oplock_hdl_update()
- * smb_oplock_send_brk()
+ * 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_brk(smb_ofile_t *ofile,
+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;
- /*
- * 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.
- *
- * This part like: smb_oplock_hdl_update()
- */
- if (AckReq) {
- uint32_t BreakTo;
-
- if ((og->og_state & OPLOCK_LEVEL_GRANULAR) != 0) {
-
- BreakTo = (NewLevel & CACHE_RWH) << BREAK_SHIFT;
- if (BreakTo == 0)
- BreakTo = BREAK_TO_NO_CACHING;
- // ls_breaking = BreakTo;
- } else {
- if ((NewLevel & LEVEL_TWO_OPLOCK) != 0)
- BreakTo = BREAK_TO_TWO;
- else
- BreakTo = BREAK_TO_NONE;
- }
- og->og_breaking = BreakTo;
- /* Set og_state in do_ack */
- } else {
+ 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;
- // If lease: ls_breaking = ...
- /* Clear og_breaking in do_ack */
+ og->og_breaking = B_FALSE;
}
/* Next, smb_oplock_send_break() would send a break. */
@@ -629,12 +632,14 @@ smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
case NT_STATUS_SUCCESS:
case NT_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK:
- test_oplock_send_brk(ofile, NewLevel, AckReq);
+ 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:
@@ -643,12 +648,42 @@ smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
}
}
+/* 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);
- smb_oplock_ind_break(ofile, NewLevel, AckRequired, STATUS_CANT_GRANT);
+
+ /* 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
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_lease.c b/usr/src/uts/common/fs/smbsrv/smb2_lease.c
index 81bf93d8fe..c440fa16c8 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_lease.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_lease.c
@@ -301,7 +301,6 @@ smb2_lease_break_ack(smb_request_t *sr)
smb_node_t *node;
smb_ofile_t *ofile;
uint32_t LeaseState;
- uint32_t BreakTo;
uint32_t status;
int rc = 0;
@@ -363,7 +362,7 @@ smb2_lease_break_ack(smb_request_t *sr)
/* Success, so have sr->fid_ofile */
ofile = sr->fid_ofile;
- if (lease->ls_breaking == 0) {
+ if (lease->ls_breaking == B_FALSE) {
/*
* This ACK is either unsolicited or too late,
* eg. we timed out the ACK and did it locally.
@@ -376,9 +375,7 @@ smb2_lease_break_ack(smb_request_t *sr)
* If the new LeaseState has any bits in excess of
* the lease state we sent in the break, error...
*/
- BreakTo = (lease->ls_breaking >> BREAK_SHIFT) &
- OPLOCK_LEVEL_CACHE_MASK;
- if ((LeaseState & ~BreakTo) != 0) {
+ if ((LeaseState & ~(lease->ls_breakto)) != 0) {
status = NT_STATUS_REQUEST_NOT_ACCEPTED;
goto errout;
}
@@ -388,16 +385,18 @@ smb2_lease_break_ack(smb_request_t *sr)
*
* Clear breaking flags before we ack,
* because ack might set those.
+ * Signal both CVs, out of paranoia.
*/
- ofile->f_oplock.og_breaking = 0;
- lease->ls_breaking = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
+ cv_broadcast(&ofile->f_oplock.og_ack_cv);
+ lease->ls_breaking = B_FALSE;
cv_broadcast(&lease->ls_ack_cv);
LeaseState |= OPLOCK_LEVEL_GRANULAR;
status = smb_oplock_ack_break(sr, ofile, &LeaseState);
ofile->f_oplock.og_state = LeaseState;
- lease->ls_state = LeaseState & CACHE_RWH;
+ lease->ls_state = LeaseState;
/* ls_epoch does not change here */
if (ofile->dh_persist)
@@ -676,7 +675,7 @@ smb2_lease_send_break(smb_request_t *sr)
* We're expecting an ACK. Wait in this thread
* so we can log clients that don't respond.
*/
- status = smb_oplock_wait_ack(sr);
+ status = smb_oplock_wait_ack(sr, NewLevel);
if (status == 0)
return;
@@ -718,14 +717,14 @@ smb2_lease_send_break(smb_request_t *sr)
/*
* Now continue like the non-lease code
*/
- ofile->f_oplock.og_breaking = 0;
- lease->ls_breaking = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
+ lease->ls_breaking = B_FALSE;
cv_broadcast(&lease->ls_ack_cv);
status = smb_oplock_ack_break(sr, ofile, &NewLevel);
ofile->f_oplock.og_state = NewLevel;
- lease->ls_state = NewLevel & CACHE_RWH;
+ lease->ls_state = NewLevel;
/* ls_epoch does not change here */
if (ofile->dh_persist)
@@ -748,7 +747,7 @@ unlock_out:
* Convert SMB2 lease request info in to internal form,
* call common oplock code, convert result to SMB2.
*
- * If necessary, "go async" here.
+ * If necessary, "go async" here (at the end).
*/
void
smb2_lease_acquire(smb_request_t *sr)
@@ -807,15 +806,18 @@ smb2_lease_acquire(smb_request_t *sr)
mutex_enter(&node->n_oplock.ol_mutex);
/*
- * Disallow downgrade
+ * MS-SMB2 3.3.5.9.8 and 3.3.5.9.11 Lease (V2) create contexts
*
- * Note that open with a lease is not allowed to turn off
- * any cache rights. If the client tries to "downgrade",
- * any bits, just return the existing lease cache bits.
+ * If the caching state requested in LeaseState of the (create ctx)
+ * is not a superset of Lease.LeaseState or if Lease.Breaking is TRUE,
+ * the server MUST NOT promote Lease.LeaseState. If the lease state
+ * requested is a superset of Lease.LeaseState and Lease.Breaking is
+ * FALSE, the server MUST request promotion of the lease state from
+ * the underlying object store to the new caching state.
*/
have = lease->ls_state & CACHE_RWH;
want = op->op_oplock_state & CACHE_RWH;
- if ((have & ~want) != 0) {
+ if ((have & ~want) != 0 || lease->ls_breaking) {
op->op_oplock_state = have |
OPLOCK_LEVEL_GRANULAR;
goto done;
@@ -840,9 +842,7 @@ smb2_lease_acquire(smb_request_t *sr)
* Try exclusive (request is RW or RWH)
*/
if ((op->op_oplock_state & WRITE_CACHING) != 0) {
- want = op->op_oplock_state & CACHE_RWH;
- if (have == want)
- goto done;
+ /* Alread checked (want & ~have) */
status = smb_oplock_request_LH(sr, ofile,
&op->op_oplock_state);
@@ -881,7 +881,7 @@ smb2_lease_acquire(smb_request_t *sr)
*/
if ((op->op_oplock_state & HANDLE_CACHING) != 0) {
want = op->op_oplock_state & CACHE_RWH;
- if (have == want)
+ if ((want & ~have) == 0)
goto done;
status = smb_oplock_request_LH(sr, ofile,
@@ -907,7 +907,7 @@ smb2_lease_acquire(smb_request_t *sr)
*/
if ((op->op_oplock_state & READ_CACHING) != 0) {
want = op->op_oplock_state & CACHE_RWH;
- if (have == want)
+ if ((want & ~have) == 0)
goto done;
status = smb_oplock_request_LH(sr, ofile,
@@ -945,11 +945,13 @@ done:
* this has to be using granular oplocks.
*/
if (NewGrant) {
- ofile->f_oplock.og_state = op->op_oplock_state;
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_state = op->op_oplock_state;
+ ofile->f_oplock.og_breakto = op->op_oplock_state;
+ ofile->f_oplock.og_breaking = B_FALSE;
lease->ls_oplock_ofile = ofile;
- lease->ls_state = op->op_oplock_state;
+ lease->ls_state = ofile->f_oplock.og_state;
+ lease->ls_breakto = ofile->f_oplock.og_breakto;
lease->ls_breaking = B_FALSE;
lease->ls_epoch++;
@@ -988,6 +990,11 @@ done:
* This ofile has a lease and is about to close.
* Called by smb_ofile_close when there's a lease.
*
+ * Note that a client may close an ofile in response to an
+ * oplock break or lease break intead of doing an Ack break,
+ * so this must wake anything that might be waiting on an ack
+ * when the last close of a lease happens.
+ *
* With leases, just one ofile on a lease owns the oplock.
* If an ofile with a lease is closed and it's the one that
* owns the oplock, try to move the oplock to another ofile
@@ -1009,6 +1016,12 @@ smb2_lease_ofile_close(smb_ofile_t *ofile)
ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
+#ifdef DEBUG
+ FOREACH_NODE_OFILE(node, o) {
+ DTRACE_PROBE1(each_ofile, smb_ofile_t *, o);
+ }
+#endif
+
/*
* If this ofile was not the oplock owner for this lease,
* we can leave things as they are.
@@ -1077,7 +1090,8 @@ smb2_lease_ofile_close(smb_ofile_t *ofile)
* Wakeup ACK waiters too.
*/
lease->ls_state = 0;
- lease->ls_breaking = 0;
+ lease->ls_breakto = 0;
+ lease->ls_breaking = B_FALSE;
cv_broadcast(&lease->ls_ack_cv);
lease->ls_oplock_ofile = NULL;
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_oplock.c b/usr/src/uts/common/fs/smbsrv/smb2_oplock.c
index 613b56dac9..0d807870bc 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_oplock.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_oplock.c
@@ -133,7 +133,7 @@ smb2_oplock_break_ack(smb_request_t *sr)
smb_llist_enter(&node->n_ofile_list, RW_READER);
mutex_enter(&node->n_oplock.ol_mutex);
- if (og->og_breaking == 0) {
+ if (og->og_breaking == B_FALSE) {
/*
* This is an unsolicited Ack. (There is no
* outstanding oplock break in progress now.)
@@ -154,7 +154,7 @@ smb2_oplock_break_ack(smb_request_t *sr)
* Clear breaking flags before we ack,
* because ack might set those.
*/
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
cv_broadcast(&ofile->f_oplock.og_ack_cv);
status = smb_oplock_ack_break(sr, ofile, &NewLevel);
@@ -355,7 +355,7 @@ smb2_oplock_send_break(smb_request_t *sr)
* We're expecting an ACK. Wait in this thread
* so we can log clients that don't respond.
*/
- status = smb_oplock_wait_ack(sr);
+ status = smb_oplock_wait_ack(sr, NewLevel);
if (status == 0)
return;
@@ -377,7 +377,7 @@ smb2_oplock_send_break(smb_request_t *sr)
smb_llist_enter(&node->n_ofile_list, RW_READER);
mutex_enter(&node->n_oplock.ol_mutex);
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
cv_broadcast(&ofile->f_oplock.og_ack_cv);
status = smb_oplock_ack_break(sr, ofile, &NewLevel);
@@ -487,8 +487,9 @@ smb2_oplock_acquire(smb_request_t *sr)
case NT_STATUS_SUCCESS:
case NT_STATUS_OPLOCK_BREAK_IN_PROGRESS:
ofile->f_oplock.og_dialect = SMB_VERS_2_002;
- ofile->f_oplock.og_state = op->op_oplock_state;
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_state = op->op_oplock_state;
+ ofile->f_oplock.og_breakto = op->op_oplock_state;
+ ofile->f_oplock.og_breaking = B_FALSE;
if (ofile->dh_persist) {
smb2_dh_update_oplock(sr, ofile);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_cmn_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_cmn_oplock.c
index 441dc59a6e..840ab49367 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_cmn_oplock.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_cmn_oplock.c
@@ -563,6 +563,12 @@ smb_oplock_req_excl(
ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
+#ifdef DEBUG
+ FOREACH_NODE_OFILE(node, o) {
+ DTRACE_PROBE1(each_ofile, smb_ofile_t *, o);
+ }
+#endif
+
/*
* Don't allow grants on closing ofiles.
*/
@@ -1063,6 +1069,12 @@ smb_oplock_req_shared(
ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
+#ifdef DEBUG
+ FOREACH_NODE_OFILE(node, o) {
+ DTRACE_PROBE1(each_ofile, smb_ofile_t *, o);
+ }
+#endif
+
/*
* Don't allow grants on closing ofiles.
*/
@@ -1601,21 +1613,10 @@ smb_oplock_ack_break(
* OplockCompletionStatus = STATUS_SUCCESS.
* (Because BreakingOplockOpen is equal to the
* passed-in Open, the operation ends at this point.)
- *
- * It should be OK to return the reduced oplock
- * (*rop = LEVEL_NONE) here and avoid the need
- * to send another oplock break. This is safe
- * because we already have an Ack of the break
- * to Level_II, and the additional break to none
- * would use AckRequired = FALSE.
- *
- * If we followed the spec here, we'd have:
- * smb_oplock_ind_break(ofile,
- * LEVEL_NONE, B_FALSE,
- * NT_STATUS_SUCCESS);
- * (Or smb_oplock_ind_break_in_ack...)
*/
- *rop = LEVEL_NONE; /* Reduced from L2 */
+ smb_oplock_ind_break_in_ack(
+ sr, ofile,
+ LEVEL_NONE, B_FALSE);
}
status = NT_STATUS_SUCCESS;
goto out;
@@ -1691,9 +1692,19 @@ smb_oplock_ack_break(
BreakToLevel = READ_CACHING;
break;
case BREAK_TO_NO_CACHING:
- default:
BreakToLevel = LEVEL_NONE;
break;
+ default:
+ ASSERT(0);
+ /* FALLTHROUGH */
+ case 0:
+ /*
+ * This can happen when we have multiple RH opens,
+ * and one of them breaks (RH to R). Happens in
+ * the smbtorture smb2.lease.v2rename test.
+ */
+ BreakToLevel = CACHE_R;
+ break;
}
/* Switch Open.Stream.Oplock.State */
@@ -1704,6 +1715,21 @@ smb_oplock_ack_break(
case (READ_CACHING|HANDLE_CACHING|BREAK_TO_READ_CACHING):
case (READ_CACHING|HANDLE_CACHING|BREAK_TO_NO_CACHING):
/*
+ * XXX: Missing from [MS-FSA]
+ *
+ * If we previously sent a break to none and the
+ * client Ack level is R instead of none, we
+ * need to send another break. We can then
+ * proceed as if we got level = none.
+ */
+ if (level == CACHE_R && BreakToLevel == LEVEL_NONE) {
+ smb_oplock_ind_break_in_ack(
+ sr, ofile,
+ LEVEL_NONE, B_FALSE);
+ level = LEVEL_NONE;
+ }
+
+ /*
* For each RHOpContext ThisContext in
* Open.Stream.Oplock.RHBreakQueue:
* If ThisContext.Open equals Open:
@@ -2001,7 +2027,11 @@ smb_oplock_ack_break(
*/
/*
- * Breaking R to none? This is like:
+ * Breaking R to none.
+ *
+ * We sent break exclusive (RWH or RW) to none and
+ * the client Ack reduces to R instead of to none.
+ * Need to send another break. This is like:
* "If BreakCacheLevel contains READ_CACHING..."
* from smb_oplock_break_cmn.
*/
@@ -2015,16 +2045,24 @@ smb_oplock_ack_break(
}
/*
- * Breaking RH to R or RH to none? This is like:
+ * Breaking RH to R or RH to none.
+ *
+ * We sent break from (RWH or RW) to (R or none),
+ * and the client Ack reduces to RH instead of none.
+ * Need to send another break. This is like:
* "If BreakCacheLevel equals HANDLE_CACHING..."
* from smb_oplock_break_cmn.
+ *
+ * Note: Windows always does break to CACHE_R here,
+ * letting another Ack and ind_break round trip
+ * take us the rest of the way from R to none.
*/
if (level == CACHE_RH &&
(BreakToLevel == CACHE_R ||
BreakToLevel == LEVEL_NONE)) {
smb_oplock_ind_break_in_ack(
sr, ofile,
- BreakToLevel, B_TRUE);
+ CACHE_R, B_TRUE);
ofile->f_oplock.BreakingToRead =
(BreakToLevel & READ_CACHING) ? 1: 0;
@@ -2331,6 +2369,12 @@ smb_oplock_break_CLOSE(smb_node_t *node, smb_ofile_t *ofile)
ASSERT(RW_READ_HELD(&node->n_ofile_list.ll_lock));
ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
+#ifdef DEBUG
+ FOREACH_NODE_OFILE(node, o) {
+ DTRACE_PROBE1(each_ofile, smb_ofile_t *, o);
+ }
+#endif
+
/*
* If Oplock.IIOplocks is not empty:
* For each Open ThisOpen in Oplock.IIOplocks:
@@ -2701,6 +2745,12 @@ smb_oplock_break_cmn(smb_node_t *node,
smb_llist_enter(&node->n_ofile_list, RW_READER);
mutex_enter(&node->n_oplock.ol_mutex);
+#ifdef DEBUG
+ FOREACH_NODE_OFILE(node, o) {
+ DTRACE_PROBE1(each_ofile, smb_ofile_t *, o);
+ }
+#endif
+
if (node->n_oplock.ol_state == 0 ||
node->n_oplock.ol_state == NO_OPLOCK)
goto out;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_oplock.c
index a3fd103fa1..58447a98f3 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c
@@ -55,7 +55,7 @@ smb1_oplock_ack_break(smb_request_t *sr, uchar_t oplock_level)
smb_llist_enter(&node->n_ofile_list, RW_READER);
mutex_enter(&node->n_oplock.ol_mutex);
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
cv_broadcast(&ofile->f_oplock.og_ack_cv);
(void) smb_oplock_ack_break(sr, ofile, &NewLevel);
@@ -189,7 +189,7 @@ smb1_oplock_send_break(smb_request_t *sr)
* We're expecting an ACK. Wait in this thread
* so we can log clients that don't respond.
*/
- status = smb_oplock_wait_ack(sr);
+ status = smb_oplock_wait_ack(sr, NewLevel);
if (status == 0)
return;
@@ -207,7 +207,7 @@ smb1_oplock_send_break(smb_request_t *sr)
smb_llist_enter(&node->n_ofile_list, RW_READER);
mutex_enter(&node->n_oplock.ol_mutex);
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
cv_broadcast(&ofile->f_oplock.og_ack_cv);
status = smb_oplock_ack_break(sr, ofile, &NewLevel);
@@ -313,8 +313,9 @@ smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok)
case NT_STATUS_OPLOCK_BREAK_IN_PROGRESS:
ofile->f_oplock.og_dialect = (level2ok) ?
NT_LM_0_12 : LANMAN2_1;
- ofile->f_oplock.og_state = op->op_oplock_state;
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_state = op->op_oplock_state;
+ ofile->f_oplock.og_breakto = op->op_oplock_state;
+ ofile->f_oplock.og_breaking = B_FALSE;
break;
case NT_STATUS_OPLOCK_NOT_GRANTED:
op->op_oplock_level = SMB_OPLOCK_NONE;
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 df917c3d0c..fbb2b51c24 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_srv_oplock.c
@@ -227,9 +227,18 @@ smb_oplock_ind_break_in_ack(smb_request_t *ack_sr, smb_ofile_t *ofile,
sr->uid_user = ofile->f_user;
smb_user_hold_internal(sr->uid_user);
}
+ if (ofile->f_lease != NULL)
+ NewLevel |= OPLOCK_LEVEL_GRANULAR;
+
sr->arg.olbrk.NewLevel = NewLevel;
sr->arg.olbrk.AckRequired = AckRequired;
+ /*
+ * Could do this in _hdl_update but this way it's
+ * visible in the dtrace fbt entry probe.
+ */
+ sr->arg.olbrk.OldLevel = ofile->f_oplock.og_breakto;
+
smb_oplock_hdl_update(sr);
if (use_postwork) {
@@ -350,14 +359,23 @@ smb_oplock_ind_break(smb_ofile_t *ofile, uint32_t NewLevel,
sr->uid_user = ofile->f_user;
smb_user_hold_internal(sr->uid_user);
}
+ if (ofile->f_lease != NULL)
+ NewLevel |= OPLOCK_LEVEL_GRANULAR;
+
sr->arg.olbrk.NewLevel = NewLevel;
sr->arg.olbrk.AckRequired = AckRequired;
sr->smb2_status = CompletionStatus;
+ /*
+ * Could do this in _hdl_update but this way it's
+ * visible in the dtrace fbt entry probe.
+ */
+ sr->arg.olbrk.OldLevel = ofile->f_oplock.og_breakto;
+
smb_oplock_hdl_update(sr);
- (void) taskq_dispatch(
- sv->sv_worker_pool,
+ /* Will call smb_oplock_send_break */
+ (void) taskq_dispatch(sv->sv_worker_pool,
smb_oplock_async_break, sr, TQ_SLEEP);
}
@@ -462,7 +480,8 @@ smb_oplock_hdl_moved(smb_ofile_t *ofile)
ls->ls_oplock_ofile = (smb_ofile_t *)&invalid_ofile;
ofile->f_oplock.og_state = 0;
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_breakto = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
}
/*
@@ -488,7 +507,8 @@ smb_oplock_hdl_closed(smb_ofile_t *ofile)
}
}
ofile->f_oplock.og_state = 0;
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_breakto = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
}
/*
@@ -499,8 +519,16 @@ smb_oplock_hdl_closed(smb_ofile_t *ofile)
* so we can make any state changes that should happen immediately.
*
* Here, keep track of what we will send to the client.
- * More importantly, if a break ack is expected, set
- * the og_breaking flags to note that fact.
+ * Saves old state in arg.olbck.OldLevel
+ *
+ * Note that because we may be in the midst of processing an
+ * smb_oplock_ack_break call here, the _breaking flag will be
+ * temporarily false, and is set true again if this ack causes
+ * another break. This makes it tricky to know when to update
+ * the epoch, which is not supposed to increment when there's
+ * already an unacknowledged break out to the client.
+ * We can recognize that by comparing ls_state vs ls_breakto.
+ * If no unacknowledged break, ls_state == ls_breakto.
*/
static void
smb_oplock_hdl_update(smb_request_t *sr)
@@ -516,36 +544,28 @@ smb_oplock_hdl_update(smb_request_t *sr)
ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
#endif
+ /* Caller sets arg.olbrk.OldLevel */
+ ofile->f_oplock.og_breakto = NewLevel;
+ ofile->f_oplock.og_breaking = B_TRUE;
if (lease != NULL) {
- sr->arg.olbrk.OldLevel = lease->ls_state;
- lease->ls_epoch++;
- NewLevel |= OPLOCK_LEVEL_GRANULAR;
- }
+ // If no unacknowledged break, update epoch.
+ if (lease->ls_breakto == lease->ls_state)
+ lease->ls_epoch++;
- if (AckReq) {
- uint32_t BreakTo;
+ lease->ls_breakto = NewLevel;
+ lease->ls_breaking = B_TRUE;
+ }
- if (lease != NULL) {
- BreakTo = (NewLevel & CACHE_RWH) << BREAK_SHIFT;
- if (BreakTo == 0)
- BreakTo = BREAK_TO_NO_CACHING;
- lease->ls_breaking = BreakTo;
- } else {
- if ((NewLevel & LEVEL_TWO_OPLOCK) != 0)
- BreakTo = BREAK_TO_TWO;
- else
- BreakTo = BREAK_TO_NONE;
- }
- ofile->f_oplock.og_breaking = BreakTo;
- /* Will update ls/og_state in ack. */
- } else {
+ if (!AckReq) {
/*
* Not expecting an Ack from the client.
* Update state immediately.
*/
ofile->f_oplock.og_state = NewLevel;
+ ofile->f_oplock.og_breaking = B_FALSE;
if (lease != NULL) {
- lease->ls_state = NewLevel & CACHE_RWH;
+ lease->ls_state = NewLevel;
+ lease->ls_breaking = B_FALSE;
}
if (ofile->dh_persist) {
smb2_dh_update_oplock(sr, ofile);
@@ -577,7 +597,8 @@ smb_oplock_close(smb_ofile_t *ofile)
smb_oplock_break_CLOSE(node, ofile);
ofile->f_oplock.og_state = 0;
- ofile->f_oplock.og_breaking = 0;
+ ofile->f_oplock.og_breakto = 0;
+ ofile->f_oplock.og_breaking = B_FALSE;
cv_broadcast(&ofile->f_oplock.og_ack_cv);
}
@@ -605,34 +626,49 @@ smb_oplock_wait_ack_cancel(smb_request_t *sr)
* Wait for an oplock break ACK to arrive. This is called after
* we've sent an oplock break or lease break to the client where
* an "Ack break" is expected back. If we get an Ack, that will
- * wake us up via smb2_oplock_break_ack or smb2_lease_break_ack,
- * which signal the CV on which we wait here.
+ * wake us up via smb2_oplock_break_ack or smb2_lease_break_ack.
+ *
+ * Wait until state reduced to NewLevel (or less).
+ * Note that in multi-break cases, we might wait here for just
+ * one ack when another has become pending, in which case the
+ * og_breakto might be a subset of NewLevel. Wait until the
+ * state field is no longer a superset of NewLevel.
*/
uint32_t
-smb_oplock_wait_ack(smb_request_t *sr)
+smb_oplock_wait_ack(smb_request_t *sr, uint32_t NewLevel)
{
smb_ofile_t *ofile = sr->fid_ofile;
smb_lease_t *lease = ofile->f_lease;
smb_node_t *node = ofile->f_node;
smb_oplock_t *ol = &node->n_oplock;
- uint32_t *brp;
- kcondvar_t *cvp;
+ uint32_t *state_p;
+ kcondvar_t *cv_p;
clock_t time, rv;
uint32_t status = 0;
smb_req_state_t srstate;
+ uint32_t wait_mask;
time = ddi_get_lbolt() +
MSEC_TO_TICK(smb_oplock_timeout_ack);
+ /*
+ * Wait on either lease state or oplock state
+ */
if (lease != NULL) {
- brp = &lease->ls_breaking;
- cvp = &lease->ls_ack_cv;
+ state_p = &lease->ls_state;
+ cv_p = &lease->ls_ack_cv;
} else {
- brp = &ofile->f_oplock.og_breaking;
- cvp = &ofile->f_oplock.og_ack_cv;
+ state_p = &ofile->f_oplock.og_state;
+ cv_p = &ofile->f_oplock.og_ack_cv;
}
/*
+ * These are all the bits that we wait to be cleared.
+ */
+ wait_mask = ~NewLevel & (CACHE_RWH |
+ LEVEL_TWO | LEVEL_ONE | LEVEL_BATCH);
+
+ /*
* Setup cancellation callback
*/
mutex_enter(&sr->sr_mutex);
@@ -642,15 +678,16 @@ smb_oplock_wait_ack(smb_request_t *sr)
}
sr->sr_state = SMB_REQ_STATE_WAITING_OLBRK;
sr->cancel_method = smb_oplock_wait_ack_cancel;
- sr->cancel_arg2 = cvp;
+ sr->cancel_arg2 = cv_p;
mutex_exit(&sr->sr_mutex);
/*
* Enter the wait loop
*/
mutex_enter(&ol->ol_mutex);
- while (*brp != 0) {
- rv = cv_timedwait(cvp, &ol->ol_mutex, time);
+
+ while ((*state_p & wait_mask) != 0) {
+ rv = cv_timedwait(cv_p, &ol->ol_mutex, time);
if (rv < 0) {
/* cv_timewait timeout */
status = NT_STATUS_CANNOT_BREAK_OPLOCK;
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index c93ecb353e..4a231051ff 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -288,7 +288,7 @@ 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 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);
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 76def803ab..f871fe76b2 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -598,8 +598,9 @@ typedef struct smb_oplock {
*/
typedef struct smb_oplock_grant {
/* smb protocol-level state */
- uint32_t og_state; /* latest sent to client */
- uint32_t og_breaking; /* BREAK_TO... flags */
+ 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 */
@@ -614,7 +615,7 @@ typedef struct smb_oplock_grant {
typedef struct smb_lease {
list_node_t ls_lnd; /* sv_lease_ht */
- kmutex_t ls_mutex;
+ kmutex_t ls_mutex; /* for ls_refcnt */
smb_llist_t *ls_bucket;
struct smb_node *ls_node;
/*
@@ -623,10 +624,11 @@ typedef struct smb_lease {
*/
void *ls_oplock_ofile;
uint32_t ls_refcnt;
- uint32_t ls_state;
- uint32_t ls_breaking; /* BREAK_TO... flags */
+ uint32_t ls_state; /* what client has now */
+ uint32_t ls_breakto; /* level breaking to */
uint16_t ls_epoch;
uint16_t ls_version;
+ boolean_t ls_breaking;
kcondvar_t ls_ack_cv; /* Wait for ACK */
uint8_t ls_key[SMB_LEASE_KEY_SZ];
uint8_t ls_clnt[SMB_LEASE_KEY_SZ];