SMB3 Persistent Handles
Persistent Handles Design
Design Notes
Persistent Handles can be granted on a CREATE requesting a caching level of none or lease, but not an oplock level. Testing against Windows had revealed that while Windows does grant persistency with oplocks, overall behaviour with contenting access an oplock breaks seemed broken.
Options
-
Global persistent handles, sets
SMB2_CAP_PERSISTENT_HANDLESinSMB2-NEGPROTresponse and controls whether smbXsrv_open_global.tdb, locking.tdb and brlock.tdb are opened with newdb_open()flagDBWRAP_FLAG_PER_REC_PERSISTENT. -
Per share continuous availability, sets
SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITYinSMB2-TCONresponse.
dbwrap and ctdb
New db_open() flag DBWRAP_FLAG_PER_REC_PERSISTENT: opens a secondary pesistent
database NAME_persistent.tdb. When opening a database all existing records
from NAME_persistent.tdb are copied to NAME.tdb depending on the presence
or absence of a marker record in NAME.tdb.
New ctdb control CTDB_CONTROL_PUSH_RECORD that stores a record on all nodes in NAME.tdb.
New dbwrap_record_store() flags DBWRAP_STORE_PERSISTENT.
New ctdb_ltdb_header flags CTDB_REC_FLAG_PERSISTENT and CTDB_REC_FLAG_PERSISTENT_IN_PROGRESS.
New record header in the dbwrap_tdb.c struct dbwrap_tdb_header which stores and maintains DBWRAP_TDB_FLAG_PERSISTENT.
When fetching records, only NAME.tdb is used. When storing record data, a backup of the record data is stored in NAME_persistent.tdb.
dbwrap_ctdb store semantics:
-
DBWRAP_STORE_PERSISTENT:- store in volatile tdb with flag
CTDB_REC_FLAG_PERSISTENT_IN_PROGRESSand additional header with server_id - push-record to all volatilve tbds (without
CTDB_REC_FLAG_PERSISTENT_IN_PROGRESSstuff). Note that the local store done in the previous step has an incremented ctdb ltdb header rsn. - drop chainlock
- store with txn on persistent backup tdb
- fetch_locked_migrate loop
- store again locally without
CTDB_REC_FLAG_PERSISTENT_IN_PROGRESS
- store in volatile tdb with flag
dbwrap_ctdb fetch-locked and do-locked semantics:
- in the fetch-locked loop additionally check for
CTDB_REC_FLAG_PERSISTENT_IN_PROGRESS - if set, check for stale a server_id and either use the record after removing the server_id header, or continue the fetched-locked loop
- if
CTDB_REC_FLAG_PERSISTENTis set for a record when callingdbwrap_store_record()withoutDBWRAP_STORE_PERSISTENT, the persistent backup record is deleted.
Processing
SMB
If a SMB2-CREATE DH2Q context has the SMB2_DHANDLE_FLAG_PERSISTENT flag set,
call SMB_VFS_CREATE_FILE() with private_flags=NTCREATEX_FLAG_PERSISTENT_OPEN if
the share capabilities includes SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY and the request
requests a caching level of none or lease, but not for an oplock level.
FSA
In open_file_ntcreate() and open_directory() set fsp->op->global->persistent
based on NTCREATEX_FLAG_PERSISTENT_OPEN.
When creating, modifying or deleting a record in smbXsrv_open_global.tdb,
locking.tdb or brlock.tdb, DBWRAP_STORE_PERSISTENT is used based on a database specific logic:
-
smbXsrv_open_global.tdb:
fsp->op->global->persistent, -
locking.tdb: counter of persistent handles per share_mode_data (num_persistent),
-
brlock.tdb: loop over all locks per record counting the number of persistent locks
When processing any open and checking for incompatible opens and potential lease breaks, an existing open that is a disconnected Persistent Handle either
-
if the existing open has a RWH lease, trigger a deferred lease break and defer the new open,
-
otherwise let the new open fail with
NT_STATUS_FILE_NOT_AVAILABLE.
VFS
The role of the VFS cookie returned from SMB_VFS_DURABLE_COOKIE() and stored in
the smbXsrv_open_global.tdb record is turned from a "protective" cookie, to an
"initial handle state" cookie as we can't rely on SMB_VFS_DURABLE_DISCONNECT()
being called to update the cookie with filesystem metadata:
-
SMB_VFS_DURABLE_COOKIE(): for a Persisten HandleSMB_VFS_DURABLE_COOKIE()is only used to store some handle metadata like initial-delete-on-close, -
SMB_VFS_DURABLE_DISCONNECT(): becomes basically a no-op for for a Persisten Handle, -
SMB_VFS_DURABLE_RECONNECT(): skips the cookie filesystem validation, triggers deferred lease breaks.
Cleanup of stale Persistent Handles
cleanupd scans smbXsrv_open_global_persistent.tdb and signals the scavenger for every disconnected Persistent Handle. The scanning is done on two occasions:
-
after acquiring a cluster wide lock (glock),
-
when an smbd exits uncleanly.