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