]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3:smbd: maintain all SHARE_MODE_LEASE_* flags not only _READ
authorStefan Metzmacher <metze@samba.org>
Mon, 15 Aug 2022 15:42:33 +0000 (17:42 +0200)
committerJeremy Allison <jra@samba.org>
Tue, 20 Sep 2022 00:34:35 +0000 (00:34 +0000)
Remember SMB2 Create is the only was to upgrade a lease.

The strategy is that opening of a file will always result
in storing the total lease bits.

But we're lazy clearing the flags on close.

We'll only clear them by traversing all entries when
we break a NONE or when opening a new handle.

We don't do any decision on SHARE_MODE_LEASE_{HANDLE,WRITE},
maybe we'll do in future, but at least it should be much more
sane for debugging now!

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15125

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/smbd/open.c
source3/smbd/smb2_oplock.c

index cb54f03a3b8dd41891acbbb9de1e56cd3f18dfe4..3dc8c60e763eb88ea74af0446d9c20f2e8bbf96e 100644 (file)
@@ -2571,6 +2571,7 @@ struct delay_for_oplock_state {
        bool got_handle_lease;
        bool got_oplock;
        bool have_other_lease;
+       uint32_t total_lease_types;
        bool delay;
 };
 
@@ -2648,6 +2649,12 @@ static bool delay_for_oplock_fn(
                e_lease_type = get_lease_type(e, fsp->file_id);
        }
 
+       if (((e_lease_type & ~state->total_lease_types) != 0) &&
+           !share_entry_stale_pid(e))
+       {
+               state->total_lease_types |= e_lease_type;
+       }
+
        if (!state->got_handle_lease &&
            ((e_lease_type & SMB2_LEASE_HANDLE) != 0) &&
            !share_entry_stale_pid(e)) {
@@ -2770,6 +2777,8 @@ static NTSTATUS delay_for_oplock(files_struct *fsp,
                        oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
        }
 
+       share_mode_flags_get(lck, NULL, NULL, &state.total_lease_types);
+
        if (is_oplock_stat_open(fsp->access_mask)) {
                goto grant;
        }
@@ -2788,6 +2797,7 @@ static NTSTATUS delay_for_oplock(files_struct *fsp,
                break;
        }
 
+       state.total_lease_types = SMB2_LEASE_NONE;
        ok = share_mode_forall_entries(lck, delay_for_oplock_fn, &state);
        if (!ok) {
                return NT_STATUS_INTERNAL_ERROR;
@@ -2865,15 +2875,17 @@ grant:
                granted = map_oplock_to_lease_type(oplock_type);
        }
 
-       if (granted & SMB2_LEASE_READ) {
+       state.total_lease_types |= granted;
+
+       {
                uint32_t acc, sh, ls;
                share_mode_flags_get(lck, &acc, &sh, &ls);
-               ls |= SMB2_LEASE_READ;
+               ls = state.total_lease_types;
                share_mode_flags_set(lck, acc, sh, ls, NULL);
        }
 
        DBG_DEBUG("oplock type 0x%x granted (%s%s%s)(0x%x), on file %s, "
-                 "requested 0x%x (%s%s%s)(0x%x)\n",
+                 "requested 0x%x (%s%s%s)(0x%x) => total (%s%s%s)(0x%x)\n",
                  fsp->oplock_type,
                  granted & SMB2_LEASE_READ ? "R":"",
                  granted & SMB2_LEASE_WRITE ? "W":"",
@@ -2884,7 +2896,11 @@ grant:
                  requested & SMB2_LEASE_READ ? "R":"",
                  requested & SMB2_LEASE_WRITE ? "W":"",
                  requested & SMB2_LEASE_HANDLE ? "H":"",
-                 requested);
+                 requested,
+                 state.total_lease_types & SMB2_LEASE_READ ? "R":"",
+                 state.total_lease_types & SMB2_LEASE_WRITE ? "W":"",
+                 state.total_lease_types & SMB2_LEASE_HANDLE ? "H":"",
+                 state.total_lease_types);
 
        *poplock_type = oplock_type;
        *pgranted = granted;
index c4f4fb3ac3360af6cd592933ae823117f1666455..a7bf803e87832c70546f18647b453a668c97f7fb 100644 (file)
@@ -1150,6 +1150,7 @@ struct break_to_none_state {
        struct smb2_lease_key lease_key;
        struct GUID client_guid;
        size_t num_read_leases;
+       uint32_t total_lease_types;
 };
 
 static bool do_break_lease_to_none(struct share_mode_entry *e,
@@ -1179,6 +1180,8 @@ static bool do_break_lease_to_none(struct share_mode_entry *e,
                return false;
        }
 
+       state->total_lease_types |= current_state;
+
        if ((current_state & SMB2_LEASE_READ) == 0) {
                return false;
        }
@@ -1229,6 +1232,8 @@ static bool do_break_oplock_to_none(struct share_mode_entry *e,
 
        DBG_DEBUG("e->op_type == %d\n", e->op_type);
 
+       state->total_lease_types |= map_oplock_to_lease_type(e->op_type);
+
        if (e->op_type == NO_OPLOCK) {
                return false;
        }
@@ -1313,14 +1318,14 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp,
                DBG_WARNING("share_mode_forall_entries failed\n");
        }
 
-       if (state.num_read_leases == 0) {
+       {
                /*
-                * Lazy update here. It might be that the read lease
-                * has gone in the meantime.
+                * Lazy update here. It might be that all leases
+                * have gone in the meantime.
                 */
                uint32_t acc, sh, ls;
                share_mode_flags_get(lck, &acc, &sh, &ls);
-               ls &= ~SMB2_LEASE_READ;
+               ls = state.total_lease_types;
                share_mode_flags_set(lck, acc, sh, ls, NULL);
        }