[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