2 Unix SMB/CIFS implementation.
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/>.
24 #include "smbd/globals.h"
25 #include "smbd/scavenger.h"
26 #include "locking/proto.h"
27 #include "lib/util/server_id.h"
28 #include "lib/util/util_process.h"
29 #include "lib/util/sys_rw_data.h"
32 #define DBGC_CLASS DBGC_SCAVENGER
34 struct smbd_scavenger_state
{
35 struct tevent_context
*ev
;
36 struct messaging_context
*msg
;
37 struct server_id parent_id
;
38 struct server_id
*scavenger_id
;
42 static struct smbd_scavenger_state
*smbd_scavenger_state
= NULL
;
44 struct scavenger_message
{
45 struct file_id file_id
;
46 uint64_t open_persistent_id
;
50 static int smbd_scavenger_main(struct smbd_scavenger_state
*state
)
52 struct server_id_buf tmp1
, tmp2
;
54 DEBUG(10, ("scavenger: %s started, parent: %s\n",
55 server_id_str_buf(*state
->scavenger_id
, &tmp1
),
56 server_id_str_buf(state
->parent_id
, &tmp2
)));
59 TALLOC_CTX
*frame
= talloc_stackframe();
62 ret
= tevent_loop_once(state
->ev
);
64 DEBUG(2, ("tevent_loop_once failed: %s\n",
70 DEBUG(10, ("scavenger: %s event loop iteration\n",
71 server_id_str_buf(*state
->scavenger_id
, &tmp1
)));
78 static void smbd_scavenger_done(struct tevent_context
*event_ctx
, struct tevent_fd
*fde
,
79 uint16_t flags
, void *private_data
)
81 struct smbd_scavenger_state
*state
= talloc_get_type_abort(
82 private_data
, struct smbd_scavenger_state
);
83 struct server_id_buf tmp
;
85 DEBUG(2, ("scavenger: %s died\n",
86 server_id_str_buf(*state
->scavenger_id
, &tmp
)));
88 TALLOC_FREE(state
->scavenger_id
);
91 static void smbd_scavenger_parent_dead(struct tevent_context
*event_ctx
,
92 struct tevent_fd
*fde
,
93 uint16_t flags
, void *private_data
)
95 struct smbd_scavenger_state
*state
= talloc_get_type_abort(
96 private_data
, struct smbd_scavenger_state
);
97 struct server_id_buf tmp1
, tmp2
;
99 DEBUG(2, ("scavenger: %s parent %s died\n",
100 server_id_str_buf(*state
->scavenger_id
, &tmp1
),
101 server_id_str_buf(state
->parent_id
, &tmp2
)));
103 exit_server("smbd_scavenger_parent_dead");
106 static void scavenger_sig_term_handler(struct tevent_context
*ev
,
107 struct tevent_signal
*se
,
113 exit_server_cleanly("termination signal");
116 static void scavenger_setup_sig_term_handler(struct tevent_context
*ev_ctx
)
118 struct tevent_signal
*se
;
120 se
= tevent_add_signal(ev_ctx
,
123 scavenger_sig_term_handler
,
126 exit_server("failed to setup SIGTERM handler");
130 static bool smbd_scavenger_running(struct smbd_scavenger_state
*state
)
132 if (state
->scavenger_id
== NULL
) {
136 return serverid_exists(state
->scavenger_id
);
139 static int smbd_scavenger_server_id_destructor(struct server_id
*id
)
144 static bool scavenger_say_hello(int fd
, struct server_id self
)
147 struct server_id_buf tmp
;
149 ret
= write_data(fd
, &self
, sizeof(self
));
151 DEBUG(2, ("Failed to write to pipe: %s\n", strerror(errno
)));
154 if (ret
< sizeof(self
)) {
155 DBG_WARNING("Could not write serverid\n");
159 DEBUG(4, ("scavenger_say_hello: self[%s]\n",
160 server_id_str_buf(self
, &tmp
)));
164 static bool scavenger_wait_hello(int fd
, struct server_id
*child
)
166 struct server_id_buf tmp
;
169 ret
= read_data(fd
, child
, sizeof(struct server_id
));
171 DEBUG(2, ("Failed to read from pipe: %s\n",
175 if (ret
< sizeof(struct server_id
)) {
176 DBG_WARNING("Could not read serverid\n");
180 DEBUG(4, ("scavenger_say_hello: child[%s]\n",
181 server_id_str_buf(*child
, &tmp
)));
185 static bool smbd_scavenger_start(struct smbd_scavenger_state
*state
)
187 struct server_id self
= messaging_server_id(state
->msg
);
188 struct tevent_fd
*fde
= NULL
;
193 SMB_ASSERT(server_id_equal(&state
->parent_id
, &self
));
195 if (smbd_scavenger_running(state
)) {
196 struct server_id_buf tmp
;
197 DEBUG(10, ("scavenger %s already running\n",
198 server_id_str_buf(*state
->scavenger_id
,
203 if (state
->scavenger_id
!= NULL
) {
204 struct server_id_buf tmp
;
205 DEBUG(10, ("scavenger zombie %s, cleaning up\n",
206 server_id_str_buf(*state
->scavenger_id
,
208 TALLOC_FREE(state
->scavenger_id
);
211 state
->scavenger_id
= talloc_zero(state
, struct server_id
);
212 if (state
->scavenger_id
== NULL
) {
213 DEBUG(2, ("Out of memory\n"));
216 talloc_set_destructor(state
->scavenger_id
,
217 smbd_scavenger_server_id_destructor
);
219 ret
= socketpair(AF_UNIX
, SOCK_STREAM
, 0, fds
);
221 DEBUG(2, ("socketpair failed: %s", strerror(errno
)));
225 smb_set_close_on_exec(fds
[0]);
226 smb_set_close_on_exec(fds
[1]);
233 DEBUG(0, ("fork failed: %s", strerror(err
)));
244 status
= smbd_reinit_after_fork(state
->msg
, state
->ev
,
245 true, "smbd-scavenger");
246 if (!NT_STATUS_IS_OK(status
)) {
247 DEBUG(2, ("reinit_after_fork failed: %s\n",
249 exit_server("reinit_after_fork failed");
255 state
->am_scavenger
= true;
256 *state
->scavenger_id
= messaging_server_id(state
->msg
);
258 scavenger_setup_sig_term_handler(state
->ev
);
260 ok
= scavenger_say_hello(fds
[1], *state
->scavenger_id
);
262 DEBUG(2, ("scavenger_say_hello failed\n"));
263 exit_server("scavenger_say_hello failed");
267 fde
= tevent_add_fd(state
->ev
, state
->scavenger_id
,
268 fds
[1], TEVENT_FD_READ
,
269 smbd_scavenger_parent_dead
, state
);
271 DEBUG(2, ("tevent_add_fd(smbd_scavenger_parent_dead) "
273 exit_server("tevent_add_fd(smbd_scavenger_parent_dead) "
277 tevent_fd_set_auto_close(fde
);
279 ret
= smbd_scavenger_main(state
);
281 DEBUG(10, ("scavenger ended: %d\n", ret
));
282 exit_server_cleanly("scavenger ended");
289 ok
= scavenger_wait_hello(fds
[0], state
->scavenger_id
);
295 fde
= tevent_add_fd(state
->ev
, state
->scavenger_id
,
296 fds
[0], TEVENT_FD_READ
,
297 smbd_scavenger_done
, state
);
302 tevent_fd_set_auto_close(fde
);
306 TALLOC_FREE(state
->scavenger_id
);
310 static void scavenger_add_timer(struct smbd_scavenger_state
*state
,
311 struct scavenger_message
*msg
);
313 static void smbd_scavenger_msg(struct messaging_context
*msg_ctx
,
316 struct server_id src
,
319 struct smbd_scavenger_state
*state
=
320 talloc_get_type_abort(private_data
,
321 struct smbd_scavenger_state
);
322 TALLOC_CTX
*frame
= talloc_stackframe();
323 struct server_id self
= messaging_server_id(msg_ctx
);
324 struct scavenger_message
*msg
= NULL
;
325 struct server_id_buf tmp1
, tmp2
;
327 DEBUG(10, ("smbd_scavenger_msg: %s got message from %s\n",
328 server_id_str_buf(self
, &tmp1
),
329 server_id_str_buf(src
, &tmp2
)));
331 if (server_id_equal(&state
->parent_id
, &self
)) {
334 if (!smbd_scavenger_running(state
) &&
335 !smbd_scavenger_start(state
))
337 DEBUG(2, ("Failed to start scavenger\n"));
340 DEBUG(10, ("forwarding message to scavenger\n"));
342 status
= messaging_send(msg_ctx
,
343 *state
->scavenger_id
, msg_type
, data
);
344 if (!NT_STATUS_IS_OK(status
)) {
345 DEBUG(2, ("forwarding message to scavenger failed: "
346 "%s\n", nt_errstr(status
)));
352 if (!state
->am_scavenger
) {
353 DEBUG(10, ("im not the scavenger: ignore message\n"));
357 if (!server_id_equal(&state
->parent_id
, &src
)) {
358 DEBUG(10, ("scavenger: ignore spurious message\n"));
362 DEBUG(10, ("scavenger: got a message\n"));
363 msg
= (struct scavenger_message
*)data
->data
;
364 scavenger_add_timer(state
, msg
);
369 bool smbd_scavenger_init(TALLOC_CTX
*mem_ctx
,
370 struct messaging_context
*msg
,
371 struct tevent_context
*ev
)
373 struct smbd_scavenger_state
*state
;
376 if (smbd_scavenger_state
) {
377 DEBUG(10, ("smbd_scavenger_init called again\n"));
381 state
= talloc_zero(mem_ctx
, struct smbd_scavenger_state
);
383 DEBUG(2, ("Out of memory\n"));
389 state
->parent_id
= messaging_server_id(msg
);
391 status
= messaging_register(msg
, state
, MSG_SMB_SCAVENGER
,
393 if (!NT_STATUS_IS_OK(status
)) {
394 DEBUG(2, ("failed to register message handler: %s\n",
399 smbd_scavenger_state
= state
;
406 void scavenger_schedule_disconnected(struct files_struct
*fsp
)
409 struct server_id self
= messaging_server_id(fsp
->conn
->sconn
->msg_ctx
);
410 struct timeval disconnect_time
, until
;
411 uint64_t timeout_usec
;
412 struct scavenger_message msg
;
414 struct server_id_buf tmp
;
415 struct file_id_buf idbuf
;
417 if (fsp
->op
== NULL
) {
420 nttime_to_timeval(&disconnect_time
, fsp
->op
->global
->disconnect_time
);
421 timeout_usec
= 1000 * fsp
->op
->global
->durable_timeout_msec
;
422 until
= timeval_add(&disconnect_time
,
423 timeout_usec
/ 1000000,
424 timeout_usec
% 1000000);
427 msg
.file_id
= fsp
->file_id
;
428 msg
.open_persistent_id
= fsp
->op
->global
->open_persistent_id
;
429 msg
.until
= timeval_to_nttime(&until
);
431 DEBUG(10, ("smbd: %s mark file %s as disconnected at %s with timeout "
433 server_id_str_buf(self
, &tmp
),
434 file_id_str_buf(fsp
->file_id
, &idbuf
),
435 timeval_string(talloc_tos(), &disconnect_time
, true),
436 timeval_string(talloc_tos(), &until
, true),
437 fsp
->op
->global
->durable_timeout_msec
/1000.0));
439 SMB_ASSERT(server_id_is_disconnected(&fsp
->op
->global
->server_id
));
440 SMB_ASSERT(!server_id_equal(&self
, &smbd_scavenger_state
->parent_id
));
441 SMB_ASSERT(!smbd_scavenger_state
->am_scavenger
);
443 msg_blob
= data_blob_const(&msg
, sizeof(msg
));
444 DEBUG(10, ("send message to scavenger\n"));
446 status
= messaging_send(smbd_scavenger_state
->msg
,
447 smbd_scavenger_state
->parent_id
,
450 if (!NT_STATUS_IS_OK(status
)) {
451 struct server_id_buf tmp1
, tmp2
;
452 DEBUG(2, ("Failed to send message to parent smbd %s "
454 server_id_str_buf(smbd_scavenger_state
->parent_id
,
456 server_id_str_buf(self
, &tmp2
),
461 struct scavenger_timer_context
{
462 struct smbd_scavenger_state
*state
;
463 struct scavenger_message msg
;
466 static void scavenger_timer(struct tevent_context
*ev
,
467 struct tevent_timer
*te
,
468 struct timeval t
, void *data
)
470 struct scavenger_timer_context
*ctx
=
471 talloc_get_type_abort(data
, struct scavenger_timer_context
);
472 struct file_id_buf idbuf
;
476 DBG_DEBUG("do cleanup for file %s at %s\n",
477 file_id_str_buf(ctx
->msg
.file_id
, &idbuf
),
478 timeval_string(talloc_tos(), &t
, true));
480 ok
= share_mode_cleanup_disconnected(ctx
->msg
.file_id
,
481 ctx
->msg
.open_persistent_id
);
483 DBG_WARNING("Failed to cleanup share modes and byte range "
484 "locks for file %s open %"PRIu64
"\n",
485 file_id_str_buf(ctx
->msg
.file_id
, &idbuf
),
486 ctx
->msg
.open_persistent_id
);
489 status
= smbXsrv_open_cleanup(ctx
->msg
.open_persistent_id
);
490 if (!NT_STATUS_IS_OK(status
)) {
491 DBG_WARNING("Failed to cleanup open global for file %s open "
493 file_id_str_buf(ctx
->msg
.file_id
, &idbuf
),
494 ctx
->msg
.open_persistent_id
,
499 static void scavenger_add_timer(struct smbd_scavenger_state
*state
,
500 struct scavenger_message
*msg
)
502 struct tevent_timer
*te
;
503 struct scavenger_timer_context
*ctx
;
504 struct timeval until
;
505 struct file_id_buf idbuf
;
507 nttime_to_timeval(&until
, msg
->until
);
509 DBG_DEBUG("schedule file %s for cleanup at %s\n",
510 file_id_str_buf(msg
->file_id
, &idbuf
),
511 timeval_string(talloc_tos(), &until
, true));
513 ctx
= talloc_zero(state
, struct scavenger_timer_context
);
515 DEBUG(2, ("Failed to talloc_zero(scavenger_timer_context)\n"));
522 te
= tevent_add_timer(state
->ev
,
528 DEBUG(2, ("Failed to add scavenger_timer event\n"));
533 /* delete context after handler was running */
534 talloc_steal(te
, ctx
);