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 <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    
    Autobuild-User(master): Stefan Metzmacher <[email protected]>
    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 <[email protected]>
    Autobuild-Date(v4-21-test): Mon Oct 14 11:09:14 UTC 2024 on atb-devel-224

commit bd13b39b6de06e20808425a31a1aace9871c776c
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit b1e5f5d8d2852b66ca4c858d14d367ffe228a88d)

commit fb406446b9574198cfa90e69981829fe550814cf
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit 2869bd1a507e7376f0bb0ec68ed4e045b043cfdb)

commit da144e3cf5c627f5da72adb8234bb28caef95ecf
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit 9e98cd5c7a180521026b0d73a330bdaf2c8af73a)

commit 710dc5dca507114e0c55c377cd5f5653007bc104
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit 77c7741f39a0a9789bede7c4722bd3f35d4af3fd)

commit 97542f40947b8815851a2cdb82aee73bb521cfef
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit 0893ae88180137d44f17196234f657d362543ff5)

commit ceb5bbc7e306727b3c7d1214b7548614f5dd7444
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit 8884d617310b47375e38c0386433c5e183703454)

commit 1d97e7cc2cf5308a1bd4d2b114ee45a7f8fc4645
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit 1cc1586d84a65046ab7804f17297c6964bb76c23)

commit 7d158ba707f56c159676ab0ba92189ae15fff3cc
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (cherry picked from commit 9b2417c2f04857709c25e3665cd783a68edf0cf2)

commit 706b26c88b516fe397358305169f980841bf26f1
Author: Stefan Metzmacher <[email protected]>
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 <[email protected]>
    Reviewed-by: Ralph Boehme <[email protected]>
    (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

Reply via email to