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