Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : smbd scavenger daemon
4 :
5 : Copyright (C) Gregor Beck 2013
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "messages.h"
23 : #include "serverid.h"
24 : #include "smbd/globals.h"
25 : #include "smbd/smbXsrv_open.h"
26 : #include "smbd/scavenger.h"
27 : #include "locking/share_mode_lock.h"
28 : #include "locking/leases_db.h"
29 : #include "locking/proto.h"
30 : #include "librpc/gen_ndr/open_files.h"
31 : #include "lib/util/server_id.h"
32 : #include "lib/util/util_process.h"
33 : #include "lib/util/sys_rw_data.h"
34 :
35 : #undef DBGC_CLASS
36 : #define DBGC_CLASS DBGC_SCAVENGER
37 :
38 : struct smbd_scavenger_state {
39 : struct tevent_context *ev;
40 : struct messaging_context *msg;
41 : struct server_id parent_id;
42 : struct server_id *scavenger_id;
43 : bool am_scavenger;
44 : };
45 :
46 : static struct smbd_scavenger_state *smbd_scavenger_state = NULL;
47 :
48 : struct scavenger_message {
49 : struct file_id file_id;
50 : uint64_t open_persistent_id;
51 : NTTIME until;
52 : };
53 :
54 0 : static int smbd_scavenger_main(struct smbd_scavenger_state *state)
55 : {
56 : struct server_id_buf tmp1, tmp2;
57 :
58 0 : DEBUG(10, ("scavenger: %s started, parent: %s\n",
59 : server_id_str_buf(*state->scavenger_id, &tmp1),
60 : server_id_str_buf(state->parent_id, &tmp2)));
61 :
62 0 : while (true) {
63 0 : TALLOC_CTX *frame = talloc_stackframe();
64 : int ret;
65 :
66 0 : ret = tevent_loop_once(state->ev);
67 0 : if (ret != 0) {
68 0 : DEBUG(2, ("tevent_loop_once failed: %s\n",
69 : strerror(errno)));
70 0 : TALLOC_FREE(frame);
71 0 : return 1;
72 : }
73 :
74 0 : DEBUG(10, ("scavenger: %s event loop iteration\n",
75 : server_id_str_buf(*state->scavenger_id, &tmp1)));
76 0 : TALLOC_FREE(frame);
77 : }
78 :
79 : return 0;
80 : }
81 :
82 0 : static void smbd_scavenger_done(struct tevent_context *event_ctx, struct tevent_fd *fde,
83 : uint16_t flags, void *private_data)
84 : {
85 0 : struct smbd_scavenger_state *state = talloc_get_type_abort(
86 : private_data, struct smbd_scavenger_state);
87 : struct server_id_buf tmp;
88 :
89 0 : DEBUG(2, ("scavenger: %s died\n",
90 : server_id_str_buf(*state->scavenger_id, &tmp)));
91 :
92 0 : TALLOC_FREE(state->scavenger_id);
93 0 : }
94 :
95 0 : static void smbd_scavenger_parent_dead(struct tevent_context *event_ctx,
96 : struct tevent_fd *fde,
97 : uint16_t flags, void *private_data)
98 : {
99 0 : struct smbd_scavenger_state *state = talloc_get_type_abort(
100 : private_data, struct smbd_scavenger_state);
101 : struct server_id_buf tmp1, tmp2;
102 :
103 0 : DEBUG(2, ("scavenger: %s parent %s died\n",
104 : server_id_str_buf(*state->scavenger_id, &tmp1),
105 : server_id_str_buf(state->parent_id, &tmp2)));
106 :
107 0 : exit_server_cleanly("smbd_scavenger_parent_dead");
108 : }
109 :
110 0 : static void scavenger_sig_term_handler(struct tevent_context *ev,
111 : struct tevent_signal *se,
112 : int signum,
113 : int count,
114 : void *siginfo,
115 : void *private_data)
116 : {
117 0 : exit_server_cleanly("termination signal");
118 : }
119 :
120 0 : static void scavenger_setup_sig_term_handler(struct tevent_context *ev_ctx)
121 : {
122 : struct tevent_signal *se;
123 :
124 0 : se = tevent_add_signal(ev_ctx,
125 : ev_ctx,
126 : SIGTERM, 0,
127 : scavenger_sig_term_handler,
128 : NULL);
129 0 : if (se == NULL) {
130 0 : exit_server("failed to setup SIGTERM handler");
131 : }
132 0 : }
133 :
134 0 : static bool smbd_scavenger_running(struct smbd_scavenger_state *state)
135 : {
136 0 : if (state->scavenger_id == NULL) {
137 0 : return false;
138 : }
139 :
140 0 : return serverid_exists(state->scavenger_id);
141 : }
142 :
143 0 : static int smbd_scavenger_server_id_destructor(struct server_id *id)
144 : {
145 0 : return 0;
146 : }
147 :
148 0 : static bool scavenger_say_hello(int fd, struct server_id self)
149 : {
150 : ssize_t ret;
151 : struct server_id_buf tmp;
152 :
153 0 : ret = write_data(fd, &self, sizeof(self));
154 0 : if (ret == -1) {
155 0 : DEBUG(2, ("Failed to write to pipe: %s\n", strerror(errno)));
156 0 : return false;
157 : }
158 0 : if (ret < sizeof(self)) {
159 0 : DBG_WARNING("Could not write serverid\n");
160 0 : return false;
161 : }
162 :
163 0 : DEBUG(4, ("scavenger_say_hello: self[%s]\n",
164 : server_id_str_buf(self, &tmp)));
165 0 : return true;
166 : }
167 :
168 0 : static bool scavenger_wait_hello(int fd, struct server_id *child)
169 : {
170 : struct server_id_buf tmp;
171 : ssize_t ret;
172 :
173 0 : ret = read_data(fd, child, sizeof(struct server_id));
174 0 : if (ret == -1) {
175 0 : DEBUG(2, ("Failed to read from pipe: %s\n",
176 : strerror(errno)));
177 0 : return false;
178 : }
179 0 : if (ret < sizeof(struct server_id)) {
180 0 : DBG_WARNING("Could not read serverid\n");
181 0 : return false;
182 : }
183 :
184 0 : DEBUG(4, ("scavenger_say_hello: child[%s]\n",
185 : server_id_str_buf(*child, &tmp)));
186 0 : return true;
187 : }
188 :
189 0 : static bool smbd_scavenger_start(struct smbd_scavenger_state *state)
190 : {
191 0 : struct server_id self = messaging_server_id(state->msg);
192 0 : struct tevent_fd *fde = NULL;
193 : int fds[2];
194 : int ret;
195 : bool ok;
196 :
197 0 : SMB_ASSERT(server_id_equal(&state->parent_id, &self));
198 :
199 0 : if (smbd_scavenger_running(state)) {
200 : struct server_id_buf tmp;
201 0 : DEBUG(10, ("scavenger %s already running\n",
202 : server_id_str_buf(*state->scavenger_id,
203 : &tmp)));
204 0 : return true;
205 : }
206 :
207 0 : if (state->scavenger_id != NULL) {
208 : struct server_id_buf tmp;
209 0 : DEBUG(10, ("scavenger zombie %s, cleaning up\n",
210 : server_id_str_buf(*state->scavenger_id,
211 : &tmp)));
212 0 : TALLOC_FREE(state->scavenger_id);
213 : }
214 :
215 0 : state->scavenger_id = talloc_zero(state, struct server_id);
216 0 : if (state->scavenger_id == NULL) {
217 0 : DEBUG(2, ("Out of memory\n"));
218 0 : goto fail;
219 : }
220 0 : talloc_set_destructor(state->scavenger_id,
221 : smbd_scavenger_server_id_destructor);
222 :
223 0 : ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
224 0 : if (ret == -1) {
225 0 : DEBUG(2, ("socketpair failed: %s", strerror(errno)));
226 0 : goto fail;
227 : }
228 :
229 0 : smb_set_close_on_exec(fds[0]);
230 0 : smb_set_close_on_exec(fds[1]);
231 :
232 0 : ret = fork();
233 0 : if (ret == -1) {
234 0 : int err = errno;
235 0 : close(fds[0]);
236 0 : close(fds[1]);
237 0 : DEBUG(0, ("fork failed: %s", strerror(err)));
238 0 : goto fail;
239 : }
240 :
241 0 : if (ret == 0) {
242 : /* child */
243 :
244 : NTSTATUS status;
245 :
246 0 : close(fds[0]);
247 :
248 0 : status = smbd_reinit_after_fork(state->msg, state->ev,
249 : true, "smbd-scavenger");
250 0 : if (!NT_STATUS_IS_OK(status)) {
251 0 : DEBUG(2, ("reinit_after_fork failed: %s\n",
252 : nt_errstr(status)));
253 0 : exit_server("reinit_after_fork failed");
254 : return false;
255 : }
256 :
257 0 : reopen_logs();
258 :
259 0 : state->am_scavenger = true;
260 0 : *state->scavenger_id = messaging_server_id(state->msg);
261 :
262 0 : scavenger_setup_sig_term_handler(state->ev);
263 :
264 0 : ok = scavenger_say_hello(fds[1], *state->scavenger_id);
265 0 : if (!ok) {
266 0 : DEBUG(2, ("scavenger_say_hello failed\n"));
267 0 : exit_server("scavenger_say_hello failed");
268 : return false;
269 : }
270 :
271 0 : fde = tevent_add_fd(state->ev, state->scavenger_id,
272 : fds[1], TEVENT_FD_READ,
273 : smbd_scavenger_parent_dead, state);
274 0 : if (fde == NULL) {
275 0 : DEBUG(2, ("tevent_add_fd(smbd_scavenger_parent_dead) "
276 : "failed\n"));
277 0 : exit_server("tevent_add_fd(smbd_scavenger_parent_dead) "
278 : "failed");
279 : return false;
280 : }
281 0 : tevent_fd_set_auto_close(fde);
282 :
283 0 : ret = smbd_scavenger_main(state);
284 :
285 0 : DEBUG(10, ("scavenger ended: %d\n", ret));
286 0 : exit_server_cleanly("scavenger ended");
287 : return false;
288 : }
289 :
290 : /* parent */
291 0 : close(fds[1]);
292 :
293 0 : ok = scavenger_wait_hello(fds[0], state->scavenger_id);
294 0 : if (!ok) {
295 0 : close(fds[0]);
296 0 : goto fail;
297 : }
298 :
299 0 : fde = tevent_add_fd(state->ev, state->scavenger_id,
300 : fds[0], TEVENT_FD_READ,
301 : smbd_scavenger_done, state);
302 0 : if (fde == NULL) {
303 0 : close(fds[0]);
304 0 : goto fail;
305 : }
306 0 : tevent_fd_set_auto_close(fde);
307 :
308 0 : return true;
309 0 : fail:
310 0 : TALLOC_FREE(state->scavenger_id);
311 0 : return false;
312 : }
313 :
314 : static void scavenger_add_timer(struct smbd_scavenger_state *state,
315 : struct scavenger_message *msg);
316 :
317 0 : static void smbd_scavenger_msg(struct messaging_context *msg_ctx,
318 : void *private_data,
319 : uint32_t msg_type,
320 : struct server_id src,
321 : DATA_BLOB *data)
322 : {
323 0 : struct smbd_scavenger_state *state =
324 0 : talloc_get_type_abort(private_data,
325 : struct smbd_scavenger_state);
326 0 : TALLOC_CTX *frame = talloc_stackframe();
327 0 : struct server_id self = messaging_server_id(msg_ctx);
328 0 : struct scavenger_message *msg = NULL;
329 : struct server_id_buf tmp1, tmp2;
330 :
331 0 : DEBUG(10, ("smbd_scavenger_msg: %s got message from %s\n",
332 : server_id_str_buf(self, &tmp1),
333 : server_id_str_buf(src, &tmp2)));
334 :
335 0 : if (server_id_equal(&state->parent_id, &self)) {
336 : NTSTATUS status;
337 :
338 0 : if (!smbd_scavenger_running(state) &&
339 0 : !smbd_scavenger_start(state))
340 : {
341 0 : DEBUG(2, ("Failed to start scavenger\n"));
342 0 : goto done;
343 : }
344 0 : DEBUG(10, ("forwarding message to scavenger\n"));
345 :
346 0 : status = messaging_send(msg_ctx,
347 0 : *state->scavenger_id, msg_type, data);
348 0 : if (!NT_STATUS_IS_OK(status)) {
349 0 : DEBUG(2, ("forwarding message to scavenger failed: "
350 : "%s\n", nt_errstr(status)));
351 0 : goto done;
352 : }
353 0 : goto done;
354 : }
355 :
356 0 : if (!state->am_scavenger) {
357 0 : DEBUG(10, ("im not the scavenger: ignore message\n"));
358 0 : goto done;
359 : }
360 :
361 0 : if (!server_id_equal(&state->parent_id, &src)) {
362 0 : DEBUG(10, ("scavenger: ignore spurious message\n"));
363 0 : goto done;
364 : }
365 :
366 0 : DEBUG(10, ("scavenger: got a message\n"));
367 0 : msg = (struct scavenger_message*)data->data;
368 0 : scavenger_add_timer(state, msg);
369 0 : done:
370 0 : talloc_free(frame);
371 0 : }
372 :
373 39 : bool smbd_scavenger_init(TALLOC_CTX *mem_ctx,
374 : struct messaging_context *msg,
375 : struct tevent_context *ev)
376 : {
377 : struct smbd_scavenger_state *state;
378 : NTSTATUS status;
379 :
380 39 : if (smbd_scavenger_state) {
381 0 : DEBUG(10, ("smbd_scavenger_init called again\n"));
382 0 : return true;
383 : }
384 :
385 39 : state = talloc_zero(mem_ctx, struct smbd_scavenger_state);
386 39 : if (state == NULL) {
387 0 : DEBUG(2, ("Out of memory\n"));
388 0 : return false;
389 : }
390 :
391 39 : state->msg = msg;
392 39 : state->ev = ev;
393 39 : state->parent_id = messaging_server_id(msg);
394 :
395 39 : status = messaging_register(msg, state, MSG_SMB_SCAVENGER,
396 : smbd_scavenger_msg);
397 39 : if (!NT_STATUS_IS_OK(status)) {
398 0 : DEBUG(2, ("failed to register message handler: %s\n",
399 : nt_errstr(status)));
400 0 : goto fail;
401 : }
402 :
403 39 : smbd_scavenger_state = state;
404 39 : return true;
405 0 : fail:
406 0 : talloc_free(state);
407 0 : return false;
408 : }
409 :
410 0 : void scavenger_schedule_disconnected(struct files_struct *fsp)
411 : {
412 : NTSTATUS status;
413 0 : struct server_id self = messaging_server_id(fsp->conn->sconn->msg_ctx);
414 : struct timeval disconnect_time, until;
415 : uint64_t timeout_usec;
416 : struct scavenger_message msg;
417 : DATA_BLOB msg_blob;
418 : struct server_id_buf tmp;
419 : struct file_id_buf idbuf;
420 :
421 0 : if (fsp->op == NULL) {
422 0 : return;
423 : }
424 0 : nttime_to_timeval(&disconnect_time, fsp->op->global->disconnect_time);
425 0 : timeout_usec = 1000 * fsp->op->global->durable_timeout_msec;
426 0 : until = timeval_add(&disconnect_time,
427 0 : timeout_usec / 1000000,
428 0 : timeout_usec % 1000000);
429 :
430 0 : ZERO_STRUCT(msg);
431 0 : msg.file_id = fsp->file_id;
432 0 : msg.open_persistent_id = fsp->op->global->open_persistent_id;
433 0 : msg.until = timeval_to_nttime(&until);
434 :
435 0 : DEBUG(10, ("smbd: %s mark file %s as disconnected at %s with timeout "
436 : "at %s in %fs\n",
437 : server_id_str_buf(self, &tmp),
438 : file_id_str_buf(fsp->file_id, &idbuf),
439 : timeval_string(talloc_tos(), &disconnect_time, true),
440 : timeval_string(talloc_tos(), &until, true),
441 : fsp->op->global->durable_timeout_msec/1000.0));
442 :
443 0 : SMB_ASSERT(server_id_is_disconnected(&fsp->op->global->server_id));
444 0 : SMB_ASSERT(!server_id_equal(&self, &smbd_scavenger_state->parent_id));
445 0 : SMB_ASSERT(!smbd_scavenger_state->am_scavenger);
446 :
447 0 : msg_blob = data_blob_const(&msg, sizeof(msg));
448 0 : DEBUG(10, ("send message to scavenger\n"));
449 :
450 0 : status = messaging_send(smbd_scavenger_state->msg,
451 0 : smbd_scavenger_state->parent_id,
452 : MSG_SMB_SCAVENGER,
453 : &msg_blob);
454 0 : if (!NT_STATUS_IS_OK(status)) {
455 : struct server_id_buf tmp1, tmp2;
456 0 : DEBUG(2, ("Failed to send message to parent smbd %s "
457 : "from %s: %s\n",
458 : server_id_str_buf(smbd_scavenger_state->parent_id,
459 : &tmp1),
460 : server_id_str_buf(self, &tmp2),
461 : nt_errstr(status)));
462 : }
463 : }
464 :
465 : struct scavenger_timer_context {
466 : struct smbd_scavenger_state *state;
467 : struct scavenger_message msg;
468 : };
469 :
470 : struct cleanup_disconnected_state {
471 : struct file_id fid;
472 : struct share_mode_lock *lck;
473 : uint64_t open_persistent_id;
474 : size_t num_disconnected;
475 : bool found_connected;
476 : };
477 :
478 0 : static bool cleanup_disconnected_lease(struct share_mode_entry *e,
479 : void *private_data)
480 : {
481 0 : struct cleanup_disconnected_state *state = private_data;
482 : NTSTATUS status;
483 :
484 0 : status = leases_db_del(&e->client_guid, &e->lease_key, &state->fid);
485 :
486 0 : if (!NT_STATUS_IS_OK(status)) {
487 0 : DBG_DEBUG("leases_db_del failed: %s\n",
488 : nt_errstr(status));
489 : }
490 :
491 0 : return false;
492 : }
493 :
494 0 : static bool share_mode_find_connected_fn(
495 : struct share_mode_entry *e,
496 : bool *modified,
497 : void *private_data)
498 : {
499 0 : struct cleanup_disconnected_state *state = private_data;
500 : bool disconnected;
501 :
502 0 : disconnected = server_id_is_disconnected(&e->pid);
503 0 : if (!disconnected) {
504 0 : char *name = share_mode_filename(talloc_tos(), state->lck);
505 : struct file_id_buf tmp1;
506 : struct server_id_buf tmp2;
507 0 : DBG_INFO("file (file-id='%s', servicepath='%s', name='%s') "
508 : "is used by server %s ==> do not cleanup\n",
509 : file_id_str_buf(state->fid, &tmp1),
510 : share_mode_servicepath(state->lck),
511 : name,
512 : server_id_str_buf(e->pid, &tmp2));
513 0 : TALLOC_FREE(name);
514 0 : state->found_connected = true;
515 0 : return true;
516 : }
517 :
518 0 : if (state->open_persistent_id != e->share_file_id) {
519 0 : char *name = share_mode_filename(talloc_tos(), state->lck);
520 : struct file_id_buf tmp;
521 0 : DBG_INFO("entry for file "
522 : "(file-id='%s', servicepath='%s', name='%s') "
523 : "has share_file_id %"PRIu64" but expected "
524 : "%"PRIu64"==> do not cleanup\n",
525 : file_id_str_buf(state->fid, &tmp),
526 : share_mode_servicepath(state->lck),
527 : name,
528 : e->share_file_id,
529 : state->open_persistent_id);
530 0 : TALLOC_FREE(name);
531 0 : state->found_connected = true;
532 0 : return true;
533 : }
534 :
535 0 : state->num_disconnected += 1;
536 :
537 0 : return false;
538 : }
539 :
540 0 : static bool cleanup_disconnected_share_mode_entry_fn(
541 : struct share_mode_entry *e,
542 : bool *modified,
543 : void *private_data)
544 : {
545 0 : struct cleanup_disconnected_state *state = private_data;
546 :
547 : bool disconnected;
548 :
549 0 : disconnected = server_id_is_disconnected(&e->pid);
550 0 : if (!disconnected) {
551 0 : char *name = share_mode_filename(talloc_tos(), state->lck);
552 : struct file_id_buf tmp1;
553 : struct server_id_buf tmp2;
554 0 : DBG_ERR("file (file-id='%s', servicepath='%s', name='%s') "
555 : "is used by server %s ==> internal error\n",
556 : file_id_str_buf(state->fid, &tmp1),
557 : share_mode_servicepath(state->lck),
558 : name,
559 : server_id_str_buf(e->pid, &tmp2));
560 0 : TALLOC_FREE(name);
561 0 : smb_panic(__location__);
562 : }
563 :
564 : /*
565 : * Setting e->stale = true is
566 : * the indication to delete the entry.
567 : */
568 0 : e->stale = true;
569 0 : return false;
570 : }
571 :
572 0 : static bool share_mode_cleanup_disconnected(
573 : struct file_id fid, uint64_t open_persistent_id)
574 : {
575 0 : struct cleanup_disconnected_state state = {
576 : .fid = fid,
577 : .open_persistent_id = open_persistent_id
578 : };
579 0 : bool ret = false;
580 0 : TALLOC_CTX *frame = talloc_stackframe();
581 0 : char *name = NULL;
582 : struct file_id_buf idbuf;
583 : bool ok;
584 :
585 0 : state.lck = get_existing_share_mode_lock(frame, fid);
586 0 : if (state.lck == NULL) {
587 0 : DBG_INFO("Could not fetch share mode entry for %s\n",
588 : file_id_str_buf(fid, &idbuf));
589 0 : goto done;
590 : }
591 0 : name = share_mode_filename(frame, state.lck);
592 :
593 0 : ok = share_mode_forall_entries(
594 : state.lck, share_mode_find_connected_fn, &state);
595 0 : if (!ok) {
596 0 : DBG_DEBUG("share_mode_forall_entries failed\n");
597 0 : goto done;
598 : }
599 0 : if (state.found_connected) {
600 0 : DBG_DEBUG("Found connected entry\n");
601 0 : goto done;
602 : }
603 :
604 0 : ok = share_mode_forall_leases(
605 : state.lck, cleanup_disconnected_lease, &state);
606 0 : if (!ok) {
607 0 : DBG_DEBUG("failed to clean up leases associated "
608 : "with file (file-id='%s', servicepath='%s', "
609 : "name='%s') and open_persistent_id %"PRIu64" "
610 : "==> do not cleanup\n",
611 : file_id_str_buf(fid, &idbuf),
612 : share_mode_servicepath(state.lck),
613 : name,
614 : open_persistent_id);
615 0 : goto done;
616 : }
617 :
618 0 : ok = brl_cleanup_disconnected(fid, open_persistent_id);
619 0 : if (!ok) {
620 0 : DBG_DEBUG("failed to clean up byte range locks associated "
621 : "with file (file-id='%s', servicepath='%s', "
622 : "name='%s') and open_persistent_id %"PRIu64" "
623 : "==> do not cleanup\n",
624 : file_id_str_buf(fid, &idbuf),
625 : share_mode_servicepath(state.lck),
626 : name,
627 : open_persistent_id);
628 0 : goto done;
629 : }
630 :
631 0 : DBG_DEBUG("cleaning up %zu entries for file "
632 : "(file-id='%s', servicepath='%s', name='%s') "
633 : "from open_persistent_id %"PRIu64"\n",
634 : state.num_disconnected,
635 : file_id_str_buf(fid, &idbuf),
636 : share_mode_servicepath(state.lck),
637 : name,
638 : open_persistent_id);
639 :
640 0 : ok = share_mode_forall_entries(
641 : state.lck, cleanup_disconnected_share_mode_entry_fn, &state);
642 0 : if (!ok) {
643 0 : DBG_DEBUG("failed to clean up %zu entries associated "
644 : "with file (file-id='%s', servicepath='%s', "
645 : "name='%s') and open_persistent_id %"PRIu64" "
646 : "==> do not cleanup\n",
647 : state.num_disconnected,
648 : file_id_str_buf(fid, &idbuf),
649 : share_mode_servicepath(state.lck),
650 : name,
651 : open_persistent_id);
652 0 : goto done;
653 : }
654 :
655 0 : ret = true;
656 0 : done:
657 0 : talloc_free(frame);
658 0 : return ret;
659 : }
660 :
661 0 : static void scavenger_timer(struct tevent_context *ev,
662 : struct tevent_timer *te,
663 : struct timeval t, void *data)
664 : {
665 0 : struct scavenger_timer_context *ctx =
666 0 : talloc_get_type_abort(data, struct scavenger_timer_context);
667 : struct file_id_buf idbuf;
668 : NTSTATUS status;
669 : bool ok;
670 :
671 0 : DBG_DEBUG("do cleanup for file %s at %s\n",
672 : file_id_str_buf(ctx->msg.file_id, &idbuf),
673 : timeval_string(talloc_tos(), &t, true));
674 :
675 0 : ok = share_mode_cleanup_disconnected(ctx->msg.file_id,
676 : ctx->msg.open_persistent_id);
677 0 : if (!ok) {
678 0 : DBG_WARNING("Failed to cleanup share modes and byte range "
679 : "locks for file %s open %"PRIu64"\n",
680 : file_id_str_buf(ctx->msg.file_id, &idbuf),
681 : ctx->msg.open_persistent_id);
682 : }
683 :
684 0 : status = smbXsrv_open_cleanup(ctx->msg.open_persistent_id);
685 0 : if (!NT_STATUS_IS_OK(status)) {
686 0 : DBG_WARNING("Failed to cleanup open global for file %s open "
687 : "%"PRIu64": %s\n",
688 : file_id_str_buf(ctx->msg.file_id, &idbuf),
689 : ctx->msg.open_persistent_id,
690 : nt_errstr(status));
691 : }
692 0 : }
693 :
694 0 : static void scavenger_add_timer(struct smbd_scavenger_state *state,
695 : struct scavenger_message *msg)
696 : {
697 : struct tevent_timer *te;
698 : struct scavenger_timer_context *ctx;
699 : struct timeval until;
700 : struct file_id_buf idbuf;
701 :
702 0 : nttime_to_timeval(&until, msg->until);
703 :
704 0 : DBG_DEBUG("schedule file %s for cleanup at %s\n",
705 : file_id_str_buf(msg->file_id, &idbuf),
706 : timeval_string(talloc_tos(), &until, true));
707 :
708 0 : ctx = talloc_zero(state, struct scavenger_timer_context);
709 0 : if (ctx == NULL) {
710 0 : DEBUG(2, ("Failed to talloc_zero(scavenger_timer_context)\n"));
711 0 : return;
712 : }
713 :
714 0 : ctx->state = state;
715 0 : ctx->msg = *msg;
716 :
717 0 : te = tevent_add_timer(state->ev,
718 : state,
719 : until,
720 : scavenger_timer,
721 : ctx);
722 0 : if (te == NULL) {
723 0 : DEBUG(2, ("Failed to add scavenger_timer event\n"));
724 0 : talloc_free(ctx);
725 0 : return;
726 : }
727 :
728 : /* delete context after handler was running */
729 0 : talloc_steal(te, ctx);
730 : }
|