summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2019-08-02 14:50:27 +0200
committerStefan Metzmacher <metze@samba.org>2019-09-09 16:04:29 +0000
commitc4d7c186aca3b9fb42354ac47f10514468b4c8b7 (patch)
treec7237f41a0d7024b0144d6cdd9e4bb95a493d9cb
parent061b60353d76ac368f7e48df9fe7fb899f7a2642 (diff)
downloadsamba-c4d7c186aca3b9fb42354ac47f10514468b4c8b7.tar.gz
s3:smb2_lock: add retry for POSIX locks
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Volker Lendecke <vl@samba.org> (cherry picked from commit 8decf41bbb8be2b4ac463eb6ace16a8628276ab5)
-rw-r--r--selftest/knownfail.d/smb2.localposixlock1
-rw-r--r--source3/smbd/smb2_lock.c55
2 files changed, 55 insertions, 1 deletions
diff --git a/selftest/knownfail.d/smb2.localposixlock b/selftest/knownfail.d/smb2.localposixlock
deleted file mode 100644
index 1b84f074e0b..00000000000
--- a/selftest/knownfail.d/smb2.localposixlock
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.smb2.samba3misc.localposixlock1
diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c
index a8ccf21cc20..8ba54fe6995 100644
--- a/source3/smbd/smb2_lock.c
+++ b/source3/smbd/smb2_lock.c
@@ -43,6 +43,7 @@ struct smbd_smb2_lock_state {
struct smb_request *smb1req;
struct files_struct *fsp;
bool blocking;
+ uint32_t polling_msecs;
uint16_t lock_count;
struct smbd_lock_element *locks;
};
@@ -371,6 +372,32 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
return req;
}
+static void smbd_smb2_lock_update_polling_msecs(
+ struct smbd_smb2_lock_state *state)
+{
+ /*
+ * The default lp_lock_spin_time() is 200ms.
+ *
+ * v_min is in the range of 0.002 to 20 secs
+ * (0.2 secs by default)
+ *
+ * v_max is in the range of 0.02 to 200 secs
+ * (2.0 secs by default)
+ *
+ * The typical steps are:
+ * 0.2, 0.4, 0.6, 0.8, ... 2.0
+ */
+ uint32_t v_min = MAX(2, MIN(20000, lp_lock_spin_time()));
+ uint32_t v_max = 10 * v_min;
+
+ if (state->polling_msecs >= v_max) {
+ state->polling_msecs = v_max;
+ return;
+ }
+
+ state->polling_msecs += v_min;
+}
+
static void smbd_smb2_lock_try(struct tevent_req *req)
{
struct smbd_smb2_lock_state *state = tevent_req_data(
@@ -381,6 +408,7 @@ static void smbd_smb2_lock_try(struct tevent_req *req)
uint64_t blocking_smblctx;
NTSTATUS status;
struct tevent_req *subreq = NULL;
+ struct timeval endtime = { 0 };
lck = get_existing_share_mode_lock(
talloc_tos(), state->fsp->file_id);
@@ -426,6 +454,15 @@ static void smbd_smb2_lock_try(struct tevent_req *req)
return;
}
+ if (blocking_smblctx == UINT64_MAX) {
+ smbd_smb2_lock_update_polling_msecs(state);
+
+ DBG_DEBUG("Blocked on a posix lock. Retry in %"PRIu32" msecs\n",
+ state->polling_msecs);
+
+ endtime = timeval_current_ofs_msec(state->polling_msecs);
+ }
+
DBG_DEBUG("Watching share mode lock\n");
subreq = dbwrap_watched_watch_send(
@@ -435,6 +472,18 @@ static void smbd_smb2_lock_try(struct tevent_req *req)
return;
}
tevent_req_set_callback(subreq, smbd_smb2_lock_retry, req);
+
+ if (!timeval_is_zero(&endtime)) {
+ bool ok;
+
+ ok = tevent_req_set_endtime(subreq,
+ state->ev,
+ endtime);
+ if (!ok) {
+ tevent_req_oom(req);
+ return;
+ }
+ }
}
static void smbd_smb2_lock_retry(struct tevent_req *subreq)
@@ -457,6 +506,12 @@ static void smbd_smb2_lock_retry(struct tevent_req *subreq)
status = dbwrap_watched_watch_recv(subreq, NULL, NULL);
TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ /*
+ * This is just a trigger for a timed retry.
+ */
+ status = NT_STATUS_OK;
+ }
if (tevent_req_nterror(req, status)) {
return;
}