s3: libsmb: In cli_qpathinfo_send() (SMBtrans2:TRANSACT2_QPATHINFO) check for DFS...
[Samba.git] / source3 / smbd / scavenger.c
blobfe47c22e05ffde3d2a3115e698ec1b693641668b
1 /*
2 Unix SMB/CIFS implementation.
3 smbd scavenger daemon
5 Copyright (C) Gregor Beck 2013
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.
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.
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/>.
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"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_SCAVENGER
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;
46 static struct smbd_scavenger_state *smbd_scavenger_state = NULL;
48 struct scavenger_message {
49 struct file_id file_id;
50 uint64_t open_persistent_id;
51 NTTIME until;
54 static int smbd_scavenger_main(struct smbd_scavenger_state *state)
56 struct server_id_buf tmp1, tmp2;
58 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)));
62 while (true) {
63 TALLOC_CTX *frame = talloc_stackframe();
64 int ret;
66 ret = tevent_loop_once(state->ev);
67 if (ret != 0) {
68 DEBUG(2, ("tevent_loop_once failed: %s\n",
69 strerror(errno)));
70 TALLOC_FREE(frame);
71 return 1;
74 DEBUG(10, ("scavenger: %s event loop iteration\n",
75 server_id_str_buf(*state->scavenger_id, &tmp1)));
76 TALLOC_FREE(frame);
79 return 0;
82 static void smbd_scavenger_done(struct tevent_context *event_ctx, struct tevent_fd *fde,
83 uint16_t flags, void *private_data)
85 struct smbd_scavenger_state *state = talloc_get_type_abort(
86 private_data, struct smbd_scavenger_state);
87 struct server_id_buf tmp;
89 DEBUG(2, ("scavenger: %s died\n",
90 server_id_str_buf(*state->scavenger_id, &tmp)));
92 TALLOC_FREE(state->scavenger_id);
95 static void smbd_scavenger_parent_dead(struct tevent_context *event_ctx,
96 struct tevent_fd *fde,
97 uint16_t flags, void *private_data)
99 struct smbd_scavenger_state *state = talloc_get_type_abort(
100 private_data, struct smbd_scavenger_state);
101 struct server_id_buf tmp1, tmp2;
103 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)));
107 exit_server("smbd_scavenger_parent_dead");
110 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)
117 exit_server_cleanly("termination signal");
120 static void scavenger_setup_sig_term_handler(struct tevent_context *ev_ctx)
122 struct tevent_signal *se;
124 se = tevent_add_signal(ev_ctx,
125 ev_ctx,
126 SIGTERM, 0,
127 scavenger_sig_term_handler,
128 NULL);
129 if (se == NULL) {
130 exit_server("failed to setup SIGTERM handler");
134 static bool smbd_scavenger_running(struct smbd_scavenger_state *state)
136 if (state->scavenger_id == NULL) {
137 return false;
140 return serverid_exists(state->scavenger_id);
143 static int smbd_scavenger_server_id_destructor(struct server_id *id)
145 return 0;
148 static bool scavenger_say_hello(int fd, struct server_id self)
150 ssize_t ret;
151 struct server_id_buf tmp;
153 ret = write_data(fd, &self, sizeof(self));
154 if (ret == -1) {
155 DEBUG(2, ("Failed to write to pipe: %s\n", strerror(errno)));
156 return false;
158 if (ret < sizeof(self)) {
159 DBG_WARNING("Could not write serverid\n");
160 return false;
163 DEBUG(4, ("scavenger_say_hello: self[%s]\n",
164 server_id_str_buf(self, &tmp)));
165 return true;
168 static bool scavenger_wait_hello(int fd, struct server_id *child)
170 struct server_id_buf tmp;
171 ssize_t ret;
173 ret = read_data(fd, child, sizeof(struct server_id));
174 if (ret == -1) {
175 DEBUG(2, ("Failed to read from pipe: %s\n",
176 strerror(errno)));
177 return false;
179 if (ret < sizeof(struct server_id)) {
180 DBG_WARNING("Could not read serverid\n");
181 return false;
184 DEBUG(4, ("scavenger_say_hello: child[%s]\n",
185 server_id_str_buf(*child, &tmp)));
186 return true;
189 static bool smbd_scavenger_start(struct smbd_scavenger_state *state)
191 struct server_id self = messaging_server_id(state->msg);
192 struct tevent_fd *fde = NULL;
193 int fds[2];
194 int ret;
195 bool ok;
197 SMB_ASSERT(server_id_equal(&state->parent_id, &self));
199 if (smbd_scavenger_running(state)) {
200 struct server_id_buf tmp;
201 DEBUG(10, ("scavenger %s already running\n",
202 server_id_str_buf(*state->scavenger_id,
203 &tmp)));
204 return true;
207 if (state->scavenger_id != NULL) {
208 struct server_id_buf tmp;
209 DEBUG(10, ("scavenger zombie %s, cleaning up\n",
210 server_id_str_buf(*state->scavenger_id,
211 &tmp)));
212 TALLOC_FREE(state->scavenger_id);
215 state->scavenger_id = talloc_zero(state, struct server_id);
216 if (state->scavenger_id == NULL) {
217 DEBUG(2, ("Out of memory\n"));
218 goto fail;
220 talloc_set_destructor(state->scavenger_id,
221 smbd_scavenger_server_id_destructor);
223 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
224 if (ret == -1) {
225 DEBUG(2, ("socketpair failed: %s", strerror(errno)));
226 goto fail;
229 smb_set_close_on_exec(fds[0]);
230 smb_set_close_on_exec(fds[1]);
232 ret = fork();
233 if (ret == -1) {
234 int err = errno;
235 close(fds[0]);
236 close(fds[1]);
237 DEBUG(0, ("fork failed: %s", strerror(err)));
238 goto fail;
241 if (ret == 0) {
242 /* child */
244 NTSTATUS status;
246 close(fds[0]);
248 status = smbd_reinit_after_fork(state->msg, state->ev,
249 true, "smbd-scavenger");
250 if (!NT_STATUS_IS_OK(status)) {
251 DEBUG(2, ("reinit_after_fork failed: %s\n",
252 nt_errstr(status)));
253 exit_server("reinit_after_fork failed");
254 return false;
257 reopen_logs();
259 state->am_scavenger = true;
260 *state->scavenger_id = messaging_server_id(state->msg);
262 scavenger_setup_sig_term_handler(state->ev);
264 ok = scavenger_say_hello(fds[1], *state->scavenger_id);
265 if (!ok) {
266 DEBUG(2, ("scavenger_say_hello failed\n"));
267 exit_server("scavenger_say_hello failed");
268 return false;
271 fde = tevent_add_fd(state->ev, state->scavenger_id,
272 fds[1], TEVENT_FD_READ,
273 smbd_scavenger_parent_dead, state);
274 if (fde == NULL) {
275 DEBUG(2, ("tevent_add_fd(smbd_scavenger_parent_dead) "
276 "failed\n"));
277 exit_server("tevent_add_fd(smbd_scavenger_parent_dead) "
278 "failed");
279 return false;
281 tevent_fd_set_auto_close(fde);
283 ret = smbd_scavenger_main(state);
285 DEBUG(10, ("scavenger ended: %d\n", ret));
286 exit_server_cleanly("scavenger ended");
287 return false;
290 /* parent */
291 close(fds[1]);
293 ok = scavenger_wait_hello(fds[0], state->scavenger_id);
294 if (!ok) {
295 close(fds[0]);
296 goto fail;
299 fde = tevent_add_fd(state->ev, state->scavenger_id,
300 fds[0], TEVENT_FD_READ,
301 smbd_scavenger_done, state);
302 if (fde == NULL) {
303 close(fds[0]);
304 goto fail;
306 tevent_fd_set_auto_close(fde);
308 return true;
309 fail:
310 TALLOC_FREE(state->scavenger_id);
311 return false;
314 static void scavenger_add_timer(struct smbd_scavenger_state *state,
315 struct scavenger_message *msg);
317 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)
323 struct smbd_scavenger_state *state =
324 talloc_get_type_abort(private_data,
325 struct smbd_scavenger_state);
326 TALLOC_CTX *frame = talloc_stackframe();
327 struct server_id self = messaging_server_id(msg_ctx);
328 struct scavenger_message *msg = NULL;
329 struct server_id_buf tmp1, tmp2;
331 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)));
335 if (server_id_equal(&state->parent_id, &self)) {
336 NTSTATUS status;
338 if (!smbd_scavenger_running(state) &&
339 !smbd_scavenger_start(state))
341 DEBUG(2, ("Failed to start scavenger\n"));
342 goto done;
344 DEBUG(10, ("forwarding message to scavenger\n"));
346 status = messaging_send(msg_ctx,
347 *state->scavenger_id, msg_type, data);
348 if (!NT_STATUS_IS_OK(status)) {
349 DEBUG(2, ("forwarding message to scavenger failed: "
350 "%s\n", nt_errstr(status)));
351 goto done;
353 goto done;
356 if (!state->am_scavenger) {
357 DEBUG(10, ("im not the scavenger: ignore message\n"));
358 goto done;
361 if (!server_id_equal(&state->parent_id, &src)) {
362 DEBUG(10, ("scavenger: ignore spurious message\n"));
363 goto done;
366 DEBUG(10, ("scavenger: got a message\n"));
367 msg = (struct scavenger_message*)data->data;
368 scavenger_add_timer(state, msg);
369 done:
370 talloc_free(frame);
373 bool smbd_scavenger_init(TALLOC_CTX *mem_ctx,
374 struct messaging_context *msg,
375 struct tevent_context *ev)
377 struct smbd_scavenger_state *state;
378 NTSTATUS status;
380 if (smbd_scavenger_state) {
381 DEBUG(10, ("smbd_scavenger_init called again\n"));
382 return true;
385 state = talloc_zero(mem_ctx, struct smbd_scavenger_state);
386 if (state == NULL) {
387 DEBUG(2, ("Out of memory\n"));
388 return false;
391 state->msg = msg;
392 state->ev = ev;
393 state->parent_id = messaging_server_id(msg);
395 status = messaging_register(msg, state, MSG_SMB_SCAVENGER,
396 smbd_scavenger_msg);
397 if (!NT_STATUS_IS_OK(status)) {
398 DEBUG(2, ("failed to register message handler: %s\n",
399 nt_errstr(status)));
400 goto fail;
403 smbd_scavenger_state = state;
404 return true;
405 fail:
406 talloc_free(state);
407 return false;
410 void scavenger_schedule_disconnected(struct files_struct *fsp)
412 NTSTATUS status;
413 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;
421 if (fsp->op == NULL) {
422 return;
424 nttime_to_timeval(&disconnect_time, fsp->op->global->disconnect_time);
425 timeout_usec = 1000 * fsp->op->global->durable_timeout_msec;
426 until = timeval_add(&disconnect_time,
427 timeout_usec / 1000000,
428 timeout_usec % 1000000);
430 ZERO_STRUCT(msg);
431 msg.file_id = fsp->file_id;
432 msg.open_persistent_id = fsp->op->global->open_persistent_id;
433 msg.until = timeval_to_nttime(&until);
435 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));
443 SMB_ASSERT(server_id_is_disconnected(&fsp->op->global->server_id));
444 SMB_ASSERT(!server_id_equal(&self, &smbd_scavenger_state->parent_id));
445 SMB_ASSERT(!smbd_scavenger_state->am_scavenger);
447 msg_blob = data_blob_const(&msg, sizeof(msg));
448 DEBUG(10, ("send message to scavenger\n"));
450 status = messaging_send(smbd_scavenger_state->msg,
451 smbd_scavenger_state->parent_id,
452 MSG_SMB_SCAVENGER,
453 &msg_blob);
454 if (!NT_STATUS_IS_OK(status)) {
455 struct server_id_buf tmp1, tmp2;
456 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)));
465 struct scavenger_timer_context {
466 struct smbd_scavenger_state *state;
467 struct scavenger_message msg;
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;
478 static bool cleanup_disconnected_lease(struct share_mode_entry *e,
479 void *private_data)
481 struct cleanup_disconnected_state *state = private_data;
482 NTSTATUS status;
484 status = leases_db_del(&e->client_guid, &e->lease_key, &state->fid);
486 if (!NT_STATUS_IS_OK(status)) {
487 DBG_DEBUG("leases_db_del failed: %s\n",
488 nt_errstr(status));
491 return false;
494 static bool share_mode_find_connected_fn(
495 struct share_mode_entry *e,
496 bool *modified,
497 void *private_data)
499 struct cleanup_disconnected_state *state = private_data;
500 bool disconnected;
502 disconnected = server_id_is_disconnected(&e->pid);
503 if (!disconnected) {
504 char *name = share_mode_filename(talloc_tos(), state->lck);
505 struct file_id_buf tmp1;
506 struct server_id_buf tmp2;
507 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 TALLOC_FREE(name);
514 state->found_connected = true;
515 return true;
518 if (state->open_persistent_id != e->share_file_id) {
519 char *name = share_mode_filename(talloc_tos(), state->lck);
520 struct file_id_buf tmp;
521 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 TALLOC_FREE(name);
531 state->found_connected = true;
532 return true;
535 state->num_disconnected += 1;
537 return false;
540 static bool cleanup_disconnected_share_mode_entry_fn(
541 struct share_mode_entry *e,
542 bool *modified,
543 void *private_data)
545 struct cleanup_disconnected_state *state = private_data;
547 bool disconnected;
549 disconnected = server_id_is_disconnected(&e->pid);
550 if (!disconnected) {
551 char *name = share_mode_filename(talloc_tos(), state->lck);
552 struct file_id_buf tmp1;
553 struct server_id_buf tmp2;
554 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 TALLOC_FREE(name);
561 smb_panic(__location__);
565 * Setting e->stale = true is
566 * the indication to delete the entry.
568 e->stale = true;
569 return false;
572 static bool share_mode_cleanup_disconnected(
573 struct file_id fid, uint64_t open_persistent_id)
575 struct cleanup_disconnected_state state = {
576 .fid = fid,
577 .open_persistent_id = open_persistent_id
579 bool ret = false;
580 TALLOC_CTX *frame = talloc_stackframe();
581 char *name = NULL;
582 struct file_id_buf idbuf;
583 bool ok;
585 state.lck = get_existing_share_mode_lock(frame, fid);
586 if (state.lck == NULL) {
587 DBG_INFO("Could not fetch share mode entry for %s\n",
588 file_id_str_buf(fid, &idbuf));
589 goto done;
591 name = share_mode_filename(frame, state.lck);
593 ok = share_mode_forall_entries(
594 state.lck, share_mode_find_connected_fn, &state);
595 if (!ok) {
596 DBG_DEBUG("share_mode_forall_entries failed\n");
597 goto done;
599 if (state.found_connected) {
600 DBG_DEBUG("Found connected entry\n");
601 goto done;
604 ok = share_mode_forall_leases(
605 state.lck, cleanup_disconnected_lease, &state);
606 if (!ok) {
607 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 goto done;
618 ok = brl_cleanup_disconnected(fid, open_persistent_id);
619 if (!ok) {
620 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 goto done;
631 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);
640 ok = share_mode_forall_entries(
641 state.lck, cleanup_disconnected_share_mode_entry_fn, &state);
642 if (!ok) {
643 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 goto done;
655 ret = true;
656 done:
657 talloc_free(frame);
658 return ret;
661 static void scavenger_timer(struct tevent_context *ev,
662 struct tevent_timer *te,
663 struct timeval t, void *data)
665 struct scavenger_timer_context *ctx =
666 talloc_get_type_abort(data, struct scavenger_timer_context);
667 struct file_id_buf idbuf;
668 NTSTATUS status;
669 bool ok;
671 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));
675 ok = share_mode_cleanup_disconnected(ctx->msg.file_id,
676 ctx->msg.open_persistent_id);
677 if (!ok) {
678 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);
684 status = smbXsrv_open_cleanup(ctx->msg.open_persistent_id);
685 if (!NT_STATUS_IS_OK(status)) {
686 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));
694 static void scavenger_add_timer(struct smbd_scavenger_state *state,
695 struct scavenger_message *msg)
697 struct tevent_timer *te;
698 struct scavenger_timer_context *ctx;
699 struct timeval until;
700 struct file_id_buf idbuf;
702 nttime_to_timeval(&until, msg->until);
704 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));
708 ctx = talloc_zero(state, struct scavenger_timer_context);
709 if (ctx == NULL) {
710 DEBUG(2, ("Failed to talloc_zero(scavenger_timer_context)\n"));
711 return;
714 ctx->state = state;
715 ctx->msg = *msg;
717 te = tevent_add_timer(state->ev,
718 state,
719 until,
720 scavenger_timer,
721 ctx);
722 if (te == NULL) {
723 DEBUG(2, ("Failed to add scavenger_timer event\n"));
724 talloc_free(ctx);
725 return;
728 /* delete context after handler was running */
729 talloc_steal(te, ctx);