LCOV - code coverage report
Current view: top level - source3/smbd - scavenger.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 11 284 3.9 %
Date: 2024-06-13 04:01:37 Functions: 1 19 5.3 %

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

Generated by: LCOV version 1.13