[RFC PATCH] smbd: resilient file handle support
Uri Simchoni
uri at samba.org
Thu Feb 11 21:42:23 UTC 2016
Hi,
Attached pls find a patch for supporting resilient file handles.
Comments are welcome. It doesn't include tests yet, but I would
appreciate technical feedback and any other feedback.
By and large, this patch stands on the shoulders of the durable handles
implementation. Same restrictions as with durable handles apply (durable
handles must be enabled, kernel oplocks, posix locks and kernel share
modes must be disabled).
I didn't plan this. The driver for doing this was that we've just found
out that Windows backup engine doesn't work with Samba and SMB dialect >
2.0.2 (see https://bugzilla.samba.org/show_bug.cgi?id=10159).
I don't know if I'm stepping on any toes here - I know resilient were
low priority because persistent handles are the "real deal", but it
appears that Windows backup requests resilient handles, at least when
persistent handles are not supported.
On to the technical stuff.
The patch implements resilient handles with the omission of lock
sequence verification ([MS-SMB2] 3.3.5.14), a mechanism used for
preventing the server from doing the same lock twice if it failed to ack
the first lock request because of disconnect.
From my reading of [MS-SMB2], it looks like resilient handles are very
similar to durable handles. They serve the same purpose, namely to allow
seamless (transparent to the application) immediate reconnect by a
client if the connection breaks, while keeping locks/oplocks/share modes
intact. The main difference between durable and resilient is in how they
are being set up, namely that durable handles get created by create
context, and failure to make the handle durable does not fail the open,
whereas resilient handles get created by an IOCTL, and failure is a
failure of the IOCTL, which perhaps provides better feedback to the
application.
Data Model
===========
[MS-SMB2] describes "durability" and "resiliency" of a file handle as
two distinct properties, but it immediately becomes apparent that they
are mutually exclusive - enabling Open.IsResilient automatically
disables Open.IsDurable (3.3.5.15.9). Therefore it would seem beneficial
to treat a resilient file handle as a special type of durable handle,
and observe the difference. From my reading, the functional differences
amount to the following:
a. When an oplock or lease breaks on a disconnected durable handle, the
handle must be deleted, whereas a resilient handle is not deleted. From
functional point of view it means a reconnect after oplock break fails
on a durable handle but not on a resilient handle.
b. If the dialect is SMB2.1, lock sequence verification is done only on
resilient handles.
c. When a disconnect happens, resilient handles are always being
preserved, whereas durable handles must be preserved only if specific
types of oplock or lease are granted.
With respect to a), it seems that current Samba code does not delete
durable handles on oplock break.
With respect to b), the patch does not implement lock sequence checking
at all.
With respect to c), it seems like Samba implements this by only marking
a handle as durable if it has a handle lease, but upon disconnect, it
unconditionally preserves durable handles.
It follows that no significant change is required to implement resilient
handles - the only required thing is to handle the IOCTL and "durablize"
the handle, with the timeout of the resiliency request. I could add a
"resilient" variable that would tell the difference but at this stage
this would be a write-only variable.
Conformance with [MS-SMB2]
====================
Following are places in which Open.IsResilient is mentioned and how it's
being covered.
3.3.4.6 - not delete a disconnected resilient handle on oplock break -
we never delete it.
3.3.4.7 - not delete a disconnected resilient handle on lease break - we
never delete it.
3.3.5.6 - not delete a resilient handle on logoff - covered by marking
the handle as durable.
3.3.5.9 - on CREATE, set Open.DurableFileId to a unique value - a handle
can only be resilient at create time if it's a reconnect, and in that
case the Open.DurableFileId has already been set.
3.3.5.9.7 - Handling of reconnect - same as durable.
3.3.5.9.12 - Handling of reconnectV2 - same as durable.
3.3.5.14 - Lock sequence verification - not implemented (that's a SHOULD)
3.3.5.14.1 - Updating the lock sequence array on Unlock - not
implemented (not needed since we don't verify sequence)
3.3.5.14.2 - Updating the lock sequence array on Lock - not implemented
(not needed since we don't verify sequence)
3.3.5.15.9 - Handling the resiliency request - that's the meat of this
patch, code can be carefully compared to the spec. The code essentially
"durablize" the handle, with the requested timeout.
3.3.6.4 - Resilient Open Scavenger Timer - The spec of what to do when a
handle expires is identical to durable handles. The difference is in how
timeouts are set. Our implementation of durable open scavenger is
compatible, timing-wise, with the spec.
3.3.7.1 - loss of connection, preserving a handle for reconnect -
resilient handles must be preserved. Durable handles must be preserved
only if Open.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH and
Open.OplockState is equal to Held. However, it seems like our code
always preserves durable handles, so the resilient==durable design holds
here too.
3.3.7.1 - triggering the scavenger time on loss of connection - same as
durable.
Thanks,
Uri.
-------------- next part --------------
From 1b4255b67034d7b9945814bf65364773118d44b3 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Thu, 11 Feb 2016 13:56:04 +0200
Subject: [PATCH] smbd: add support for resilent file handles
Add support for resilient file handles, with the same
restrictions as those for durable handles, and the following
omission:
1. Verifying lock sequence [MS-SMB2] 3.3.5.14 - this is listed
as SHOULD
This patch uses the durable file handle infrastructure, and
internally makes no distinction between durable and resilient
file handles - the difference is in how they are being set up.
This is so because in MS-SMB2, a handle can be durable or
resilient, but not both (see 3.3.5.15.9 - when resiliency
request is received, IsResilient is set to TRUE and IsDurable
is set to FALSE). The functional differences once the
handle is set up are:
1. When an oplock or lease breaks on a disconnected, durable
handle, the handle must be deleted, whereas a resilient
disconnected handle is not deleted (3.3.4.6 and
3.3.4.7) - in Samba a durable handle is not deleted
by an oplock break.
2. If the dialect is SMB2.1, lock sequence verification is done
only on resilient handles - at this stage lock sequence
verification is not implemented.
3. Upon disconnect, durable handles are preserved only if certain
types of oplocks/leases were granted, and resilient handles are
always preserved. Here Samba only marks a handle as durable
if it has a handle lease, but upon disconnect it
unconditionally preserves durable handles.
It follows that after Samba sets up a handle as durable, it also meets
the resilient handle spec.
---
source3/smbd/smb2_ioctl_network_fs.c | 69 ++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/source3/smbd/smb2_ioctl_network_fs.c b/source3/smbd/smb2_ioctl_network_fs.c
index d8590de..0af6c83 100644
--- a/source3/smbd/smb2_ioctl_network_fs.c
+++ b/source3/smbd/smb2_ioctl_network_fs.c
@@ -620,6 +620,67 @@ static NTSTATUS fsctl_srv_req_resume_key(TALLOC_CTX *mem_ctx,
return NT_STATUS_OK;
}
+static NTSTATUS fsctl_request_resiliency(struct smbXsrv_connection *conn,
+ struct files_struct *fsp,
+ DATA_BLOB *in_input)
+{
+ NTSTATUS status;
+ uint32_t timeout = 0;
+ struct smbXsrv_open *op = fsp->op;
+
+ /* Should we check whether fsp is NULL? */
+
+ timeout = IVAL(in_input->data, 0x00);
+ /*
+ * Maximum value should be configurable -
+ * MaxResiliencyTimeout, with a default in
+ * Windows of 300 sec according to [MS-SMB2] 3.3.3
+ */
+ if (timeout > 300 * 1000) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (op->global->backend_cookie.length == 0) {
+ status = SMB_VFS_DURABLE_COOKIE(fsp, op,
+ &op->global->backend_cookie);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ op->global->durable = true;
+
+ if (timeout == 0) {
+ /* Default - 120 sec as per Server 2012 and later
+ * according to [MS-SMB2] 3.3.5.15.9
+ */
+ timeout = 120 * 1000;
+ }
+
+ /* [MS-SMB2] defines different state variables for durable
+ * and resilient, but at the same time durable and resilient
+ * are mutually-exclusive, and the scavenging algorithm is
+ * identical.
+ * Therefore we keep the timeout in durable_timeout_msec.
+ */
+ op->global->durable_timeout_msec = timeout;
+
+ /* no need to handle durable owner - it's recorded
+ * on every open even if the handle is not durable
+ * or resilient.
+ */
+
+ status = smbXsrv_open_update(op);
+ DBG_DEBUG("smb2_create_send: smbXsrv_open_update "
+ "returned %s\n",
+ nt_errstr(status));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
static void smb2_ioctl_network_fs_copychunk_done(struct tevent_req *subreq);
struct tevent_req *smb2_ioctl_network_fs(uint32_t ctl_code,
@@ -698,6 +759,14 @@ struct tevent_req *smb2_ioctl_network_fs(uint32_t ctl_code,
}
return tevent_req_post(req, ev);
break;
+ case FSCTL_LMR_REQ_RESILIENCY:
+ status = fsctl_request_resiliency(state->smbreq->xconn,
+ state->fsp, &state->in_input);
+ if (!tevent_req_nterror(req, status)) {
+ tevent_req_done(req);
+ }
+ return tevent_req_post(req, ev);
+ break;
default: {
uint8_t *out_data = NULL;
uint32_t out_data_len = 0;
--
2.5.0
More information about the samba-technical
mailing list