Ralph Boehme [Mon, 25 Aug 2025 09:56:48 +0000 (11:56 +0200)]
smbtorture: add test "smb2.persistent-open.timeout_5"
Verify that a disconnected Persistent Handle with a timeout of 5 seconds is
reaped by the scavenger after the timeout expires, so another client can then
open the file.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Thu, 25 Sep 2025 14:59:54 +0000 (16:59 +0200)]
smbtorture: add test "smb2.persistent-open.reconnect-contended-oplock"
Persistent Handles together with oplocks are broken on Windows: eg oplocks are
"silently" downgraded from B to S when reconnecting a PH, instead of sending an
oplock break with the downgraded oplock level (cf --option=torture:subtest=7).
Samba doesn't grant Persistent Handles with oplocks at all, only with
leases or without an oplock or lease.
Skip these tests altogether, they're merely kept for historical
reference and in case this subject needs furthter exploration in the
future.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Thu, 25 Sep 2025 14:49:22 +0000 (16:49 +0200)]
smbtorture: add test "smb2.persistent-open.reconnect-contended-two"
Same as smb2.persistent-open.reconnect-contended, but with two Persistent
Handles sharing the same lease key.
Note that some tests are failing against Windows as Windows is strangely failing
to reconnect the second handle. This is being discussed with Microsoft:
Ralph Boehme [Sun, 24 Aug 2025 19:56:38 +0000 (21:56 +0200)]
smbtorture: add test "smb2.persistent-open.reconnect-contended"
This tests trying to open a file with a disconnected persistent handle
with various different lease levels, sharemodes and create disposition
combinations.
The client then disconnects and we try to open (contend) the now disconnected
Persistent Handle from the first client. This will either fail with
NT_STATUS_FILE_NOT_AVAILABLE or trigger a lease break which gets dispatched once
the first client reconnects.
The client must always be able to reconnect the disconnected open and the server
guarantees that any operations which break W or H leases are blocked.
The bottom line being:
* incompatible opens without H-lease are blocked with
NT_STATUS_FILE_NOT_AVAILABLE
* incompatible opens with a H lease trigger a lease break and are deferred until
the first client reconnects the handle
* in addition to that, if the file has byterange locks the lease must include
W, otherwise contending opens are also blocked with NT_STATUS_FILE_NOT_AVAILABLE
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Mon, 25 Aug 2025 16:48:20 +0000 (18:48 +0200)]
smbd: fail replay operation on handle that has been used
Using a handle, eg processing an SMB2_WRITE operation, removes the replay cache
record associated with open.
If the handle is a Persistent Handle, the replay must fail with
NT_STATUS_FILE_NOT_AVAILABLE in this case, whereas for a Durable Handle without
persistency, the replay would be handled as a new create.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Wed, 26 Feb 2025 16:55:57 +0000 (17:55 +0100)]
smbd: check for Persistent Handles in smbXsrv_open_global_verify_record()
Return NT_STATUS_REMOTE_DISCONNECT for a Persistent Handle if the process
doesn't exist, same error response as for a Durable Handle where the server_id
is found to be set to the special disconnected id a few lines above.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Mon, 1 Dec 2025 16:48:24 +0000 (17:48 +0100)]
scavenger: clean up stale delete-on-close tokens in the scavenger
Currently we discard Durable Handles when processing a client disconnect that
have delete-on-close set, which will then also clean up the delete-on-close
token.
This is going to change for Persistent Handles, so we have to prepare for
cleaning up delete-on-close tokens in the scavenger.
Windows takes it one step further and the file gets actually deleted: on Windows
delete-on-close in set at the FSA layer so when the scavenger closes the handle,
the filesystem will just follow standard delete-on-close processing and delete
the file.
For Samba this is hard to implement in the scavenger, as it would need to be
extended to be able talk to the Samba VFS to delete the file, so we merely
remove the stale delete-token and without deleting the file.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Factor out reset_delete_on_close_lck_internal() and then make the
existing reset_delete_on_close_lck() a wrapper around it.
No change in behaviour for reset_delete_on_close_lck().
reset_delete_on_close_lck_open_id() receives the open_persistent_id from the
smbXsrv_open_global.tdb as an additional parameter
A later commit will use reset_delete_on_close_lck_open_id() in the open
scavenging code to ensure the delete token is only removed if the open-id
matches.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Tue, 25 Nov 2025 14:58:27 +0000 (15:58 +0100)]
scavenger: update scavenger_add_timer() for Persistent Handles
With Persistent Handles global->disconnect_time might be 0 if a process or node
crashed and global->server_id won't be set to the special disconnected id.
Due to a race there might the open record might already be gone, so handle that
as well to still allow cleanup of locking.tdb and brlock.tdb records.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Fri, 29 Aug 2025 13:44:16 +0000 (15:44 +0200)]
s3/brlock: update brlock cleanup for Persistent Handles
Durable Handles don't allow byte-range locks from other opens on a file, but
Persistent Handles do allow this. Adapt brl_cleanup_disconnected() to
deal with locks from different handles.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Thu, 6 Nov 2025 13:40:41 +0000 (14:40 +0100)]
smbd: adjust get_lease_type() for Persistent Handles
If the lease record was lost due to a node outage, just return
SMB2_LEASE_NONE. Note that e->protect will only be set to true for Persistent
Handles and if the handle is currently disconnected.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Mon, 1 Dec 2025 17:03:46 +0000 (18:03 +0100)]
scavenger: pass individual args not fsp to scavenger_schedule_disconnected()
In preperation of calling scavenger_schedule_disconnected() from a
function where we don't have an fsp.
Not having an fsp also means not having access to the open record via
fsp->op->global to fetch the timeout values. Hence in the scavenger in
scavenger_add_timer() we use smbXsrv_open_global_lookup() to fetch the open
record with the timeout values.
No change in behaviour.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Sun, 30 Nov 2025 14:31:10 +0000 (15:31 +0100)]
smbd: restrict leases on CA and SO shares when filling tcon->smb_max_lease_mask
This adds the following paremetric options
smb3 ca:max lease mask = RWH (default:R, set to RWH in selftest on testshare)
smb3 ca so:max lease mask = RWH (default:R)
For now keep them as "internal" undocumented parametric options. If we learn
about real world usecases in the future, we can then look into turning them into
documented options.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Sat, 6 Dec 2025 15:26:17 +0000 (16:26 +0100)]
smbd: checking for disconnected Persistent Handles
The core of blocking access to disconnect Persistent Handles:
MS-SMB2 3.3.5.9 Receiving an SMB2 CREATE Request:
If Connection.Dialect belongs to the SMB 3.x dialect family and the request
does not contain SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context or
SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context, the server MUST look
up an existing open in the GlobalOpenTable where Open.FileName matches the
file name in the Buffer field of the request. If an Open entry is found, and
if all the following conditions are satisfied, the server SHOULD<300> fail the
request with STATUS_FILE_NOT_AVAILABLE:
- Open.IsPersistent is TRUE
- Open.Connection is NULL
If the disconnected handle has an H lease (or WH lease in case the file has
byterange locks), and the contending open triggers a lease break, we have to
"save" the lease break until the handle is reconnected.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Tue, 17 Sep 2019 16:47:52 +0000 (09:47 -0700)]
s3/locking: update share_entry_stale_pid() check for Persistent Handles
Disconnected Persistent Handles are NOT "stale" and must be preserved. But while
we're at it to check if the handle is connected or not, remember this
information so we can check this later in the open code.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Tue, 2 Dec 2025 18:44:44 +0000 (19:44 +0100)]
vfs_default: make disconnect a no-op for Persistent Handles
Basically just copy the existing initial cookie and call it a day. That way the
resulting overall disconnect/reconnect behaviour is the same for Persistent
Handles regardless of a server side process or node crash, or a TCP disconnect.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Tue, 2 Dec 2025 18:42:23 +0000 (19:42 +0100)]
vfs_default: set cookie.allow_reconnect for PH already in vfs_default_durable_cookie()
For Durable Handles we set cookie.allow_reconnect in the SMB_VFS_DISCONNECT()
implemtation, but for Persistent Handles we can't rely on SMB_VFS_DISCONNECT()
being called in case of a server side process or node failure.
The whole disconnect/reconnect logic is therefor adjusted to make
SMB_VFS_DISCONNECT() a no-op for Persistent Handles.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Tue, 30 Sep 2025 15:12:49 +0000 (17:12 +0200)]
smbd: make grant_new_fsp_lease() public and add bump_epoch
Current caller passed true which results in unchanged behaviour. However, we
will call this from durable.c when reconnecting Persistent Handle where we need
control over the exact lease version.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
Ralph Boehme [Tue, 7 Oct 2025 16:39:33 +0000 (18:39 +0200)]
s3/librpc: open_files.idl: updates for Persistent Handles
New share_mode_entry flag:
- SHARE_ENTRY_FLAG_PERSISTENT_OPEN
New share_mode_data member:
- num_persistent
New share_mode_entry members:
- create_guid
- protect
delete_token
- open_persistent_id
New vfs_default_durable_cookie members:
- initial_delete_on_close
The SHARE_ENTRY_FLAG_PERSISTENT_OPEN flag is crucially needed to modify the
behaviour of share_entry_stale_pid() and used in other places when looking at a
share_mode_entry and having to adust processing behaviour for Persistent
Handles.
num_persistent is used to track the number of Persistent Handles per
share_mode_data record, adjusting dbwrap_store() behaviour depending on its
value: if num_persistent is greater then zero, we pass DBWRAP_STORE_PERSISTENT.
Without it we would have to iterate over oll share_mode_entry's every time we
store the record.
The create_guid ties together the open state from locking.tdb and the
smbXsrv_open_global.tdb as an additional hardening to securely corolate both.
The protect boolean is an in-memory flag indicating a disconnected Persistent
Handle. We don't want to store this in the share_mode_entry on disk.
open_persistent_id in the delete_token will be used to implement scavening
delete_tokens when Persistent Handles with delete-on-close set expire. Windows
will actually delete the file, but this is not easily possible with the current
architecture of the scavenger, but we must at least correctly remove those stale
tokens.
initial_delete_on_close is used to preserve the fsp flag initial_delete_on_close
across disconnects. When reconnecting the handle, the fsp flag can be
reestablished based on the value from the cookie.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
For now keep them as "internal" undocumented parametric options. If we learn
about real world usecases in the future, we can then look into turning them into
documented options.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>
The persistent flag is the primary means of directing all FSA and SMB layer
behaviour for Persistent Handles.
The file_id is used when scanning the smbXsrv_open_global.tdb for stale opens
and scheduling cleanup via the scavenger: scavenger uses the file-id from the
open to fetch the file record from locking.tdb.
name_hash will be used as part of implementing delete-on-close token cleanup via
the scavenger.
app_instance_vhigh and app_instance_vlow are part of the app_instance_id related
feature.
Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Anoop C S <anoopcs@samba.org>