[SCM] Samba Shared Repository - branch v4-21-test updated

Jule Anger janger at samba.org
Mon Oct 14 11:10:01 UTC 2024


The branch, v4-21-test has been updated
       via  84c6a02adc4 s3:smbd: avoid false positives for got_oplock and have_other_lease in delay_for_oplock_fn
       via  bd13b39b6de s3:smbd: allow reset_share_mode_entry() to handle more than one durable handle
       via  fb406446b95 s3:smbd: let durable_reconnect_fn already check for a disconnected handle with the correct file_id
       via  da144e3cf5c s4:torture/smb2: add smb2.durable-v2-open.{keep,purge}-disconnected-* tests
       via  710dc5dca50 s4:torture/smb2: add smb2.durable-v2-open.{[non]stat[RH]-and,two-same,two-different}-lease
       via  97542f40947 s3:smbd: only store durable handles with byte range locks when having WRITE lease
       via  ceb5bbc7e30 s4:torture/smb2: add smb2.durable-v2-open.lock-{oplock,lease,noW-lease}
       via  1d97e7cc2cf s4:torture/smb2: add smb2.durable-open.lock-noW-lease
       via  7d158ba707f s4:torture/smb2: improve error handling in durable_v2_open.c
       via  706b26c88b5 s4:torture/smb2: improve error handling in durable_open.c
      from  66a21e46d0b system_mitkrb5: require 1.16 as we use ENCTYPE_AES256_CTS_HMAC_SHA384_192

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-21-test


- Log -----------------------------------------------------------------
commit 84c6a02adc4e0ee39cd8b02a953592f1a30f3630
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Aug 30 14:16:12 2024 +0200

    s3:smbd: avoid false positives for got_oplock and have_other_lease in delay_for_oplock_fn
    
    stat opens should not cause a oplock/lease downgrade if
    they don't have a lease attached to itself.
    
    Note that opens broken to NONE still count if they are
    non-stat opens...
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Thu Oct 10 13:59:18 UTC 2024 on atb-devel-224
    
    (cherry picked from commit dd5b9e08c7a98c54b62d3b097c75faa09cd17da7)
    
    Autobuild-User(v4-21-test): Jule Anger <janger at samba.org>
    Autobuild-Date(v4-21-test): Mon Oct 14 11:09:14 UTC 2024 on atb-devel-224

commit bd13b39b6de06e20808425a31a1aace9871c776c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Aug 29 18:43:14 2024 +0200

    s3:smbd: allow reset_share_mode_entry() to handle more than one durable handle
    
    This means that multiple durable handles with RH leases can
    co-exist now... Before only the last remaining durable handle
    was able to pass the SMB_VFS_DURABLE_DISCONNECT() step.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit b1e5f5d8d2852b66ca4c858d14d367ffe228a88d)

commit fb406446b9574198cfa90e69981829fe550814cf
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Aug 29 20:20:23 2024 +0200

    s3:smbd: let durable_reconnect_fn already check for a disconnected handle with the correct file_id
    
    We'll soon allow more than one disconnected durable handle, so
    we need to find the correct one instead of assuming only a single
    one.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 2869bd1a507e7376f0bb0ec68ed4e045b043cfdb)

commit da144e3cf5c627f5da72adb8234bb28caef95ecf
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Sep 4 18:18:43 2024 +0200

    s4:torture/smb2: add smb2.durable-v2-open.{keep,purge}-disconnected-* tests
    
    These demonstrate which durables handles are kept and which are purged
    because of various opens, writes or renames.
    
    smb2.durable-v2-open.keep-disconnected-rh-with-stat-open
    smb2.durable-v2-open.keep-disconnected-rh-with-rh-open
    smb2.durable-v2-open.keep-disconnected-rh-with-rwh-open
    smb2.durable-v2-open.keep-disconnected-rwh-with-stat-open
    
    smb2.durable-v2-open.purge-disconnected-rwh-with-rwh-open
    smb2.durable-v2-open.purge-disconnected-rwh-with-rh-open
    smb2.durable-v2-open.purge-disconnected-rh-with-share-none-open
    smb2.durable-v2-open.purge-disconnected-rh-with-write
    smb2.durable-v2-open.purge-disconnected-rh-with-rename
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15708
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 9e98cd5c7a180521026b0d73a330bdaf2c8af73a)

commit 710dc5dca507114e0c55c377cd5f5653007bc104
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Aug 28 16:48:27 2024 +0200

    s4:torture/smb2: add smb2.durable-v2-open.{[non]stat[RH]-and,two-same,two-different}-lease
    
    These show that it's possible to have durable handles in addition
    of stat opens, as well as multiple durable opens with RH leases.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 77c7741f39a0a9789bede7c4722bd3f35d4af3fd)

commit 97542f40947b8815851a2cdb82aee73bb521cfef
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Aug 30 18:10:16 2024 +0200

    s3:smbd: only store durable handles with byte range locks when having WRITE lease
    
    This simplifies the reconnect assumptions, when we want to allow
    more than one durable handle on a file for multiple clients with
    READ+HANDLE leases.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 0893ae88180137d44f17196234f657d362543ff5)

commit ceb5bbc7e306727b3c7d1214b7548614f5dd7444
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Aug 30 17:38:02 2024 +0200

    s4:torture/smb2: add smb2.durable-v2-open.lock-{oplock,lease,noW-lease}
    
    This demonstrates that a W lease is required for a
    durable handle to be durable when it has byte range locks.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 8884d617310b47375e38c0386433c5e183703454)

commit 1d97e7cc2cf5308a1bd4d2b114ee45a7f8fc4645
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Aug 30 17:38:02 2024 +0200

    s4:torture/smb2: add smb2.durable-open.lock-noW-lease
    
    This demonstrates that a W lease is required for a
    durable handle to be durable when it has byte range locks.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 1cc1586d84a65046ab7804f17297c6964bb76c23)

commit 7d158ba707f56c159676ab0ba92189ae15fff3cc
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Aug 30 14:22:24 2024 +0200

    s4:torture/smb2: improve error handling in durable_v2_open.c
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 9b2417c2f04857709c25e3665cd783a68edf0cf2)

commit 706b26c88b516fe397358305169f980841bf26f1
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Aug 30 14:22:24 2024 +0200

    s4:torture/smb2: improve error handling in durable_open.c
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15649
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15651
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit e65e1326a0214a7dfff75ea1e528e82c8fc64517)

-----------------------------------------------------------------------

Summary of changes:
 selftest/knownfail                                 |    1 -
 selftest/knownfail.d/smb2.durable-v2-open.bug15708 |    7 +
 source3/locking/share_mode_lock.c                  |  315 ++-
 source3/smbd/durable.c                             |   35 +-
 source3/smbd/open.c                                |   26 +-
 source4/torture/smb2/durable_open.c                |  136 +-
 source4/torture/smb2/durable_v2_open.c             | 2990 +++++++++++++++++++-
 7 files changed, 3430 insertions(+), 80 deletions(-)
 create mode 100644 selftest/knownfail.d/smb2.durable-v2-open.bug15708


Changeset truncated at 500 lines:

diff --git a/selftest/knownfail b/selftest/knownfail
index 03f8b466994..31e70a1a9d3 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -218,7 +218,6 @@
 ^samba3.smb2.compound.interim2 # wrong return code (STATUS_CANCELLED)
 ^samba3.smb2.compound.aio.interim2 # wrong return code (STATUS_CANCELLED)
 ^samba3.smb2.lock.*replay_broken_windows # This tests the windows behaviour
-^samba3.smb2.lease.statopen3
 ^samba3.smb2.lease.unlink # we currently do not downgrade RH lease to R after unlink
 ^samba4.smb2.ioctl.compress_notsup.*\(ad_dc_ntvfs\)
 ^samba3.raw.session.*reauth2 # maybe fix this?
diff --git a/selftest/knownfail.d/smb2.durable-v2-open.bug15708 b/selftest/knownfail.d/smb2.durable-v2-open.bug15708
new file mode 100644
index 00000000000..3a6380c6d65
--- /dev/null
+++ b/selftest/knownfail.d/smb2.durable-v2-open.bug15708
@@ -0,0 +1,7 @@
+#
+# https://bugzilla.samba.org/show_bug.cgi?id=15708 is not fixed
+# yet, it requires some complex changes within handle_share_mode_lease()
+# merging logic of open_mode_check() and delay_for_oplock()...
+#
+^samba3.smb2.durable-v2-open.keep-disconnected-rh-with-rh-open
+^samba3.smb2.durable-v2-open.keep-disconnected-rh-with-rwh-open
diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c
index 3fc7d56562a..4bbccdcd3bd 100644
--- a/source3/locking/share_mode_lock.c
+++ b/source3/locking/share_mode_lock.c
@@ -2703,16 +2703,25 @@ bool reset_share_mode_entry(
 	struct share_mode_data *d = NULL;
 	TDB_DATA key = locking_key(&id);
 	struct locking_tdb_data *ltdb = NULL;
-	struct share_mode_entry e;
+	struct share_mode_entry e = { .pid.pid = 0 };
 	struct share_mode_entry_buf e_buf;
+	size_t old_idx;
+	size_t new_idx;
+	bool found;
 	NTSTATUS status;
-	int cmp;
 	bool ret = false;
 	bool ok;
+	struct file_id_buf id_buf;
+	struct server_id_buf pid_buf1;
+	struct server_id_buf pid_buf2;
+	size_t low_idx1, low_idx2, low_num;
+	size_t mid_idx1, mid_idx2, mid_num;
+	size_t high_idx1, high_idx2, high_num;
+	TDB_DATA dbufs[4];
+	size_t num_dbufs = 0;
 
 	status = share_mode_lock_access_private_data(lck, &d);
 	if (!NT_STATUS_IS_OK(status)) {
-		struct file_id_buf id_buf;
 		/* Any error recovery possible here ? */
 		DBG_ERR("share_mode_lock_access_private_data() failed for "
 			"%s - %s\n",
@@ -2728,29 +2737,54 @@ bool reset_share_mode_entry(
 		return false;
 	}
 
-	if (ltdb->num_share_entries != 1) {
-		DBG_DEBUG("num_share_modes=%zu\n", ltdb->num_share_entries);
-		goto done;
-	}
+	DBG_DEBUG("%s - num_share_modes=%zu\n",
+		  file_id_str_buf(id, &id_buf),
+		  ltdb->num_share_entries);
 
-	ok = share_mode_entry_get(ltdb->share_entries, &e);
-	if (!ok) {
-		DBG_WARNING("share_mode_entry_get failed\n");
+	new_idx = share_mode_entry_find(
+		ltdb->share_entries,
+		ltdb->num_share_entries,
+		new_pid,
+		new_share_file_id,
+		&e,
+		&found);
+	if (found) {
+		DBG_ERR("%s - num_share_modes=%zu "
+			"found NEW[%s][%"PRIu64"]\n",
+			file_id_str_buf(id, &id_buf),
+			ltdb->num_share_entries,
+			server_id_str_buf(new_pid, &pid_buf2),
+			new_share_file_id);
 		goto done;
 	}
 
-	cmp = share_mode_entry_cmp(
-		old_pid, old_share_file_id, e.pid, e.share_file_id);
-	if (cmp != 0) {
-		struct server_id_buf tmp1, tmp2;
-		DBG_WARNING("Expected pid=%s, file_id=%"PRIu64", "
-			    "got pid=%s, file_id=%"PRIu64"\n",
-			    server_id_str_buf(old_pid, &tmp1),
-			    old_share_file_id,
-			    server_id_str_buf(e.pid, &tmp2),
-			    e.share_file_id);
+	old_idx = share_mode_entry_find(
+		ltdb->share_entries,
+		ltdb->num_share_entries,
+		old_pid,
+		old_share_file_id,
+		&e,
+		&found);
+	if (!found) {
+		DBG_WARNING("%s - num_share_modes=%zu "
+			    "OLD[%s][%"PRIu64"] not found\n",
+			    file_id_str_buf(id, &id_buf),
+			    ltdb->num_share_entries,
+			    server_id_str_buf(old_pid, &pid_buf1),
+			    old_share_file_id);
 		goto done;
 	}
+	DBG_DEBUG("%s - num_share_modes=%zu "
+		  "OLD[%s][%"PRIu64"] => idx=%zu "
+		  "NEW[%s][%"PRIu64"] => idx=%zu\n",
+		  file_id_str_buf(id, &id_buf),
+		  ltdb->num_share_entries,
+		  server_id_str_buf(old_pid, &pid_buf1),
+		  old_share_file_id,
+		  old_idx,
+		  server_id_str_buf(new_pid, &pid_buf2),
+		  new_share_file_id,
+		  new_idx);
 
 	e.pid = new_pid;
 	if (new_mid != UINT64_MAX) {
@@ -2764,11 +2798,248 @@ bool reset_share_mode_entry(
 		goto done;
 	}
 
-	ltdb->share_entries = e_buf.buf;
+	/*
+	 * The logic to remove the existing
+	 * entry and add the new one at the
+	 * same time is a bit complex because
+	 * we need to keep the entries sorted.
+	 *
+	 * The following examples should catch
+	 * the corner cases and show that
+	 * the {low,mid,high}_{idx1,num} are
+	 * correctly calculated and the new
+	 * entry is put before or after the mid
+	 * elements...
+	 *
+	 * 1.
+	 *    0
+	 *    1
+	 *    2  <- old_idx
+	 *          new_idx -> 3
+	 *    3
+	 *    4
+	 *
+	 *    low_idx1 = 0;
+	 *    low_idx2 = MIN(old_idx, new_idx);  => 2
+	 *    low_num = low_idx2 - low_idx1; => 2
+	 *
+	 *    if (new < old) => new; => no
+	 *
+	 *    mid_idx1 = MIN(old_idx+1, new_idx); => 3
+	 *    mid_idx2 = MAX(old_idx, new_idx); => 3
+	 *    mid_num = mid_idx2 - mid_idx1; => 0
+	 *
+	 *    if (new >= old) => new; => yes
+	 *
+	 *    high_idx1 = MAX(old_idx+1, new_idx); => 3
+	 *    high_idx2 = num_share_entries; => 5
+	 *    high_num = high_idx2 - high_idx1 = 2
+	 *
+	 * 2.
+	 *    0
+	 *    1
+	 *          new_idx -> 2
+	 *    2  <- old_idx
+	 *    3
+	 *    4
+	 *
+	 *    low_idx1 = 0;
+	 *    low_idx2 = MIN(old_idx, new_idx);  => 2
+	 *    low_num = low_idx2 - low_idx1; => 2
+	 *
+	 *    if (new < old) => new; => no
+	 *
+	 *    mid_idx1 = MIN(old_idx+1, new_idx); => 2
+	 *    mid_idx2 = MAX(old_idx, new_idx); => 2
+	 *    mid_num = mid_idx2 - mid_idx1; => 0
+	 *
+	 *    if (new >= old) => new; => yes
+	 *
+	 *    high_idx1 = MAX(old_idx+1, new_idx); => 3
+	 *    high_idx2 = num_share_entries; => 5
+	 *    high_num = high_idx2 - high_idx1 = 2
+	 *
+	 * 3.
+	 *    0
+	 *    1  <- old_idx
+	 *    2
+	 *          new_idx -> 3
+	 *    3
+	 *    4
+	 *
+	 *    low_idx1 = 0;
+	 *    low_idx2 = MIN(old_idx, new_idx);  => 1
+	 *    low_num = low_idx2 - low_idx1; => 1
+	 *
+	 *    if (new < old) => new; => no
+	 *
+	 *    mid_idx1 = MIN(old_idx+1, new_idx); => 2
+	 *    mid_idx2 = MAX(old_idx, new_idx); => 3
+	 *    mid_num = mid_idx2 - mid_idx1; => 1
+	 *
+	 *    if (new >= old) => new; => yes
+	 *
+	 *    high_idx1 = MAX(old_idx+1, new_idx); => 3
+	 *    high_idx2 = num_share_entries; => 5
+	 *    high_num = high_idx2 - high_idx1 = 2
+	 *
+	 * 4.
+	 *    0
+	 *          new_idx -> 1
+	 *    1
+	 *    2
+	 *    3  <- old_idx
+	 *    4
+	 *
+	 *    low_idx1 = 0;
+	 *    low_idx2 = MIN(old_idx, new_idx);  => 1
+	 *    low_num = low_idx2 - low_idx1; => 1
+	 *
+	 *    if (new < old) => new; => yes
+	 *
+	 *    mid_idx1 = MIN(old_idx+1, new_idx); => 1
+	 *    mid_idx2 = MAX(old_idx, new_idx); => 3
+	 *    mid_num = mid_idx2 - mid_idx1; => 2
+	 *
+	 *    if (new >= old) => new; => no
+	 *
+	 *    high_idx1 = MAX(old_idx+1, new_idx); => 4
+	 *    high_idx2 = num_share_entries; => 5
+	 *    high_num = high_idx2 - high_idx1 = 1
+	 *
+	 * 5.
+	 *          new_idx -> 0
+	 *    0
+	 *    1
+	 *    2
+	 *    3
+	 *    4  <- old_idx
+	 *
+	 *    low_idx1 = 0;
+	 *    low_idx2 = MIN(old_idx, new_idx);  => 0
+	 *    low_num = low_idx2 - low_idx1; => 0
+	 *
+	 *    if (new < old) => new; => yes
+	 *
+	 *    mid_idx1 = MIN(old_idx+1, new_idx); => 0
+	 *    mid_idx2 = MAX(old_idx, new_idx); => 4
+	 *    mid_num = mid_idx2 - mid_idx1; => 4
+	 *
+	 *    if (new >= old) => new; => no
+	 *
+	 *    high_idx1 = MAX(old_idx+1, new_idx); => 5
+	 *    high_idx2 = num_share_entries; => 5
+	 *    high_num = high_idx2 - high_idx1 = 0
+	 *
+	 * 6.
+	 *          new_idx -> 0
+	 *    0 <- old_idx
+	 *
+	 *    low_idx1 = 0;
+	 *    low_idx2 = MIN(old_idx, new_idx);  => 0
+	 *    low_num = low_idx2 - low_idx1; => 0
+	 *
+	 *    if (new < old) => new; => no
+	 *
+	 *    mid_idx1 = MIN(old_idx+1, new_idx); => 0
+	 *    mid_idx2 = MAX(old_idx, new_idx); => 0
+	 *    mid_num = mid_idx2 - mid_idx1; => 0
+	 *
+	 *    if (new >= old) => new; => yes
+	 *
+	 *    high_idx1 = MAX(old_idx+1, new_idx); => 1
+	 *    high_idx2 = num_share_entries; => 1
+	 *    high_num = high_idx2 - high_idx1 = 0
+	 *
+	 * 7.
+	 *    0 <- old_idx
+	 *          new_idx -> 1
+	 *
+	 *    low_idx1 = 0;
+	 *    low_idx2 = MIN(old_idx, new_idx);  => 0
+	 *    low_num = low_idx2 - low_idx1; => 0
+	 *
+	 *    if (new < old) => new; => no
+	 *
+	 *    mid_idx1 = MIN(old_idx+1, new_idx); => 1
+	 *    mid_idx2 = MAX(old_idx, new_idx); => 1
+	 *    mid_num = mid_idx2 - mid_idx1; => 0
+	 *
+	 *    if (new >= old) => new; => yes
+	 *
+	 *    high_idx1 = MAX(old_idx+1, new_idx); => 1
+	 *    high_idx2 = num_share_entries; => 1
+	 *    high_num = high_idx2 - high_idx1 = 0
+	 */
+	low_idx1 = 0;
+	low_idx2 = MIN(old_idx, new_idx);
+	low_num = low_idx2 - low_idx1;
+	mid_idx1 = MIN(old_idx+1, new_idx);
+	mid_idx2 = MAX(old_idx, new_idx);
+	mid_num = mid_idx2 - mid_idx1;
+	high_idx1 = MAX(old_idx+1, new_idx);
+	high_idx2 = ltdb->num_share_entries;
+	high_num = high_idx2 - high_idx1;
+
+	if (low_num != 0) {
+		dbufs[num_dbufs] = (TDB_DATA) {
+			.dptr = discard_const_p(uint8_t, ltdb->share_entries) +
+				low_idx1 * SHARE_MODE_ENTRY_SIZE,
+			.dsize = low_num * SHARE_MODE_ENTRY_SIZE,
+		};
+		num_dbufs += 1;
+	}
+
+	if (new_idx < old_idx) {
+		dbufs[num_dbufs] = (TDB_DATA) {
+			.dptr = e_buf.buf, .dsize = SHARE_MODE_ENTRY_SIZE,
+		};
+		num_dbufs += 1;
+	}
+
+	if (mid_num != 0) {
+		dbufs[num_dbufs] = (TDB_DATA) {
+			.dptr = discard_const_p(uint8_t, ltdb->share_entries) +
+				mid_idx1 * SHARE_MODE_ENTRY_SIZE,
+			.dsize = mid_num * SHARE_MODE_ENTRY_SIZE,
+		};
+		num_dbufs += 1;
+	}
+
+	if (new_idx >= old_idx) {
+		dbufs[num_dbufs] = (TDB_DATA) {
+			.dptr = e_buf.buf, .dsize = SHARE_MODE_ENTRY_SIZE,
+		};
+		num_dbufs += 1;
+	}
+
+	if (high_num != 0) {
+		dbufs[num_dbufs] = (TDB_DATA) {
+			.dptr = discard_const_p(uint8_t, ltdb->share_entries) +
+				high_idx1 * SHARE_MODE_ENTRY_SIZE,
+			.dsize = high_num * SHARE_MODE_ENTRY_SIZE,
+		};
+		num_dbufs += 1;
+	}
 
+	{
+		size_t i;
+		for (i=0; i<num_dbufs; i++) {
+			DBG_DEBUG("dbufs[%zu]=(%p, %zu)\n",
+				  i,
+				  dbufs[i].dptr,
+				  dbufs[i].dsize);
+		}
+	}
+
+	/*
+	 * We completely rewrite the entries...
+	 */
+	ltdb->share_entries = NULL;
+	ltdb->num_share_entries = 0;
 	d->modified = true;
 
-	status = share_mode_data_ltdb_store(d, key, ltdb, NULL, 0);
+	status = share_mode_data_ltdb_store(d, key, ltdb, dbufs, num_dbufs);
 	if (!NT_STATUS_IS_OK(status)) {
 		DBG_ERR("share_mode_data_ltdb_store failed: %s\n",
 			nt_errstr(status));
diff --git a/source3/smbd/durable.c b/source3/smbd/durable.c
index dfb87dd3775..bd0c9f58e24 100644
--- a/source3/smbd/durable.c
+++ b/source3/smbd/durable.c
@@ -173,6 +173,12 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
 		return NT_STATUS_NOT_SUPPORTED;
 	}
 
+	if (fsp->current_lock_count != 0 &&
+	    (fsp_lease_type(fsp) & SMB2_LEASE_WRITE) == 0)
+	{
+		return NT_STATUS_NOT_SUPPORTED;
+	}
+
 	/*
 	 * For now let it be simple and do not keep
 	 * delete on close files durable open
@@ -500,19 +506,33 @@ static bool vfs_default_durable_reconnect_check_stat(
 	return true;
 }
 
+struct durable_reconnect_state {
+	struct smbXsrv_open *op;
+	struct share_mode_entry *e;
+};
+
 static bool durable_reconnect_fn(
 	struct share_mode_entry *e,
 	bool *modified,
 	void *private_data)
 {
-	struct share_mode_entry *dst_e = private_data;
+	struct durable_reconnect_state *state = private_data;
+	uint64_t id = state->op->global->open_persistent_id;
 
-	if (dst_e->pid.pid != 0) {
+	if (e->share_file_id != id) {
+		return false; /* Look at potential other entries */
+	}
+
+	if (!server_id_is_disconnected(&e->pid)) {
+		return false; /* Look at potential other entries */
+	}
+
+	if (state->e->share_file_id == id) {
 		DBG_INFO("Found more than one entry, invalidating previous\n");
-		dst_e->pid.pid = 0;
+		*state->e = (struct share_mode_entry) { .pid = { .pid = 0, }};
 		return true;	/* end the loop through share mode entries */
 	}
-	*dst_e = *e;
+	*state->e = *e;
 	return false;		/* Look at potential other entries */
 }
 
@@ -527,7 +547,8 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
 	const struct loadparm_substitution *lp_sub =
 		loadparm_s3_global_substitution();
 	struct share_mode_lock *lck;
-	struct share_mode_entry e;
+	struct share_mode_entry e = { .pid = { .pid = 0, }};
+	struct durable_reconnect_state rstate = { .op = op, .e = &e, };
 	struct files_struct *fsp = NULL;
 	NTSTATUS status;
 	bool ok;
@@ -620,9 +641,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
 		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 	}
 
-	e = (struct share_mode_entry) { .pid.pid = 0 };
-
-	ok = share_mode_forall_entries(lck, durable_reconnect_fn, &e);
+	ok = share_mode_forall_entries(lck, durable_reconnect_fn, &rstate);
 	if (!ok) {
 		DBG_WARNING("share_mode_forall_entries failed\n");
 		status = NT_STATUS_INTERNAL_DB_ERROR;
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index bc4dcd67e02..22a39ac35ef 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -2464,7 +2464,7 @@ struct delay_for_oplock_state {
 	bool first_open_attempt;
 	bool got_handle_lease;
 	bool got_oplock;
-	bool have_other_lease;
+	bool disallow_write_lease;
 	uint32_t total_lease_types;
 	bool delay;
 	struct blocker_debug_state *blocker_debug_state;
@@ -2572,15 +2572,27 @@ static bool delay_for_oplock_fn(
 	}
 
 	if (!state->got_oplock &&
+	    (e->op_type != NO_OPLOCK) &&
 	    (e->op_type != LEASE_OPLOCK) &&
 	    !share_entry_stale_pid(e)) {
 		state->got_oplock = true;
 	}
 
-	if (!state->have_other_lease &&
+	/*
+	 * Two things prevent a write lease
+	 * to be granted:
+	 *
+	 * 1. Any oplock or lease (even broken to NONE)
+	 * 2. An open with an access mask other than
+	 *    FILE_READ_ATTRIBUTES, FILE_WRITE_ATTRIBUTES
+	 *    or SYNCHRONIZE_ACCESS
+	 */
+	if (!state->disallow_write_lease &&
+	    (e->op_type != NO_OPLOCK || !is_oplock_stat_open(e->access_mask)) &&
 	    !is_same_lease(fsp, e, lease) &&
-	    !share_entry_stale_pid(e)) {
-		state->have_other_lease = true;
+	    !share_entry_stale_pid(e))
+	{
+		state->disallow_write_lease = true;
 	}
 


-- 
Samba Shared Repository



More information about the samba-cvs mailing list