LCOV - code coverage report
Current view: top level - source3/smbd - scavenger.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 181 282 64.2 %
Date: 2021-08-25 13:27:56 Functions: 16 19 84.2 %

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

Generated by: LCOV version 1.13