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 3 : static int smbd_scavenger_main(struct smbd_scavenger_state *state)
55 : {
56 0 : struct server_id_buf tmp1, tmp2;
57 :
58 3 : 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 265 : while (true) {
63 268 : TALLOC_CTX *frame = talloc_stackframe();
64 0 : int ret;
65 :
66 268 : ret = tevent_loop_once(state->ev);
67 265 : 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 265 : DEBUG(10, ("scavenger: %s event loop iteration\n",
75 : server_id_str_buf(*state->scavenger_id, &tmp1)));
76 265 : 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 0 : 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 2 : 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 2 : struct smbd_scavenger_state *state = talloc_get_type_abort(
100 : private_data, struct smbd_scavenger_state);
101 0 : struct server_id_buf tmp1, tmp2;
102 :
103 2 : 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 2 : exit_server_cleanly("smbd_scavenger_parent_dead");
108 : }
109 :
110 1 : 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 1 : exit_server_cleanly("termination signal");
118 : }
119 :
120 3 : static void scavenger_setup_sig_term_handler(struct tevent_context *ev_ctx)
121 : {
122 0 : struct tevent_signal *se;
123 :
124 3 : se = tevent_add_signal(ev_ctx,
125 : ev_ctx,
126 : SIGTERM, 0,
127 : scavenger_sig_term_handler,
128 : NULL);
129 3 : if (se == NULL) {
130 0 : exit_server("failed to setup SIGTERM handler");
131 : }
132 3 : }
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 3 : static bool scavenger_say_hello(int fd, struct server_id self)
149 : {
150 0 : ssize_t ret;
151 0 : struct server_id_buf tmp;
152 :
153 3 : ret = write_data(fd, &self, sizeof(self));
154 3 : if (ret == -1) {
155 0 : DEBUG(2, ("Failed to write to pipe: %s\n", strerror(errno)));
156 0 : return false;
157 : }
158 3 : if (ret < sizeof(self)) {
159 0 : DBG_WARNING("Could not write serverid\n");
160 0 : return false;
161 : }
162 :
163 3 : DEBUG(4, ("scavenger_say_hello: self[%s]\n",
164 : server_id_str_buf(self, &tmp)));
165 3 : return true;
166 : }
167 :
168 0 : static bool scavenger_wait_hello(int fd, struct server_id *child)
169 : {
170 0 : struct server_id_buf tmp;
171 0 : 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 0 : int fds[2];
194 0 : int ret;
195 0 : bool ok;
196 :
197 0 : SMB_ASSERT(server_id_equal(&state->parent_id, &self));
198 :
199 0 : if (smbd_scavenger_running(state)) {
200 0 : 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 0 : 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\n", 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 3 : 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\n", strerror(err)));
238 0 : goto fail;
239 : }
240 :
241 3 : if (ret == 0) {
242 : /* child */
243 :
244 0 : NTSTATUS status;
245 :
246 3 : close(fds[0]);
247 :
248 3 : status = smbd_reinit_after_fork(state->msg, state->ev,
249 : true);
250 3 : 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 3 : process_set_title("smbd-scavenger", "scavenger");
258 3 : reopen_logs();
259 :
260 3 : state->am_scavenger = true;
261 3 : *state->scavenger_id = messaging_server_id(state->msg);
262 :
263 3 : scavenger_setup_sig_term_handler(state->ev);
264 :
265 3 : ok = scavenger_say_hello(fds[1], *state->scavenger_id);
266 3 : if (!ok) {
267 0 : DEBUG(2, ("scavenger_say_hello failed\n"));
268 0 : exit_server("scavenger_say_hello failed");
269 : return false;
270 : }
271 :
272 3 : fde = tevent_add_fd(state->ev, state->scavenger_id,
273 : fds[1], TEVENT_FD_READ,
274 : smbd_scavenger_parent_dead, state);
275 3 : if (fde == NULL) {
276 0 : DEBUG(2, ("tevent_add_fd(smbd_scavenger_parent_dead) "
277 : "failed\n"));
278 0 : exit_server("tevent_add_fd(smbd_scavenger_parent_dead) "
279 : "failed");
280 : return false;
281 : }
282 3 : tevent_fd_set_auto_close(fde);
283 :
284 3 : ret = smbd_scavenger_main(state);
285 :
286 0 : DEBUG(10, ("scavenger ended: %d\n", ret));
287 0 : exit_server_cleanly("scavenger ended");
288 : return false;
289 : }
290 :
291 : /* parent */
292 0 : close(fds[1]);
293 :
294 0 : ok = scavenger_wait_hello(fds[0], state->scavenger_id);
295 0 : if (!ok) {
296 0 : close(fds[0]);
297 0 : goto fail;
298 : }
299 :
300 0 : fde = tevent_add_fd(state->ev, state->scavenger_id,
301 : fds[0], TEVENT_FD_READ,
302 : smbd_scavenger_done, state);
303 0 : if (fde == NULL) {
304 0 : close(fds[0]);
305 0 : goto fail;
306 : }
307 0 : tevent_fd_set_auto_close(fde);
308 :
309 0 : return true;
310 0 : fail:
311 0 : TALLOC_FREE(state->scavenger_id);
312 0 : return false;
313 : }
314 :
315 : static void scavenger_add_timer(struct smbd_scavenger_state *state,
316 : struct scavenger_message *msg);
317 :
318 50 : static void smbd_scavenger_msg(struct messaging_context *msg_ctx,
319 : void *private_data,
320 : uint32_t msg_type,
321 : struct server_id src,
322 : DATA_BLOB *data)
323 : {
324 0 : struct smbd_scavenger_state *state =
325 50 : talloc_get_type_abort(private_data,
326 : struct smbd_scavenger_state);
327 50 : TALLOC_CTX *frame = talloc_stackframe();
328 50 : struct server_id self = messaging_server_id(msg_ctx);
329 50 : struct scavenger_message *msg = NULL;
330 0 : struct server_id_buf tmp1, tmp2;
331 :
332 50 : DEBUG(10, ("smbd_scavenger_msg: %s got message from %s\n",
333 : server_id_str_buf(self, &tmp1),
334 : server_id_str_buf(src, &tmp2)));
335 :
336 50 : if (server_id_equal(&state->parent_id, &self)) {
337 0 : NTSTATUS status;
338 :
339 0 : if (!smbd_scavenger_running(state) &&
340 0 : !smbd_scavenger_start(state))
341 : {
342 0 : DEBUG(2, ("Failed to start scavenger\n"));
343 0 : goto done;
344 : }
345 0 : DEBUG(10, ("forwarding message to scavenger\n"));
346 :
347 0 : status = messaging_send(msg_ctx,
348 0 : *state->scavenger_id, msg_type, data);
349 0 : if (!NT_STATUS_IS_OK(status)) {
350 0 : DEBUG(2, ("forwarding message to scavenger failed: "
351 : "%s\n", nt_errstr(status)));
352 0 : goto done;
353 : }
354 0 : goto done;
355 : }
356 :
357 50 : if (!state->am_scavenger) {
358 0 : DEBUG(10, ("im not the scavenger: ignore message\n"));
359 0 : goto done;
360 : }
361 :
362 50 : if (!server_id_equal(&state->parent_id, &src)) {
363 0 : DEBUG(10, ("scavenger: ignore spurious message\n"));
364 0 : goto done;
365 : }
366 :
367 50 : DEBUG(10, ("scavenger: got a message\n"));
368 50 : msg = (struct scavenger_message*)data->data;
369 50 : scavenger_add_timer(state, msg);
370 50 : done:
371 50 : talloc_free(frame);
372 50 : }
373 :
374 0 : bool smbd_scavenger_init(TALLOC_CTX *mem_ctx,
375 : struct messaging_context *msg,
376 : struct tevent_context *ev)
377 : {
378 0 : struct smbd_scavenger_state *state;
379 0 : NTSTATUS status;
380 :
381 0 : if (smbd_scavenger_state) {
382 0 : DEBUG(10, ("smbd_scavenger_init called again\n"));
383 0 : return true;
384 : }
385 :
386 0 : state = talloc_zero(mem_ctx, struct smbd_scavenger_state);
387 0 : if (state == NULL) {
388 0 : DEBUG(2, ("Out of memory\n"));
389 0 : return false;
390 : }
391 :
392 0 : state->msg = msg;
393 0 : state->ev = ev;
394 0 : state->parent_id = messaging_server_id(msg);
395 :
396 0 : status = messaging_register(msg, state, MSG_SMB_SCAVENGER,
397 : smbd_scavenger_msg);
398 0 : if (!NT_STATUS_IS_OK(status)) {
399 0 : DEBUG(2, ("failed to register message handler: %s\n",
400 : nt_errstr(status)));
401 0 : goto fail;
402 : }
403 :
404 0 : smbd_scavenger_state = state;
405 0 : return true;
406 0 : fail:
407 0 : talloc_free(state);
408 0 : return false;
409 : }
410 :
411 160 : void scavenger_schedule_disconnected(struct files_struct *fsp)
412 : {
413 0 : NTSTATUS status;
414 160 : struct server_id self = messaging_server_id(fsp->conn->sconn->msg_ctx);
415 0 : struct timeval disconnect_time, until;
416 0 : uint64_t timeout_usec;
417 0 : struct scavenger_message msg;
418 0 : DATA_BLOB msg_blob;
419 0 : struct server_id_buf tmp;
420 0 : struct file_id_buf idbuf;
421 :
422 160 : if (fsp->op == NULL) {
423 0 : return;
424 : }
425 160 : nttime_to_timeval(&disconnect_time, fsp->op->global->disconnect_time);
426 160 : timeout_usec = UINT64_C(1000) * fsp->op->global->durable_timeout_msec;
427 160 : until = timeval_add(&disconnect_time,
428 160 : timeout_usec / 1000000,
429 160 : timeout_usec % 1000000);
430 :
431 160 : ZERO_STRUCT(msg);
432 160 : msg.file_id = fsp->file_id;
433 160 : msg.open_persistent_id = fsp->op->global->open_persistent_id;
434 160 : msg.until = timeval_to_nttime(&until);
435 :
436 160 : DEBUG(10, ("smbd: %s mark file %s as disconnected at %s with timeout "
437 : "at %s in %fs\n",
438 : server_id_str_buf(self, &tmp),
439 : file_id_str_buf(fsp->file_id, &idbuf),
440 : timeval_string(talloc_tos(), &disconnect_time, true),
441 : timeval_string(talloc_tos(), &until, true),
442 : fsp->op->global->durable_timeout_msec/1000.0));
443 :
444 160 : SMB_ASSERT(server_id_is_disconnected(&fsp->op->global->server_id));
445 160 : SMB_ASSERT(!server_id_equal(&self, &smbd_scavenger_state->parent_id));
446 160 : SMB_ASSERT(!smbd_scavenger_state->am_scavenger);
447 :
448 160 : msg_blob = data_blob_const(&msg, sizeof(msg));
449 160 : DEBUG(10, ("send message to scavenger\n"));
450 :
451 160 : status = messaging_send(smbd_scavenger_state->msg,
452 160 : smbd_scavenger_state->parent_id,
453 : MSG_SMB_SCAVENGER,
454 : &msg_blob);
455 160 : if (!NT_STATUS_IS_OK(status)) {
456 0 : struct server_id_buf tmp1, tmp2;
457 0 : DEBUG(2, ("Failed to send message to parent smbd %s "
458 : "from %s: %s\n",
459 : server_id_str_buf(smbd_scavenger_state->parent_id,
460 : &tmp1),
461 : server_id_str_buf(self, &tmp2),
462 : nt_errstr(status)));
463 : }
464 : }
465 :
466 : struct scavenger_timer_context {
467 : struct smbd_scavenger_state *state;
468 : struct scavenger_message msg;
469 : };
470 :
471 : struct cleanup_disconnected_state {
472 : struct file_id fid;
473 : struct share_mode_lock *lck;
474 : uint64_t open_persistent_id;
475 : size_t num_disconnected;
476 : bool found_connected;
477 : };
478 :
479 1 : static bool cleanup_disconnected_lease(struct share_mode_entry *e,
480 : void *private_data)
481 : {
482 1 : struct cleanup_disconnected_state *state = private_data;
483 0 : NTSTATUS status;
484 :
485 1 : status = leases_db_del(&e->client_guid, &e->lease_key, &state->fid);
486 :
487 1 : if (!NT_STATUS_IS_OK(status)) {
488 0 : DBG_DEBUG("leases_db_del failed: %s\n",
489 : nt_errstr(status));
490 : }
491 :
492 1 : return false;
493 : }
494 :
495 7 : static bool share_mode_find_connected_fn(
496 : struct share_mode_entry *e,
497 : bool *modified,
498 : void *private_data)
499 : {
500 7 : struct cleanup_disconnected_state *state = private_data;
501 0 : bool disconnected;
502 :
503 7 : disconnected = server_id_is_disconnected(&e->pid);
504 7 : if (!disconnected) {
505 0 : char *name = share_mode_filename(talloc_tos(), state->lck);
506 0 : struct file_id_buf tmp1;
507 0 : struct server_id_buf tmp2;
508 0 : DBG_INFO("file (file-id='%s', servicepath='%s', name='%s') "
509 : "is used by server %s ==> do not cleanup\n",
510 : file_id_str_buf(state->fid, &tmp1),
511 : share_mode_servicepath(state->lck),
512 : name,
513 : server_id_str_buf(e->pid, &tmp2));
514 0 : TALLOC_FREE(name);
515 0 : state->found_connected = true;
516 0 : return true;
517 : }
518 :
519 7 : if (state->open_persistent_id != e->share_file_id) {
520 4 : char *name = share_mode_filename(talloc_tos(), state->lck);
521 0 : struct file_id_buf tmp;
522 4 : DBG_INFO("entry for file "
523 : "(file-id='%s', servicepath='%s', name='%s') "
524 : "has share_file_id %"PRIu64" but expected "
525 : "%"PRIu64"==> do not cleanup\n",
526 : file_id_str_buf(state->fid, &tmp),
527 : share_mode_servicepath(state->lck),
528 : name,
529 : e->share_file_id,
530 : state->open_persistent_id);
531 4 : TALLOC_FREE(name);
532 4 : state->found_connected = true;
533 4 : return true;
534 : }
535 :
536 3 : state->num_disconnected += 1;
537 :
538 3 : return false;
539 : }
540 :
541 3 : static bool cleanup_disconnected_share_mode_entry_fn(
542 : struct share_mode_entry *e,
543 : bool *modified,
544 : void *private_data)
545 : {
546 3 : struct cleanup_disconnected_state *state = private_data;
547 :
548 0 : bool disconnected;
549 :
550 3 : disconnected = server_id_is_disconnected(&e->pid);
551 3 : if (!disconnected) {
552 0 : char *name = share_mode_filename(talloc_tos(), state->lck);
553 0 : struct file_id_buf tmp1;
554 0 : struct server_id_buf tmp2;
555 0 : DBG_ERR("file (file-id='%s', servicepath='%s', name='%s') "
556 : "is used by server %s ==> internal error\n",
557 : file_id_str_buf(state->fid, &tmp1),
558 : share_mode_servicepath(state->lck),
559 : name,
560 : server_id_str_buf(e->pid, &tmp2));
561 0 : TALLOC_FREE(name);
562 0 : smb_panic(__location__);
563 : }
564 :
565 : /*
566 : * Setting e->stale = true is
567 : * the indication to delete the entry.
568 : */
569 3 : e->stale = true;
570 3 : return false;
571 : }
572 :
573 50 : static bool share_mode_cleanup_disconnected(
574 : struct file_id fid, uint64_t open_persistent_id)
575 : {
576 50 : struct cleanup_disconnected_state state = {
577 : .fid = fid,
578 : .open_persistent_id = open_persistent_id
579 : };
580 50 : bool ret = false;
581 50 : TALLOC_CTX *frame = talloc_stackframe();
582 50 : char *name = NULL;
583 0 : struct file_id_buf idbuf;
584 0 : bool ok;
585 :
586 50 : state.lck = get_existing_share_mode_lock(frame, fid);
587 50 : if (state.lck == NULL) {
588 43 : DBG_INFO("Could not fetch share mode entry for %s\n",
589 : file_id_str_buf(fid, &idbuf));
590 43 : goto done;
591 : }
592 7 : name = share_mode_filename(frame, state.lck);
593 :
594 7 : ok = share_mode_forall_entries(
595 : state.lck, share_mode_find_connected_fn, &state);
596 7 : if (!ok) {
597 0 : DBG_DEBUG("share_mode_forall_entries failed\n");
598 0 : goto done;
599 : }
600 7 : if (state.found_connected) {
601 4 : DBG_DEBUG("Found connected entry\n");
602 4 : goto done;
603 : }
604 :
605 3 : ok = share_mode_forall_leases(
606 : state.lck, cleanup_disconnected_lease, &state);
607 3 : if (!ok) {
608 0 : DBG_DEBUG("failed to clean up leases associated "
609 : "with file (file-id='%s', servicepath='%s', "
610 : "name='%s') and open_persistent_id %"PRIu64" "
611 : "==> do not cleanup\n",
612 : file_id_str_buf(fid, &idbuf),
613 : share_mode_servicepath(state.lck),
614 : name,
615 : open_persistent_id);
616 0 : goto done;
617 : }
618 :
619 3 : ok = brl_cleanup_disconnected(fid, open_persistent_id);
620 3 : if (!ok) {
621 0 : DBG_DEBUG("failed to clean up byte range locks associated "
622 : "with file (file-id='%s', servicepath='%s', "
623 : "name='%s') and open_persistent_id %"PRIu64" "
624 : "==> do not cleanup\n",
625 : file_id_str_buf(fid, &idbuf),
626 : share_mode_servicepath(state.lck),
627 : name,
628 : open_persistent_id);
629 0 : goto done;
630 : }
631 :
632 3 : DBG_DEBUG("cleaning up %zu entries for file "
633 : "(file-id='%s', servicepath='%s', name='%s') "
634 : "from open_persistent_id %"PRIu64"\n",
635 : state.num_disconnected,
636 : file_id_str_buf(fid, &idbuf),
637 : share_mode_servicepath(state.lck),
638 : name,
639 : open_persistent_id);
640 :
641 3 : ok = share_mode_forall_entries(
642 : state.lck, cleanup_disconnected_share_mode_entry_fn, &state);
643 3 : if (!ok) {
644 0 : DBG_DEBUG("failed to clean up %zu entries associated "
645 : "with file (file-id='%s', servicepath='%s', "
646 : "name='%s') and open_persistent_id %"PRIu64" "
647 : "==> do not cleanup\n",
648 : state.num_disconnected,
649 : file_id_str_buf(fid, &idbuf),
650 : share_mode_servicepath(state.lck),
651 : name,
652 : open_persistent_id);
653 0 : goto done;
654 : }
655 :
656 3 : ret = true;
657 50 : done:
658 50 : talloc_free(frame);
659 50 : return ret;
660 : }
661 :
662 50 : static void scavenger_timer(struct tevent_context *ev,
663 : struct tevent_timer *te,
664 : struct timeval t, void *data)
665 : {
666 0 : struct scavenger_timer_context *ctx =
667 50 : talloc_get_type_abort(data, struct scavenger_timer_context);
668 0 : struct file_id_buf idbuf;
669 0 : NTSTATUS status;
670 0 : bool ok;
671 :
672 50 : DBG_DEBUG("do cleanup for file %s at %s\n",
673 : file_id_str_buf(ctx->msg.file_id, &idbuf),
674 : timeval_string(talloc_tos(), &t, true));
675 :
676 50 : ok = share_mode_cleanup_disconnected(ctx->msg.file_id,
677 : ctx->msg.open_persistent_id);
678 50 : if (!ok) {
679 47 : DBG_WARNING("Failed to cleanup share modes and byte range "
680 : "locks for file %s open %"PRIu64"\n",
681 : file_id_str_buf(ctx->msg.file_id, &idbuf),
682 : ctx->msg.open_persistent_id);
683 : }
684 :
685 50 : status = smbXsrv_open_cleanup(ctx->msg.open_persistent_id);
686 50 : if (!NT_STATUS_IS_OK(status)) {
687 0 : DBG_WARNING("Failed to cleanup open global for file %s open "
688 : "%"PRIu64": %s\n",
689 : file_id_str_buf(ctx->msg.file_id, &idbuf),
690 : ctx->msg.open_persistent_id,
691 : nt_errstr(status));
692 : }
693 50 : }
694 :
695 50 : static void scavenger_add_timer(struct smbd_scavenger_state *state,
696 : struct scavenger_message *msg)
697 : {
698 0 : struct tevent_timer *te;
699 0 : struct scavenger_timer_context *ctx;
700 0 : struct timeval until;
701 0 : struct file_id_buf idbuf;
702 :
703 50 : nttime_to_timeval(&until, msg->until);
704 :
705 50 : DBG_DEBUG("schedule file %s for cleanup at %s\n",
706 : file_id_str_buf(msg->file_id, &idbuf),
707 : timeval_string(talloc_tos(), &until, true));
708 :
709 50 : ctx = talloc_zero(state, struct scavenger_timer_context);
710 50 : if (ctx == NULL) {
711 0 : DEBUG(2, ("Failed to talloc_zero(scavenger_timer_context)\n"));
712 0 : return;
713 : }
714 :
715 50 : ctx->state = state;
716 50 : ctx->msg = *msg;
717 :
718 50 : te = tevent_add_timer(state->ev,
719 : state,
720 : until,
721 : scavenger_timer,
722 : ctx);
723 50 : if (te == NULL) {
724 0 : DEBUG(2, ("Failed to add scavenger_timer event\n"));
725 0 : talloc_free(ctx);
726 0 : return;
727 : }
728 :
729 : /* delete context after handler was running */
730 50 : talloc_steal(te, ctx);
731 : }
|