Coverage Report

Created: 2025-11-16 06:57

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