LCOV - code coverage report
Current view: top level - source3/smbd - smb2_oplock.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 410 558 73.5 %
Date: 2024-05-31 13:13:24 Functions: 28 28 100.0 %

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

Generated by: LCOV version 1.14