LCOV - code coverage report
Current view: top level - source3/smbd - scavenger.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 144 329 43.8 %
Date: 2024-04-21 15:09:00 Functions: 13 19 68.4 %

          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             : }

Generated by: LCOV version 1.14