LCOV - code coverage report
Current view: top level - source3/smbd - smb2_oplock.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 414 596 69.5 %
Date: 2024-02-28 12:06:22 Functions: 28 30 93.3 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    oplock processing
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             :    Copyright (C) Jeremy Allison 1998 - 2001
       6             :    Copyright (C) Volker Lendecke 2005
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #define DBGC_CLASS DBGC_LOCKING
      23             : #include "includes.h"
      24             : #include "lib/util/server_id.h"
      25             : #include "locking/share_mode_lock.h"
      26             : #include "smbd/smbd.h"
      27             : #include "smbd/globals.h"
      28             : #include "messages.h"
      29             : #include "locking/leases_db.h"
      30             : #include "../librpc/gen_ndr/ndr_open_files.h"
      31             : 
      32             : /*
      33             :  * helper function used by the kernel oplock backends to post the break message
      34             :  */
      35           4 : void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp)
      36             : {
      37           0 :         uint8_t msg[MSG_SMB_KERNEL_BREAK_SIZE];
      38             : 
      39             :         /* Put the kernel break info into the message. */
      40           4 :         push_file_id_24((char *)msg, &fsp->file_id);
      41           4 :         SIVAL(msg, 24, fh_get_gen_id(fsp->fh));
      42             : 
      43             :         /* Don't need to be root here as we're only ever
      44             :            sending to ourselves. */
      45             : 
      46           4 :         messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
      47             :                            MSG_SMB_KERNEL_BREAK,
      48             :                            msg, MSG_SMB_KERNEL_BREAK_SIZE);
      49           4 : }
      50             : 
      51             : /****************************************************************************
      52             :  Attempt to set an oplock on a file. Succeeds if kernel oplocks are
      53             :  disabled (just sets flags).
      54             : ****************************************************************************/
      55             : 
      56        1836 : NTSTATUS set_file_oplock(files_struct *fsp)
      57             : {
      58        1836 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
      59        1836 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
      60        1836 :         bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) &&
      61             :                         (koplocks != NULL);
      62         123 :         struct file_id_buf buf;
      63             : 
      64        1836 :         smb_vfs_assert_allowed();
      65             : 
      66        1836 :         if (fsp->oplock_type == LEVEL_II_OPLOCK && use_kernel) {
      67           2 :                 DEBUG(10, ("Refusing level2 oplock, kernel oplocks "
      68             :                            "don't support them\n"));
      69           2 :                 return NT_STATUS_NOT_SUPPORTED;
      70             :         }
      71             : 
      72        1834 :         if ((fsp->oplock_type != NO_OPLOCK) &&
      73           7 :             use_kernel &&
      74           7 :             !koplocks->ops->set_oplock(koplocks, fsp, fsp->oplock_type))
      75             :         {
      76           0 :                 return map_nt_error_from_unix(errno);
      77             :         }
      78             : 
      79        1834 :         fsp->sent_oplock_break = NO_BREAK_SENT;
      80        1834 :         if (fsp->oplock_type == LEVEL_II_OPLOCK) {
      81         252 :                 sconn->oplocks.level_II_open++;
      82        1582 :         } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
      83        1530 :                 sconn->oplocks.exclusive_open++;
      84             :         }
      85             : 
      86        1834 :         DBG_INFO("granted oplock on file %s, %s/%"PRIu64", "
      87             :                  "tv_sec = %x, tv_usec = %x\n",
      88             :                  fsp_str_dbg(fsp),
      89             :                  file_id_str_buf(fsp->file_id, &buf),
      90             :                  fh_get_gen_id(fsp->fh),
      91             :                  (int)fsp->open_time.tv_sec,
      92             :                  (int)fsp->open_time.tv_usec);
      93             : 
      94        1834 :         return NT_STATUS_OK;
      95             : }
      96             : 
      97        2644 : static void release_fsp_kernel_oplock(files_struct *fsp)
      98             : {
      99        2644 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
     100        2644 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
     101         123 :         bool use_kernel;
     102             : 
     103        2644 :         smb_vfs_assert_allowed();
     104             : 
     105        2644 :         if (koplocks == NULL) {
     106        2514 :                 return;
     107             :         }
     108           7 :         use_kernel = lp_kernel_oplocks(SNUM(fsp->conn));
     109           7 :         if (!use_kernel) {
     110           0 :                 return;
     111             :         }
     112           7 :         if (fsp->oplock_type == NO_OPLOCK) {
     113           0 :                 return;
     114             :         }
     115           7 :         if (fsp->oplock_type == LEASE_OPLOCK) {
     116             :                 /*
     117             :                  * For leases we don't touch kernel oplocks at all
     118             :                  */
     119           0 :                 return;
     120             :         }
     121             : 
     122           7 :         koplocks->ops->release_oplock(koplocks, fsp, NO_OPLOCK);
     123             : }
     124             : 
     125             : /****************************************************************************
     126             :  Attempt to release an oplock on a file. Decrements oplock count.
     127             : ****************************************************************************/
     128             : 
     129        2644 : void release_file_oplock(files_struct *fsp)
     130             : {
     131        2644 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
     132             : 
     133        2644 :         release_fsp_kernel_oplock(fsp);
     134             : 
     135        2644 :         if (fsp->oplock_type == LEVEL_II_OPLOCK) {
     136         404 :                 sconn->oplocks.level_II_open--;
     137        2240 :         } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
     138        1278 :                 sconn->oplocks.exclusive_open--;
     139             :         }
     140             : 
     141        2644 :         SMB_ASSERT(sconn->oplocks.exclusive_open>=0);
     142        2644 :         SMB_ASSERT(sconn->oplocks.level_II_open>=0);
     143             : 
     144        2644 :         fsp->oplock_type = NO_OPLOCK;
     145        2644 :         fsp->sent_oplock_break = NO_BREAK_SENT;
     146             : 
     147        2644 :         TALLOC_FREE(fsp->oplock_timeout);
     148        2644 : }
     149             : 
     150             : /****************************************************************************
     151             :  Attempt to downgrade an oplock on a file. Doesn't decrement oplock count.
     152             : ****************************************************************************/
     153             : 
     154         154 : static void downgrade_file_oplock(files_struct *fsp)
     155             : {
     156         154 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
     157         154 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
     158         154 :         bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) &&
     159             :                         (koplocks != NULL);
     160             : 
     161         154 :         smb_vfs_assert_allowed();
     162             : 
     163         154 :         if (!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
     164           0 :                 DEBUG(0, ("trying to downgrade an already-downgraded oplock!\n"));
     165           0 :                 return;
     166             :         }
     167             : 
     168         154 :         if (use_kernel) {
     169           0 :                 koplocks->ops->release_oplock(koplocks, fsp, LEVEL_II_OPLOCK);
     170             :         }
     171         154 :         fsp->oplock_type = LEVEL_II_OPLOCK;
     172         154 :         sconn->oplocks.exclusive_open--;
     173         154 :         sconn->oplocks.level_II_open++;
     174         154 :         fsp->sent_oplock_break = NO_BREAK_SENT;
     175             : 
     176         154 :         TALLOC_FREE(fsp->oplock_timeout);
     177             : }
     178             : 
     179       30177 : uint32_t get_lease_type(struct share_mode_entry *e, struct file_id id)
     180             : {
     181         128 :         struct GUID_txt_buf guid_strbuf;
     182         128 :         struct file_id_buf file_id_strbuf;
     183         128 :         NTSTATUS status;
     184         128 :         uint32_t current_state;
     185             : 
     186       30177 :         if (e->op_type != LEASE_OPLOCK) {
     187       30149 :                 return map_oplock_to_lease_type(e->op_type);
     188             :         }
     189             : 
     190          28 :         status = leases_db_get(&e->client_guid,
     191          28 :                                &e->lease_key,
     192             :                                &id,
     193             :                                &current_state,
     194             :                                NULL,    /* breaking */
     195             :                                NULL,    /* breaking_to_requested */
     196             :                                NULL,    /* breaking_to_required */
     197             :                                NULL,    /* lease_version */
     198             :                                NULL);   /* epoch */
     199          28 :         if (NT_STATUS_IS_OK(status)) {
     200          28 :                 return current_state;
     201             :         }
     202             : 
     203           0 :         if (share_entry_stale_pid(e)) {
     204           0 :                 return 0;
     205             :         }
     206           0 :         DBG_ERR("leases_db_get for client_guid [%s] "
     207             :                 "lease_key [%"PRIu64"/%"PRIu64"] "
     208             :                 "file_id [%s] failed: %s\n",
     209             :                 GUID_buf_string(&e->client_guid, &guid_strbuf),
     210             :                 e->lease_key.data[0],
     211             :                 e->lease_key.data[1],
     212             :                 file_id_str_buf(id, &file_id_strbuf),
     213             :                 nt_errstr(status));
     214           0 :         smb_panic("leases_db_get() failed");
     215             : }
     216             : 
     217             : /****************************************************************************
     218             :  Remove a file oplock. Copes with level II and exclusive.
     219             :  Locks then unlocks the share mode lock. Client can decide to go directly
     220             :  to none even if a "break-to-level II" was sent.
     221             : ****************************************************************************/
     222             : 
     223         119 : bool remove_oplock(files_struct *fsp)
     224             : {
     225           0 :         bool ret;
     226           0 :         struct share_mode_lock *lck;
     227             : 
     228         119 :         DBG_DEBUG("remove_oplock called for %s\n", fsp_str_dbg(fsp));
     229             : 
     230             :         /* Remove the oplock flag from the sharemode. */
     231         119 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
     232         119 :         if (lck == NULL) {
     233           0 :                 DBG_ERR("failed to lock share entry for "
     234             :                          "file %s\n", fsp_str_dbg(fsp));
     235           0 :                 return false;
     236             :         }
     237             : 
     238         119 :         ret = remove_share_oplock(lck, fsp);
     239         119 :         if (!ret) {
     240           0 :                 struct file_id_buf buf;
     241             : 
     242           0 :                 DBG_ERR("failed to remove share oplock for "
     243             :                         "file %s, %s, %s\n",
     244             :                         fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
     245             :                         file_id_str_buf(fsp->file_id, &buf));
     246             :         }
     247         119 :         release_file_oplock(fsp);
     248             : 
     249         119 :         TALLOC_FREE(lck);
     250         119 :         return ret;
     251             : }
     252             : 
     253             : /*
     254             :  * Deal with a reply when a break-to-level II was sent.
     255             :  */
     256         154 : bool downgrade_oplock(files_struct *fsp)
     257             : {
     258           0 :         bool ret;
     259           0 :         struct share_mode_lock *lck;
     260             : 
     261         154 :         DEBUG(10, ("downgrade_oplock called for %s\n",
     262             :                    fsp_str_dbg(fsp)));
     263             : 
     264         154 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
     265         154 :         if (lck == NULL) {
     266           0 :                 DEBUG(0,("downgrade_oplock: failed to lock share entry for "
     267             :                          "file %s\n", fsp_str_dbg(fsp)));
     268           0 :                 return False;
     269             :         }
     270         154 :         ret = downgrade_share_oplock(lck, fsp);
     271         154 :         if (!ret) {
     272           0 :                 struct file_id_buf idbuf;
     273           0 :                 DBG_ERR("failed to downgrade share oplock "
     274             :                         "for file %s, %s, file_id %s\n",
     275             :                         fsp_str_dbg(fsp),
     276             :                         fsp_fnum_dbg(fsp),
     277             :                         file_id_str_buf(fsp->file_id, &idbuf));
     278             :         }
     279         154 :         downgrade_file_oplock(fsp);
     280             : 
     281         154 :         TALLOC_FREE(lck);
     282         154 :         return ret;
     283             : }
     284             : 
     285           4 : static void lease_timeout_handler(struct tevent_context *ctx,
     286             :                                   struct tevent_timer *te,
     287             :                                   struct timeval now,
     288             :                                   void *private_data)
     289             : {
     290           0 :         struct fsp_lease *lease =
     291           4 :                 talloc_get_type_abort(private_data,
     292             :                 struct fsp_lease);
     293           0 :         struct files_struct *fsp;
     294           0 :         struct share_mode_lock *lck;
     295           4 :         uint16_t old_epoch = lease->lease.lease_epoch;
     296             : 
     297           4 :         fsp = file_find_one_fsp_from_lease_key(lease->sconn,
     298           4 :                                                &lease->lease.lease_key);
     299           4 :         if (fsp == NULL) {
     300             :                 /* race? */
     301           0 :                 TALLOC_FREE(lease->timeout);
     302           0 :                 return;
     303             :         }
     304             : 
     305             :         /*
     306             :          * Paranoia check: There can only be one fsp_lease per lease
     307             :          * key
     308             :          */
     309           4 :         SMB_ASSERT(fsp->lease == lease);
     310             : 
     311           4 :         lck = get_existing_share_mode_lock(
     312             :                         talloc_tos(), fsp->file_id);
     313           4 :         if (lck == NULL) {
     314             :                 /* race? */
     315           0 :                 TALLOC_FREE(lease->timeout);
     316           0 :                 return;
     317             :         }
     318             : 
     319           4 :         fsp_lease_update(fsp);
     320             : 
     321           4 :         if (lease->lease.lease_epoch != old_epoch) {
     322             :                 /*
     323             :                  * If the epoch changed we need to wait for
     324             :                  * the next timeout to happen.
     325             :                  */
     326           0 :                 DEBUG(10, ("lease break timeout race (epoch) for file %s - ignoring\n",
     327             :                            fsp_str_dbg(fsp)));
     328           0 :                 TALLOC_FREE(lck);
     329           0 :                 return;
     330             :         }
     331             : 
     332           4 :         if (!(lease->lease.lease_flags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)) {
     333             :                 /*
     334             :                  * If the epoch changed we need to wait for
     335             :                  * the next timeout to happen.
     336             :                  */
     337           0 :                 DEBUG(10, ("lease break timeout race (flags) for file %s - ignoring\n",
     338             :                            fsp_str_dbg(fsp)));
     339           0 :                 TALLOC_FREE(lck);
     340           0 :                 return;
     341             :         }
     342             : 
     343           4 :         DEBUG(1, ("lease break timed out for file %s -- replying anyway\n",
     344             :                   fsp_str_dbg(fsp)));
     345           4 :         (void)downgrade_lease(lease->sconn->client,
     346             :                         1,
     347           4 :                         &fsp->file_id,
     348           4 :                         &lease->lease.lease_key,
     349             :                         SMB2_LEASE_NONE);
     350             : 
     351           4 :         TALLOC_FREE(lck);
     352             : }
     353             : 
     354         564 : bool fsp_lease_update(struct files_struct *fsp)
     355             : {
     356         564 :         const struct GUID *client_guid = fsp_client_guid(fsp);
     357         564 :         struct fsp_lease *lease = fsp->lease;
     358           0 :         uint32_t current_state;
     359           0 :         bool breaking;
     360           0 :         uint16_t lease_version, epoch;
     361           0 :         NTSTATUS status;
     362             : 
     363         564 :         status = leases_db_get(client_guid,
     364         564 :                                &lease->lease.lease_key,
     365         564 :                                &fsp->file_id,
     366             :                                &current_state,
     367             :                                &breaking,
     368             :                                NULL, /* breaking_to_requested */
     369             :                                NULL, /* breaking_to_required */
     370             :                                &lease_version,
     371             :                                &epoch);
     372         564 :         if (!NT_STATUS_IS_OK(status)) {
     373           0 :                 DBG_WARNING("Could not find lease entry: %s\n",
     374             :                             nt_errstr(status));
     375           0 :                 TALLOC_FREE(lease->timeout);
     376           0 :                 lease->lease.lease_state = SMB2_LEASE_NONE;
     377           0 :                 lease->lease.lease_epoch += 1;
     378           0 :                 lease->lease.lease_flags = 0;
     379           0 :                 return false;
     380             :         }
     381             : 
     382         564 :         DEBUG(10,("%s: refresh lease state\n", __func__));
     383             : 
     384             :         /* Ensure we're in sync with current lease state. */
     385         564 :         if (lease->lease.lease_epoch != epoch) {
     386         236 :                 DEBUG(10,("%s: cancel outdated timeout\n", __func__));
     387         236 :                 TALLOC_FREE(lease->timeout);
     388             :         }
     389         564 :         lease->lease.lease_epoch = epoch;
     390         564 :         lease->lease.lease_state = current_state;
     391             : 
     392         564 :         if (breaking) {
     393         224 :                 lease->lease.lease_flags |= SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
     394             : 
     395         224 :                 if (lease->timeout == NULL) {
     396         162 :                         struct timeval t = timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0);
     397             : 
     398         162 :                         DEBUG(10,("%s: setup timeout handler\n", __func__));
     399             : 
     400         162 :                         lease->timeout = tevent_add_timer(lease->sconn->ev_ctx,
     401             :                                                           lease, t,
     402             :                                                           lease_timeout_handler,
     403             :                                                           lease);
     404         162 :                         if (lease->timeout == NULL) {
     405           0 :                                 DEBUG(0, ("%s: Could not add lease timeout handler\n",
     406             :                                           __func__));
     407             :                         }
     408             :                 }
     409             :         } else {
     410         340 :                 lease->lease.lease_flags &= ~SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
     411         340 :                 TALLOC_FREE(lease->timeout);
     412             :         }
     413             : 
     414         564 :         return true;
     415             : }
     416             : 
     417             : struct downgrade_lease_additional_state {
     418             :         struct tevent_immediate *im;
     419             :         struct smbXsrv_client *client;
     420             :         uint32_t break_flags;
     421             :         struct smb2_lease_key lease_key;
     422             :         uint32_t break_from;
     423             :         uint32_t break_to;
     424             :         uint16_t new_epoch;
     425             : };
     426             : 
     427           8 : static void downgrade_lease_additional_trigger(struct tevent_context *ev,
     428             :                                                struct tevent_immediate *im,
     429             :                                                void *private_data)
     430             : {
     431           0 :         struct downgrade_lease_additional_state *state =
     432           8 :                 talloc_get_type_abort(private_data,
     433             :                 struct downgrade_lease_additional_state);
     434           0 :         NTSTATUS status;
     435             : 
     436           8 :         status = smbd_smb2_send_lease_break(state->client,
     437           8 :                                             state->new_epoch,
     438             :                                             state->break_flags,
     439             :                                             &state->lease_key,
     440             :                                             state->break_from,
     441             :                                             state->break_to);
     442           8 :         if (!NT_STATUS_IS_OK(status)) {
     443           0 :                 smbd_server_disconnect_client(state->client,
     444             :                                               nt_errstr(status));
     445             :         }
     446           8 :         TALLOC_FREE(state);
     447           8 : }
     448             : 
     449             : struct fsps_lease_update_state {
     450             :         const struct file_id *id;
     451             :         const struct smb2_lease_key *key;
     452             : };
     453             : 
     454         260 : static struct files_struct *fsps_lease_update_fn(
     455             :         struct files_struct *fsp, void *private_data)
     456             : {
     457         260 :         struct fsps_lease_update_state *state =
     458             :                 (struct fsps_lease_update_state *)private_data;
     459             : 
     460         260 :         if (fsp->oplock_type != LEASE_OPLOCK) {
     461          90 :                 return NULL;
     462             :         }
     463         170 :         if (!smb2_lease_key_equal(&fsp->lease->lease.lease_key, state->key)) {
     464          36 :                 return NULL;
     465             :         }
     466         134 :         if (!file_id_equal(&fsp->file_id, state->id)) {
     467           4 :                 return NULL;
     468             :         }
     469             : 
     470         130 :         fsp_lease_update(fsp);
     471             : 
     472         130 :         return NULL;
     473             : }
     474             : 
     475         126 : static void fsps_lease_update(struct smbd_server_connection *sconn,
     476             :                               const struct file_id *id,
     477             :                               const struct smb2_lease_key *key)
     478             : {
     479         126 :         struct fsps_lease_update_state state = { .id = id, .key = key };
     480         126 :         files_forall(sconn, fsps_lease_update_fn, &state);
     481         126 : }
     482             : 
     483         144 : NTSTATUS downgrade_lease(struct smbXsrv_client *client,
     484             :                          uint32_t num_file_ids,
     485             :                          const struct file_id *ids,
     486             :                          const struct smb2_lease_key *key,
     487             :                          uint32_t lease_state)
     488             : {
     489         144 :         struct smbd_server_connection *sconn = client->sconn;
     490         144 :         const struct GUID *client_guid = NULL;
     491           0 :         struct share_mode_lock *lck;
     492         144 :         const struct file_id id = ids[0];
     493           0 :         uint32_t current_state, breaking_to_requested, breaking_to_required;
     494           0 :         bool breaking;
     495           0 :         uint16_t lease_version, epoch;
     496           0 :         NTSTATUS status;
     497           0 :         uint32_t i;
     498           0 :         struct file_id_buf idbuf;
     499             : 
     500         144 :         DBG_DEBUG("Downgrading %s to %"PRIu32"\n",
     501             :                   file_id_str_buf(id, &idbuf),
     502             :                   lease_state);
     503             : 
     504         144 :         lck = get_existing_share_mode_lock(talloc_tos(), id);
     505         144 :         if (lck == NULL) {
     506           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     507             :         }
     508             : 
     509         144 :         client_guid = &sconn->client->global->client_guid;
     510             : 
     511         144 :         status = leases_db_get(client_guid,
     512             :                                key,
     513             :                                &id,
     514             :                                &current_state,
     515             :                                &breaking,
     516             :                                &breaking_to_requested,
     517             :                                &breaking_to_required,
     518             :                                &lease_version,
     519             :                                &epoch);
     520         144 :         if (!NT_STATUS_IS_OK(status)) {
     521           0 :                 DBG_WARNING("leases_db_get returned %s\n",
     522             :                             nt_errstr(status));
     523           0 :                 TALLOC_FREE(lck);
     524           0 :                 return status;
     525             :         }
     526             : 
     527         144 :         if (!breaking) {
     528           6 :                 DBG_WARNING("Attempt to break from %"PRIu32" to %"PRIu32" - "
     529             :                             "but we're not in breaking state\n",
     530             :                             current_state, lease_state);
     531           6 :                 TALLOC_FREE(lck);
     532           6 :                 return NT_STATUS_UNSUCCESSFUL;
     533             :         }
     534             : 
     535             :         /*
     536             :          * Can't upgrade anything: breaking_to_requested (and current_state)
     537             :          * must be a strict bitwise superset of new_lease_state
     538             :          */
     539         138 :         if ((lease_state & breaking_to_requested) != lease_state) {
     540          14 :                 DBG_WARNING("Attempt to upgrade from %"PRIu32" to %"PRIu32" "
     541             :                             "- expected %"PRIu32"\n",
     542             :                             current_state, lease_state,
     543             :                             breaking_to_requested);
     544          14 :                 TALLOC_FREE(lck);
     545          14 :                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
     546             :         }
     547             : 
     548         124 :         if (current_state != lease_state) {
     549         124 :                 current_state = lease_state;
     550             :         }
     551             : 
     552         124 :         status = NT_STATUS_OK;
     553             : 
     554         124 :         if ((lease_state & ~breaking_to_required) != 0) {
     555           0 :                 struct downgrade_lease_additional_state *state;
     556             : 
     557           8 :                 DBG_INFO("lease state %"PRIu32" not fully broken from "
     558             :                          "%"PRIu32" to %"PRIu32"\n",
     559             :                          lease_state,
     560             :                          current_state,
     561             :                          breaking_to_required);
     562             : 
     563           8 :                 breaking_to_requested = breaking_to_required;
     564             : 
     565           8 :                 if (current_state & (SMB2_LEASE_WRITE|SMB2_LEASE_HANDLE)) {
     566             :                         /*
     567             :                          * Here we break in steps, as windows does
     568             :                          * see the breaking3 and v2_breaking3 tests.
     569             :                          */
     570           4 :                         breaking_to_requested |= SMB2_LEASE_READ;
     571             :                 }
     572             : 
     573           8 :                 state = talloc_zero(client,
     574             :                                     struct downgrade_lease_additional_state);
     575           8 :                 if (state == NULL) {
     576           0 :                         TALLOC_FREE(lck);
     577           0 :                         return NT_STATUS_NO_MEMORY;
     578             :                 }
     579             : 
     580           8 :                 state->im = tevent_create_immediate(state);
     581           8 :                 if (state->im == NULL) {
     582           0 :                         TALLOC_FREE(state);
     583           0 :                         TALLOC_FREE(lck);
     584           0 :                         return NT_STATUS_NO_MEMORY;
     585             :                 }
     586             : 
     587           8 :                 state->client = client;
     588           8 :                 state->lease_key = *key;
     589           8 :                 state->break_from = current_state;
     590           8 :                 state->break_to = breaking_to_requested;
     591           8 :                 if (lease_version > 1) {
     592           4 :                         state->new_epoch = epoch;
     593             :                 }
     594             : 
     595           8 :                 if (current_state & (SMB2_LEASE_WRITE|SMB2_LEASE_HANDLE)) {
     596           4 :                         state->break_flags =
     597             :                                 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;
     598             :                 } else {
     599             :                         /*
     600             :                          * This is an async break without
     601             :                          * SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED
     602             :                          *
     603             :                          * we need to store NONE state in the
     604             :                          * database.
     605             :                          */
     606           4 :                         current_state = 0;
     607           4 :                         breaking_to_requested = 0;
     608           4 :                         breaking_to_required = 0;
     609           4 :                         breaking = false;
     610             : 
     611             :                         {
     612           0 :                                 NTSTATUS set_status;
     613             : 
     614           4 :                                 set_status = leases_db_set(
     615           4 :                                         &sconn->client->global->client_guid,
     616             :                                         key,
     617             :                                         current_state,
     618             :                                         breaking,
     619             :                                         breaking_to_requested,
     620             :                                         breaking_to_required,
     621             :                                         lease_version,
     622             :                                         epoch);
     623             : 
     624           4 :                                 if (!NT_STATUS_IS_OK(set_status)) {
     625           0 :                                         DBG_DEBUG("leases_db_set failed: %s\n",
     626             :                                                   nt_errstr(set_status));
     627           0 :                                         return set_status;
     628             :                                 }
     629             :                         }
     630             :                 }
     631             : 
     632           8 :                 tevent_schedule_immediate(state->im,
     633             :                                           client->raw_ev_ctx,
     634             :                                           downgrade_lease_additional_trigger,
     635           0 :                                           state);
     636             : 
     637           8 :                 status = NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
     638             :         } else {
     639         116 :                 DBG_DEBUG("breaking from %"PRIu32" to %"PRIu32" - "
     640             :                           "expected %"PRIu32"\n",
     641             :                           current_state,
     642             :                           lease_state,
     643             :                           breaking_to_requested);
     644             : 
     645         116 :                 breaking_to_requested = 0;
     646         116 :                 breaking_to_required = 0;
     647         116 :                 breaking = false;
     648             :         }
     649             : 
     650             :         {
     651           0 :                 NTSTATUS set_status;
     652             : 
     653         124 :                 set_status = leases_db_set(
     654             :                         client_guid,
     655             :                         key,
     656             :                         current_state,
     657             :                         breaking,
     658             :                         breaking_to_requested,
     659             :                         breaking_to_required,
     660             :                         lease_version,
     661             :                         epoch);
     662             : 
     663         124 :                 if (!NT_STATUS_IS_OK(set_status)) {
     664           0 :                         DBG_DEBUG("leases_db_set failed: %s\n",
     665             :                                   nt_errstr(set_status));
     666           0 :                         TALLOC_FREE(lck);
     667           0 :                         return set_status;
     668             :                 }
     669             :         }
     670             : 
     671         124 :         DBG_DEBUG("Downgrading %s to %"PRIu32" => %s\n",
     672             :                   file_id_str_buf(id, &idbuf),
     673             :                   lease_state,
     674             :                   nt_errstr(status));
     675             : 
     676         124 :         share_mode_wakeup_waiters(id);
     677             : 
     678         124 :         fsps_lease_update(sconn, &id, key);
     679             : 
     680         124 :         TALLOC_FREE(lck);
     681             : 
     682         124 :         DBG_DEBUG("Downgrading %s to %"PRIu32" => %s\n",
     683             :                   file_id_str_buf(id, &idbuf),
     684             :                   lease_state,
     685             :                   nt_errstr(status));
     686             : 
     687             :         /*
     688             :          * Dynamic share case. Ensure other opens are copies.
     689             :          * This will only be breaking to NONE.
     690             :          */
     691             : 
     692         126 :         for (i = 1; i < num_file_ids; i++) {
     693           2 :                 lck = get_existing_share_mode_lock(talloc_tos(), ids[i]);
     694           2 :                 if (lck == NULL) {
     695           0 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     696             :                 }
     697             : 
     698           2 :                 fsps_lease_update(sconn, &ids[i], key);
     699             : 
     700           2 :                 DBG_DEBUG("Downgrading %s to %"PRIu32" => %s\n",
     701             :                           file_id_str_buf(ids[i], &idbuf),
     702             :                           lease_state,
     703             :                           nt_errstr(status));
     704             : 
     705           2 :                 TALLOC_FREE(lck);
     706             :         }
     707             : 
     708         124 :         return status;
     709             : }
     710             : 
     711             : #define SMB1_BREAK_MESSAGE_LENGTH (smb_size + 8*2)
     712             : 
     713             : /****************************************************************************
     714             :  Function to do the waiting before sending a local break.
     715             : ****************************************************************************/
     716             : 
     717         223 : static void wait_before_sending_break(void)
     718             : {
     719         223 :         long wait_time = (long)lp_oplock_break_wait_time();
     720             : 
     721         223 :         if (wait_time) {
     722           0 :                 smb_msleep(wait_time);
     723             :         }
     724         223 : }
     725             : 
     726             : /****************************************************************************
     727             :  Ensure that we have a valid oplock.
     728             : ****************************************************************************/
     729             : 
     730         596 : static files_struct *initial_break_processing(
     731             :         struct smbd_server_connection *sconn, struct file_id id,
     732             :         unsigned long file_id)
     733             : {
     734         596 :         files_struct *fsp = NULL;
     735           0 :         struct file_id_buf idbuf;
     736             : 
     737         596 :         DBG_NOTICE("called for %s/%u\n"
     738             :                    "Current oplocks_open (exclusive = %d, levelII = %d)\n",
     739             :                    file_id_str_buf(id, &idbuf),
     740             :                    (int)file_id,
     741             :                    sconn->oplocks.exclusive_open,
     742             :                    sconn->oplocks.level_II_open);
     743             : 
     744             :         /*
     745             :          * We need to search the file open table for the
     746             :          * entry containing this dev and inode, and ensure
     747             :          * we have an oplock on it.
     748             :          */
     749             : 
     750         596 :         fsp = file_find_dif(sconn, id, file_id);
     751             : 
     752         596 :         if(fsp == NULL) {
     753             :                 /* The file could have been closed in the meantime - return success. */
     754           0 :                 DBG_NOTICE("cannot find open file "
     755             :                            "with file_id %s gen_id = %lu, allowing break to "
     756             :                            "succeed.\n",
     757             :                            file_id_str_buf(id, &idbuf),
     758             :                            file_id);
     759           0 :                 return NULL;
     760             :         }
     761             : 
     762             :         /* Ensure we have an oplock on the file */
     763             : 
     764             :         /*
     765             :          * There is a potential race condition in that an oplock could
     766             :          * have been broken due to another udp request, and yet there are
     767             :          * still oplock break messages being sent in the udp message
     768             :          * queue for this file. So return true if we don't have an oplock,
     769             :          * as we may have just freed it.
     770             :          */
     771             : 
     772         596 :         if(fsp->oplock_type == NO_OPLOCK) {
     773           0 :                 DBG_NOTICE("file %s (file_id = %s gen_id = %"PRIu64") "
     774             :                            "has no oplock. "
     775             :                            "Allowing break to succeed regardless.\n",
     776             :                            fsp_str_dbg(fsp),
     777             :                            file_id_str_buf(id, &idbuf),
     778             :                            fh_get_gen_id(fsp->fh));
     779           0 :                 return NULL;
     780             :         }
     781             : 
     782         596 :         return fsp;
     783             : }
     784             : 
     785          16 : static void oplock_timeout_handler(struct tevent_context *ctx,
     786             :                                    struct tevent_timer *te,
     787             :                                    struct timeval now,
     788             :                                    void *private_data)
     789             : {
     790          16 :         files_struct *fsp = (files_struct *)private_data;
     791             : 
     792          16 :         SMB_ASSERT(fsp->sent_oplock_break != NO_BREAK_SENT);
     793             : 
     794             :         /* Remove the timed event handler. */
     795          16 :         TALLOC_FREE(fsp->oplock_timeout);
     796          16 :         DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n",
     797             :                   fsp_str_dbg(fsp)));
     798          16 :         remove_oplock(fsp);
     799          16 : }
     800             : 
     801             : /*******************************************************************
     802             :  Add a timeout handler waiting for the client reply.
     803             : *******************************************************************/
     804             : 
     805         307 : static void add_oplock_timeout_handler(files_struct *fsp)
     806             : {
     807         307 :         if (fsp->oplock_timeout != NULL) {
     808           0 :                 DEBUG(0, ("Logic problem -- have an oplock event hanging "
     809             :                           "around\n"));
     810             :         }
     811             : 
     812         307 :         fsp->oplock_timeout =
     813         307 :                 tevent_add_timer(fsp->conn->sconn->ev_ctx, fsp,
     814             :                                  timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
     815             :                                  oplock_timeout_handler, fsp);
     816             : 
     817         307 :         if (fsp->oplock_timeout == NULL) {
     818           0 :                 DEBUG(0, ("Could not add oplock timeout handler\n"));
     819             :         }
     820         307 : }
     821             : 
     822             : /*******************************************************************
     823             :  This handles the generic oplock break message from another smbd.
     824             : *******************************************************************/
     825             : 
     826         592 : static void process_oplock_break_message(struct messaging_context *msg_ctx,
     827             :                                          void *private_data,
     828             :                                          uint32_t msg_type,
     829             :                                          struct server_id src,
     830             :                                          DATA_BLOB *data)
     831             : {
     832         592 :         struct oplock_break_message *msg = NULL;
     833           0 :         enum ndr_err_code ndr_err;
     834           0 :         files_struct *fsp;
     835           0 :         bool use_kernel;
     836           0 :         struct smbd_server_connection *sconn =
     837         592 :                 talloc_get_type_abort(private_data,
     838             :                 struct smbd_server_connection);
     839         592 :         struct server_id self = messaging_server_id(sconn->msg_ctx);
     840         592 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
     841           0 :         uint16_t break_from;
     842           0 :         uint16_t break_to;
     843         592 :         bool break_needed = true;
     844             : 
     845         592 :         smb_vfs_assert_allowed();
     846             : 
     847         592 :         msg = talloc(talloc_tos(), struct oplock_break_message);
     848         592 :         if (msg == NULL) {
     849           0 :                 DBG_WARNING("talloc failed\n");
     850         289 :                 return;
     851             :         }
     852             : 
     853         592 :         ndr_err = ndr_pull_struct_blob_all(
     854             :                 data,
     855             :                 msg,
     856             :                 msg,
     857             :                 (ndr_pull_flags_fn_t)ndr_pull_oplock_break_message);
     858         592 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     859           0 :                 DBG_DEBUG("ndr_pull_oplock_break_message failed: %s\n",
     860             :                           ndr_errstr(ndr_err));
     861           0 :                 TALLOC_FREE(msg);
     862           0 :                 return;
     863             :         }
     864         592 :         if (DEBUGLEVEL >= 10) {
     865           0 :                 struct server_id_buf buf;
     866           0 :                 DBG_DEBUG("Got break message from %s\n",
     867             :                           server_id_str_buf(src, &buf));
     868           0 :                 NDR_PRINT_DEBUG(oplock_break_message, msg);
     869             :         }
     870             : 
     871         592 :         break_to = msg->break_to;
     872         592 :         fsp = initial_break_processing(sconn, msg->id, msg->share_file_id);
     873             : 
     874         592 :         TALLOC_FREE(msg);
     875             : 
     876         592 :         if (fsp == NULL) {
     877             :                 /* We hit a race here. Break messages are sent, and before we
     878             :                  * get to process this message, we have closed the file. */
     879           0 :                 DEBUG(3, ("Did not find fsp\n"));
     880           0 :                 return;
     881             :         }
     882             : 
     883         592 :         break_from = fsp_lease_type(fsp);
     884             : 
     885         592 :         if (fsp->oplock_type != LEASE_OPLOCK) {
     886         374 :                 if (fsp->sent_oplock_break != NO_BREAK_SENT) {
     887             :                         /*
     888             :                          * Nothing to do anymore
     889             :                          */
     890          10 :                         DEBUG(10, ("fsp->sent_oplock_break = %d\n",
     891             :                                    fsp->sent_oplock_break));
     892          10 :                         return;
     893             :                 }
     894             :         }
     895             : 
     896         582 :         if (!(global_client_caps & CAP_LEVEL_II_OPLOCKS)) {
     897          18 :                 DEBUG(10, ("client_caps without level2 oplocks\n"));
     898          18 :                 break_to &= ~SMB2_LEASE_READ;
     899             :         }
     900             : 
     901         582 :         use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) &&
     902             :                         (koplocks != NULL);
     903         582 :         if (use_kernel) {
     904           1 :                 DEBUG(10, ("Kernel oplocks don't allow level2\n"));
     905           1 :                 break_to &= ~SMB2_LEASE_READ;
     906             :         }
     907             : 
     908         582 :         if (!lp_level2_oplocks(SNUM(fsp->conn))) {
     909           0 :                 DEBUG(10, ("no level2 oplocks by config\n"));
     910           0 :                 break_to &= ~SMB2_LEASE_READ;
     911             :         }
     912             : 
     913         582 :         if (fsp->oplock_type == LEASE_OPLOCK) {
     914         218 :                 const struct GUID *client_guid = fsp_client_guid(fsp);
     915           0 :                 struct share_mode_lock *lck;
     916           0 :                 uint32_t current_state;
     917           0 :                 uint32_t breaking_to_requested, breaking_to_required;
     918           0 :                 bool breaking;
     919           0 :                 uint16_t lease_version, epoch;
     920           0 :                 NTSTATUS status;
     921             : 
     922         218 :                 lck = get_existing_share_mode_lock(
     923             :                         talloc_tos(), fsp->file_id);
     924         218 :                 if (lck == NULL) {
     925             :                         /*
     926             :                          * We hit a race here. Break messages are sent, and
     927             :                          * before we get to process this message, we have closed
     928             :                          * the file.
     929             :                          */
     930           0 :                         DEBUG(3, ("Did not find share_mode\n"));
     931           0 :                         return;
     932             :                 }
     933             : 
     934         218 :                 status = leases_db_get(client_guid,
     935         218 :                                        &fsp->lease->lease.lease_key,
     936         218 :                                        &fsp->file_id,
     937             :                                        &current_state,
     938             :                                        &breaking,
     939             :                                        &breaking_to_requested,
     940             :                                        &breaking_to_required,
     941             :                                        &lease_version,
     942             :                                        &epoch);
     943         218 :                 if (!NT_STATUS_IS_OK(status)) {
     944           0 :                         DBG_WARNING("leases_db_get returned %s\n",
     945             :                                     nt_errstr(status));
     946           0 :                         TALLOC_FREE(lck);
     947           0 :                         return;
     948             :                 }
     949             : 
     950         218 :                 break_from = current_state;
     951         218 :                 break_to &= current_state;
     952             : 
     953         218 :                 if (breaking) {
     954          34 :                         break_to &= breaking_to_required;
     955          34 :                         if (breaking_to_required != break_to) {
     956             :                                 /*
     957             :                                  * Note we don't increment the epoch
     958             :                                  * here, which might be a bug in
     959             :                                  * Windows too...
     960             :                                  */
     961           4 :                                 breaking_to_required = break_to;
     962             :                         }
     963          34 :                         break_needed = false;
     964         184 :                 } else if (current_state == break_to) {
     965           0 :                         break_needed = false;
     966         184 :                 } else if (current_state == SMB2_LEASE_READ) {
     967          22 :                         current_state = SMB2_LEASE_NONE;
     968             :                         /* Need to increment the epoch */
     969          22 :                         epoch += 1;
     970             :                 } else {
     971         162 :                         breaking = true;
     972         162 :                         breaking_to_required = break_to;
     973         162 :                         breaking_to_requested = break_to;
     974             :                         /* Need to increment the epoch */
     975         162 :                         epoch += 1;
     976             :                 }
     977             : 
     978             :                 {
     979           0 :                         NTSTATUS set_status;
     980             : 
     981         218 :                         set_status = leases_db_set(
     982             :                                 client_guid,
     983         218 :                                 &fsp->lease->lease.lease_key,
     984             :                                 current_state,
     985             :                                 breaking,
     986             :                                 breaking_to_requested,
     987             :                                 breaking_to_required,
     988             :                                 lease_version,
     989             :                                 epoch);
     990             : 
     991         218 :                         if (!NT_STATUS_IS_OK(set_status)) {
     992           0 :                                 DBG_DEBUG("leases_db_set failed: %s\n",
     993             :                                           nt_errstr(set_status));
     994           0 :                                 return;
     995             :                         }
     996             :                 }
     997             : 
     998             :                 /* Ensure we're in sync with current lease state. */
     999         218 :                 fsp_lease_update(fsp);
    1000             : 
    1001         218 :                 TALLOC_FREE(lck);
    1002             :         }
    1003             : 
    1004         582 :         if (!break_needed) {
    1005          34 :                 DEBUG(10,("%s: skip break\n", __func__));
    1006          34 :                 return;
    1007             :         }
    1008             : 
    1009         548 :         if (break_from == SMB2_LEASE_NONE) {
    1010           0 :                 struct file_id_buf idbuf;
    1011           0 :                 DBG_NOTICE("Already downgraded oplock to none on %s: %s\n",
    1012             :                            file_id_str_buf(fsp->file_id, &idbuf),
    1013             :                            fsp_str_dbg(fsp));
    1014           0 :                 return;
    1015             :         }
    1016             : 
    1017         548 :         DEBUG(10, ("break_from=%u, break_to=%u\n",
    1018             :                    (unsigned)break_from, (unsigned)break_to));
    1019             : 
    1020         548 :         if (break_from == break_to) {
    1021           0 :                 struct file_id_buf idbuf;
    1022           0 :                 DBG_NOTICE("Already downgraded oplock to %u on %s: %s\n",
    1023             :                            (unsigned)break_to,
    1024             :                            file_id_str_buf(fsp->file_id, &idbuf),
    1025             :                            fsp_str_dbg(fsp));
    1026           0 :                 return;
    1027             :         }
    1028             : 
    1029             :         /* Need to wait before sending a break
    1030             :            message if we sent ourselves this message. */
    1031         548 :         if (server_id_equal(&self, &src)) {
    1032         223 :                 wait_before_sending_break();
    1033             :         }
    1034             : 
    1035             : #if defined(WITH_SMB1SERVER)
    1036         548 :         if (sconn->using_smb2) {
    1037             : #endif
    1038         422 :                 send_break_message_smb2(fsp, break_from, break_to);
    1039             : #if defined(WITH_SMB1SERVER)
    1040             :         } else {
    1041         126 :                 send_break_message_smb1(fsp, (break_to & SMB2_LEASE_READ) ?
    1042             :                                         OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
    1043             :         }
    1044             : #endif
    1045             : 
    1046         548 :         if ((break_from == SMB2_LEASE_READ) &&
    1047           0 :             (break_to == SMB2_LEASE_NONE)) {
    1048             :                 /*
    1049             :                  * This is an async break without a reply and thus no timeout
    1050             :                  *
    1051             :                  * leases are handled above.
    1052             :                  */
    1053          83 :                 if (fsp->oplock_type != LEASE_OPLOCK) {
    1054          61 :                         remove_oplock(fsp);
    1055             :                 }
    1056          83 :                 return;
    1057             :         }
    1058         465 :         if (fsp->oplock_type == LEASE_OPLOCK) {
    1059         162 :                 return;
    1060             :         }
    1061             : 
    1062         606 :         fsp->sent_oplock_break = (break_to & SMB2_LEASE_READ) ?
    1063         303 :                 LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
    1064             : 
    1065         303 :         add_oplock_timeout_handler(fsp);
    1066             : }
    1067             : 
    1068             : /*******************************************************************
    1069             :  This handles the kernel oplock break message.
    1070             : *******************************************************************/
    1071             : 
    1072           4 : static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
    1073             :                                         void *private_data,
    1074             :                                         uint32_t msg_type,
    1075             :                                         struct server_id src,
    1076             :                                         DATA_BLOB *data)
    1077             : {
    1078           0 :         struct file_id id;
    1079           0 :         struct file_id_buf idbuf;
    1080           0 :         unsigned long file_id;
    1081           0 :         files_struct *fsp;
    1082           0 :         struct smbd_server_connection *sconn =
    1083           4 :                 talloc_get_type_abort(private_data,
    1084             :                 struct smbd_server_connection);
    1085           0 :         struct server_id_buf tmp;
    1086             : 
    1087           4 :         if (data->data == NULL) {
    1088           0 :                 DEBUG(0, ("Got NULL buffer\n"));
    1089           0 :                 return;
    1090             :         }
    1091             : 
    1092           4 :         if (data->length != MSG_SMB_KERNEL_BREAK_SIZE) {
    1093           0 :                 DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
    1094           0 :                 return;
    1095             :         }
    1096             : 
    1097             :         /* Pull the data from the message. */
    1098           4 :         pull_file_id_24((char *)data->data, &id);
    1099           4 :         file_id = (unsigned long)IVAL(data->data, 24);
    1100             : 
    1101           4 :         DBG_DEBUG("Got kernel oplock break message from pid %s: %s/%u\n",
    1102             :                   server_id_str_buf(src, &tmp),
    1103             :                   file_id_str_buf(id, &idbuf),
    1104             :                   (unsigned int)file_id);
    1105             : 
    1106           4 :         fsp = initial_break_processing(sconn, id, file_id);
    1107             : 
    1108           4 :         if (fsp == NULL) {
    1109           0 :                 DEBUG(3, ("Got a kernel oplock break message for a file "
    1110             :                           "I don't know about\n"));
    1111           0 :                 return;
    1112             :         }
    1113             : 
    1114           4 :         if (fsp->sent_oplock_break != NO_BREAK_SENT) {
    1115             :                 /* This is ok, kernel oplocks come in completely async */
    1116           0 :                 DEBUG(3, ("Got a kernel oplock request while waiting for a "
    1117             :                           "break reply\n"));
    1118           0 :                 return;
    1119             :         }
    1120             : 
    1121             : #if defined(WITH_SMB1SERVER)
    1122           4 :         if (sconn->using_smb2) {
    1123             : #endif
    1124           4 :                 send_break_message_smb2(fsp, 0, OPLOCKLEVEL_NONE);
    1125             : #if defined(WITH_SMB1SERVER)
    1126             :         } else {
    1127           0 :                 send_break_message_smb1(fsp, OPLOCKLEVEL_NONE);
    1128             :         }
    1129             : #endif
    1130             : 
    1131           4 :         fsp->sent_oplock_break = BREAK_TO_NONE_SENT;
    1132             : 
    1133           4 :         add_oplock_timeout_handler(fsp);
    1134             : }
    1135             : 
    1136          84 : static void send_break_to_none(struct messaging_context *msg_ctx,
    1137             :                                const struct file_id *id,
    1138             :                                const struct share_mode_entry *e)
    1139             : {
    1140           0 :         NTSTATUS status;
    1141          84 :         status = send_break_message(msg_ctx, id, e, OPLOCK_NONE);
    1142          84 :         if (!NT_STATUS_IS_OK(status)) {
    1143           0 :                 DBG_DEBUG("send_break_message failed: %s\n",
    1144             :                           nt_errstr(status));
    1145             :         }
    1146          84 : }
    1147             : struct break_to_none_state {
    1148             :         struct smbd_server_connection *sconn;
    1149             :         struct file_id id;
    1150             :         struct smb2_lease_key lease_key;
    1151             :         struct GUID client_guid;
    1152             :         size_t num_read_leases;
    1153             :         uint32_t total_lease_types;
    1154             : };
    1155             : 
    1156          74 : static bool do_break_lease_to_none(struct share_mode_entry *e,
    1157             :                                    void *private_data)
    1158             : {
    1159          74 :         struct break_to_none_state *state = private_data;
    1160          74 :         uint32_t current_state = 0;
    1161           0 :         bool our_own;
    1162           0 :         NTSTATUS status;
    1163             : 
    1164          74 :         DBG_DEBUG("lease_key=%"PRIu64"/%"PRIu64"\n",
    1165             :                   e->lease_key.data[0],
    1166             :                   e->lease_key.data[1]);
    1167             : 
    1168          74 :         status = leases_db_get(&e->client_guid,
    1169          74 :                                &e->lease_key,
    1170          74 :                                &state->id,
    1171             :                                &current_state,
    1172             :                                NULL, /* breaking */
    1173             :                                NULL, /* breaking_to_requested */
    1174             :                                NULL, /* breaking_to_required */
    1175             :                                NULL, /* lease_version */
    1176             :                                NULL); /* epoch */
    1177          74 :         if (!NT_STATUS_IS_OK(status)) {
    1178           0 :                 DBG_WARNING("leases_db_get failed: %s\n",
    1179             :                             nt_errstr(status));
    1180           0 :                 return false;
    1181             :         }
    1182             : 
    1183          74 :         state->total_lease_types |= current_state;
    1184             : 
    1185          74 :         if ((current_state & SMB2_LEASE_READ) == 0) {
    1186          26 :                 return false;
    1187             :         }
    1188             : 
    1189          48 :         state->num_read_leases += 1;
    1190             : 
    1191          48 :         our_own = smb2_lease_equal(&state->client_guid,
    1192          48 :                                    &state->lease_key,
    1193          48 :                                    &e->client_guid,
    1194          48 :                                    &e->lease_key);
    1195          48 :         if (our_own) {
    1196          18 :                 DEBUG(10, ("Don't break our own lease\n"));
    1197          18 :                 return false;
    1198             :         }
    1199             : 
    1200          30 :         DBG_DEBUG("Breaking %"PRIu64"/%"PRIu64" to none\n",
    1201             :                   e->lease_key.data[0],
    1202             :                   e->lease_key.data[1]);
    1203             : 
    1204          30 :         send_break_to_none(state->sconn->msg_ctx, &state->id, e);
    1205             : 
    1206          30 :         return false;
    1207             : }
    1208             : 
    1209         160 : static bool do_break_oplock_to_none(struct share_mode_entry *e,
    1210             :                                     bool *modified,
    1211             :                                     void *private_data)
    1212             : {
    1213         160 :         struct break_to_none_state *state = private_data;
    1214             : 
    1215         160 :         if (e->op_type == LEASE_OPLOCK) {
    1216             :                 /*
    1217             :                  * Already being taken care of
    1218             :                  */
    1219          74 :                 return false;
    1220             :         }
    1221             : 
    1222             :         /*
    1223             :          * As there could have been multiple writes waiting at the
    1224             :          * lock_share_entry gate we may not be the first to
    1225             :          * enter. Hence the state of the op_types in the share mode
    1226             :          * entries may be partly NO_OPLOCK and partly LEVEL_II
    1227             :          * oplock. It will do no harm to re-send break messages to
    1228             :          * those smbd's that are still waiting their turn to remove
    1229             :          * their LEVEL_II state, and also no harm to ignore existing
    1230             :          * NO_OPLOCK states. JRA.
    1231             :          */
    1232             : 
    1233          86 :         DBG_DEBUG("e->op_type == %d\n", e->op_type);
    1234             : 
    1235          86 :         state->total_lease_types |= map_oplock_to_lease_type(e->op_type);
    1236             : 
    1237          86 :         if (e->op_type == NO_OPLOCK) {
    1238          32 :                 return false;
    1239             :         }
    1240             : 
    1241          54 :         state->num_read_leases += 1;
    1242             : 
    1243             :         /* Paranoia .... */
    1244          54 :         SMB_ASSERT(!EXCLUSIVE_OPLOCK_TYPE(e->op_type));
    1245             : 
    1246          54 :         send_break_to_none(state->sconn->msg_ctx, &state->id, e);
    1247             : 
    1248          54 :         return false;
    1249             : }
    1250             : 
    1251             : /****************************************************************************
    1252             :  This function is called on any file modification or lock request. If a file
    1253             :  is level 2 oplocked then it must tell all other level 2 holders to break to
    1254             :  none.
    1255             : ****************************************************************************/
    1256             : 
    1257      201852 : static void contend_level2_oplocks_begin_default(files_struct *fsp,
    1258             :                                               enum level2_contention_type type)
    1259             : {
    1260      201852 :         struct break_to_none_state state = {
    1261      201852 :                 .sconn = fsp->conn->sconn, .id = fsp->file_id,
    1262             :         };
    1263      201852 :         struct share_mode_lock *lck = NULL;
    1264      201852 :         uint32_t fsp_lease = fsp_lease_type(fsp);
    1265         118 :         bool ok, has_read_lease;
    1266             : 
    1267             :         /*
    1268             :          * If this file is level II oplocked then we need
    1269             :          * to grab the shared memory lock and inform all
    1270             :          * other files with a level II lock that they need
    1271             :          * to flush their read caches. We keep the lock over
    1272             :          * the shared memory area whilst doing this.
    1273             :          */
    1274             : 
    1275      201852 :         if (fsp_lease & SMB2_LEASE_WRITE) {
    1276             :                 /*
    1277             :                  * There can't be any level2 oplocks, we're alone.
    1278             :                  */
    1279      201772 :                 return;
    1280             :         }
    1281             : 
    1282      201670 :         has_read_lease = file_has_read_lease(fsp);
    1283      201670 :         if (!has_read_lease) {
    1284      201580 :                 DEBUG(10, ("No read oplocks around\n"));
    1285      201580 :                 return;
    1286             :         }
    1287             : 
    1288          90 :         if (fsp->oplock_type == LEASE_OPLOCK) {
    1289          34 :                 state.client_guid = *fsp_client_guid(fsp);
    1290          34 :                 state.lease_key = fsp->lease->lease.lease_key;
    1291          34 :                 DEBUG(10, ("Breaking through lease key %"PRIu64"/%"PRIu64"\n",
    1292             :                            state.lease_key.data[0],
    1293             :                            state.lease_key.data[1]));
    1294             :         }
    1295             : 
    1296          90 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
    1297          90 :         if (lck == NULL) {
    1298           0 :                 struct file_id_buf idbuf;
    1299          10 :                 DBG_WARNING("failed to lock share mode entry for file %s.\n",
    1300             :                             file_id_str_buf(state.id, &idbuf));
    1301          10 :                 return;
    1302             :         }
    1303             : 
    1304             :         /*
    1305             :          * Walk leases and oplocks separately: We have to send one break per
    1306             :          * lease. If we have multiple share_mode_entry having a common lease,
    1307             :          * we would break the lease twice if we don't walk the leases list
    1308             :          * separately.
    1309             :          */
    1310             : 
    1311          80 :         ok = share_mode_forall_leases(lck, do_break_lease_to_none, &state);
    1312          80 :         if (!ok) {
    1313           0 :                 DBG_WARNING("share_mode_forall_leases failed\n");
    1314             :         }
    1315             : 
    1316          80 :         ok = share_mode_forall_entries(lck, do_break_oplock_to_none, &state);
    1317          80 :         if (!ok) {
    1318           0 :                 DBG_WARNING("share_mode_forall_entries failed\n");
    1319             :         }
    1320             : 
    1321             :         {
    1322             :                 /*
    1323             :                  * Lazy update here. It might be that all leases
    1324             :                  * have gone in the meantime.
    1325             :                  */
    1326           0 :                 uint32_t acc, sh, ls;
    1327          80 :                 share_mode_flags_get(lck, &acc, &sh, &ls);
    1328          80 :                 ls = state.total_lease_types;
    1329          80 :                 share_mode_flags_set(lck, acc, sh, ls, NULL);
    1330             :         }
    1331             : 
    1332          80 :         TALLOC_FREE(lck);
    1333             : }
    1334             : 
    1335      201852 : void smbd_contend_level2_oplocks_begin(files_struct *fsp,
    1336             :                                   enum level2_contention_type type)
    1337             : {
    1338      201852 :         contend_level2_oplocks_begin_default(fsp, type);
    1339      201852 : }
    1340             : 
    1341      201444 : void smbd_contend_level2_oplocks_end(files_struct *fsp,
    1342             :                                 enum level2_contention_type type)
    1343             : {
    1344      201444 :         return;
    1345             : }
    1346             : 
    1347             : /****************************************************************************
    1348             :  Linearize a share mode entry struct to an internal oplock break message.
    1349             : ****************************************************************************/
    1350             : 
    1351           0 : void share_mode_entry_to_message(char *msg, const struct file_id *id,
    1352             :                                  const struct share_mode_entry *e)
    1353             : {
    1354           0 :         SIVAL(msg,OP_BREAK_MSG_PID_OFFSET,(uint32_t)e->pid.pid);
    1355           0 :         SBVAL(msg,OP_BREAK_MSG_MID_OFFSET,e->op_mid);
    1356           0 :         SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET,e->op_type);
    1357           0 :         SIVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET,e->access_mask);
    1358           0 :         SIVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET,e->share_access);
    1359           0 :         SIVAL(msg,OP_BREAK_MSG_PRIV_OFFSET,e->private_options);
    1360           0 :         SIVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET,(uint32_t)e->time.tv_sec);
    1361           0 :         SIVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET,(uint32_t)e->time.tv_usec);
    1362             :         /*
    1363             :          * "id" used to be part of share_mode_entry, thus the strange
    1364             :          * place to put this. Feel free to move somewhere else :-)
    1365             :          */
    1366           0 :         push_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, id);
    1367           0 :         SIVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET,e->share_file_id);
    1368           0 :         SIVAL(msg,OP_BREAK_MSG_UID_OFFSET,e->uid);
    1369           0 :         SSVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET,e->flags);
    1370           0 :         SIVAL(msg,OP_BREAK_MSG_NAME_HASH_OFFSET,e->name_hash);
    1371           0 :         SIVAL(msg,OP_BREAK_MSG_VNN_OFFSET,e->pid.vnn);
    1372           0 : }
    1373             : 
    1374             : /****************************************************************************
    1375             :  De-linearize an internal oplock break message to a share mode entry struct.
    1376             : ****************************************************************************/
    1377             : 
    1378           0 : void message_to_share_mode_entry(struct file_id *id,
    1379             :                                  struct share_mode_entry *e,
    1380             :                                  const char *msg)
    1381             : {
    1382           0 :         e->pid = (struct server_id){
    1383           0 :                 .pid = (pid_t)IVAL(msg, OP_BREAK_MSG_PID_OFFSET),
    1384           0 :                 .vnn = IVAL(msg, OP_BREAK_MSG_VNN_OFFSET),
    1385             :         };
    1386           0 :         e->op_mid = BVAL(msg,OP_BREAK_MSG_MID_OFFSET);
    1387           0 :         e->op_type = SVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET);
    1388           0 :         e->access_mask = IVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET);
    1389           0 :         e->share_access = IVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET);
    1390           0 :         e->private_options = IVAL(msg,OP_BREAK_MSG_PRIV_OFFSET);
    1391           0 :         e->time.tv_sec = (time_t)IVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET);
    1392           0 :         e->time.tv_usec = (int)IVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET);
    1393             :         /*
    1394             :          * "id" used to be part of share_mode_entry, thus the strange
    1395             :          * place to put this. Feel free to move somewhere else :-)
    1396             :          */
    1397           0 :         pull_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, id);
    1398           0 :         e->share_file_id = (unsigned long)IVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET);
    1399           0 :         e->uid = (uint32_t)IVAL(msg,OP_BREAK_MSG_UID_OFFSET);
    1400           0 :         e->flags = (uint16_t)SVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET);
    1401           0 :         e->name_hash = IVAL(msg, OP_BREAK_MSG_NAME_HASH_OFFSET);
    1402           0 : }
    1403             : 
    1404             : /****************************************************************************
    1405             :  Setup oplocks for this process.
    1406             : ****************************************************************************/
    1407             : 
    1408       35395 : bool init_oplocks(struct smbd_server_connection *sconn)
    1409             : {
    1410       35395 :         DEBUG(3,("init_oplocks: initializing messages.\n"));
    1411             : 
    1412       35395 :         messaging_register(sconn->msg_ctx, sconn, MSG_SMB_BREAK_REQUEST,
    1413             :                            process_oplock_break_message);
    1414       35395 :         messaging_register(sconn->msg_ctx, sconn, MSG_SMB_KERNEL_BREAK,
    1415             :                            process_kernel_oplock_break);
    1416       35395 :         return true;
    1417             : }
    1418             : 
    1419          17 : void init_kernel_oplocks(struct smbd_server_connection *sconn)
    1420             : {
    1421          17 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
    1422             : 
    1423             :         /* only initialize once */
    1424          17 :         if (koplocks == NULL) {
    1425             : #ifdef HAVE_KERNEL_OPLOCKS_LINUX
    1426          17 :                 koplocks = linux_init_kernel_oplocks(sconn);
    1427             : #endif
    1428          17 :                 sconn->oplocks.kernel_ops = koplocks;
    1429             :         }
    1430          17 : }

Generated by: LCOV version 1.14