LCOV - code coverage report
Current view: top level - source3/smbd - oplock.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 421 549 76.7 %
Date: 2021-08-25 13:27:56 Functions: 31 34 91.2 %

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

Generated by: LCOV version 1.13