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 : ¤t_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 : ¤t_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 : ¤t_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 : ¤t_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 : ¤t_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 : }
|