s3: VFS: delay_inject: Implement SMB_VFS_FNTIMES()
[samba.git] / source3 / modules / vfs_delay_inject.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Samba VFS module for delay injection in VFS calls
4  *  Copyright (C) Ralph Boehme 2018
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "locking/share_mode_lock.h"
22 #include "smbd/smbd.h"
23 #include "lib/util/tevent_unix.h"
24 #include "lib/global_contexts.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_VFS
28
29 static void inject_delay(const char *vfs_func, vfs_handle_struct *handle)
30 {
31         int delay;
32
33         delay = lp_parm_int(SNUM(handle->conn), "delay_inject", vfs_func, 0);
34         if (delay == 0) {
35                 return;
36         }
37
38         DBG_DEBUG("Injected delay for [%s] of [%d] ms\n", vfs_func, delay);
39
40         smb_msleep(delay);
41 }
42
43 static int vfs_delay_inject_ntimes(vfs_handle_struct *handle,
44                                    const struct smb_filename *smb_fname,
45                                    struct smb_file_time *ft)
46 {
47         inject_delay("ntimes", handle);
48
49         return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
50 }
51
52 static int vfs_delay_inject_fntimes(vfs_handle_struct *handle,
53                                     files_struct *fsp,
54                                     struct smb_file_time *ft)
55 {
56         inject_delay("fntimes", handle);
57
58         return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
59 }
60
61 struct vfs_delay_inject_pread_state {
62         struct tevent_context *ev;
63         struct vfs_handle_struct *handle;
64         struct files_struct *fsp;
65         void *data;
66         size_t n;
67         off_t offset;
68         ssize_t ret;
69         struct vfs_aio_state vfs_aio_state;
70 };
71
72 static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq);
73 static void vfs_delay_inject_pread_done(struct tevent_req *subreq);
74
75 static struct tevent_req *vfs_delay_inject_pread_send(
76                                 struct vfs_handle_struct *handle,
77                                 TALLOC_CTX *mem_ctx,
78                                 struct tevent_context *ev,
79                                 struct files_struct *fsp,
80                                 void *data,
81                                 size_t n,
82                                 off_t offset)
83 {
84         struct tevent_req *req = NULL, *subreq = NULL;
85         struct vfs_delay_inject_pread_state *state = NULL;
86         int delay;
87         struct timeval delay_tv;
88
89         delay = lp_parm_int(
90                 SNUM(handle->conn), "delay_inject", "pread_send", 0);
91         delay_tv = tevent_timeval_current_ofs(delay / 1000,
92                                               (delay * 1000) % 1000000);
93
94         req = tevent_req_create(mem_ctx, &state,
95                                 struct vfs_delay_inject_pread_state);
96         if (req == NULL) {
97                 return NULL;
98         }
99         *state = (struct vfs_delay_inject_pread_state) {
100                 .ev = ev,
101                 .handle = handle,
102                 .fsp = fsp,
103                 .data = data,
104                 .n = n,
105                 .offset = offset,
106         };
107
108         if (delay == 0) {
109                 subreq = SMB_VFS_NEXT_PREAD_SEND(state,
110                                                  state->ev,
111                                                  state->handle,
112                                                  state->fsp,
113                                                  state->data,
114                                                  state->n,
115                                                  state->offset);
116                 if (tevent_req_nomem(subreq, req)) {
117                         return tevent_req_post(req, ev);
118                 }
119                 tevent_req_set_callback(subreq,
120                                         vfs_delay_inject_pread_done,
121                                         req);
122                 return req;
123         }
124
125         subreq = tevent_wakeup_send(state, ev, delay_tv);
126         if (tevent_req_nomem(subreq, req)) {
127                 return tevent_req_post(req, ev);
128         }
129         tevent_req_set_callback(subreq, vfs_delay_inject_pread_wait_done, req);
130         return req;
131 }
132
133
134 static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq)
135 {
136         struct tevent_req *req = tevent_req_callback_data(
137                 subreq, struct tevent_req);
138         struct vfs_delay_inject_pread_state *state = tevent_req_data(
139                 req, struct vfs_delay_inject_pread_state);
140         bool ok;
141
142         ok = tevent_wakeup_recv(subreq);
143         TALLOC_FREE(subreq);
144         if (!ok) {
145                 tevent_req_error(req, EIO);
146                 return;
147         }
148
149         subreq = SMB_VFS_NEXT_PREAD_SEND(state,
150                                          state->ev,
151                                          state->handle,
152                                          state->fsp,
153                                          state->data,
154                                          state->n,
155                                          state->offset);
156         if (tevent_req_nomem(subreq, req)) {
157                 return;
158         }
159         tevent_req_set_callback(subreq, vfs_delay_inject_pread_done, req);
160 }
161
162 static void vfs_delay_inject_pread_done(struct tevent_req *subreq)
163 {
164         struct tevent_req *req = tevent_req_callback_data(
165                 subreq, struct tevent_req);
166         struct vfs_delay_inject_pread_state *state = tevent_req_data(
167                 req, struct vfs_delay_inject_pread_state);
168
169         state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
170         TALLOC_FREE(subreq);
171
172         tevent_req_done(req);
173 }
174
175 static ssize_t vfs_delay_inject_pread_recv(struct tevent_req *req,
176                                 struct vfs_aio_state *vfs_aio_state)
177 {
178         struct vfs_delay_inject_pread_state *state = tevent_req_data(
179                 req, struct vfs_delay_inject_pread_state);
180
181         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
182                 return -1;
183         }
184
185         *vfs_aio_state = state->vfs_aio_state;
186         return state->ret;
187 }
188
189 struct vfs_delay_inject_pwrite_state {
190         struct tevent_context *ev;
191         struct vfs_handle_struct *handle;
192         struct files_struct *fsp;
193         const void *data;
194         size_t n;
195         off_t offset;
196         ssize_t ret;
197         struct vfs_aio_state vfs_aio_state;
198 };
199
200 static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq);
201 static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq);
202
203 static struct tevent_req *vfs_delay_inject_pwrite_send(
204                                 struct vfs_handle_struct *handle,
205                                 TALLOC_CTX *mem_ctx,
206                                 struct tevent_context *ev,
207                                 struct files_struct *fsp,
208                                 const void *data,
209                                 size_t n,
210                                 off_t offset)
211 {
212         struct tevent_req *req = NULL, *subreq = NULL;
213         struct vfs_delay_inject_pwrite_state *state = NULL;
214         int delay;
215         struct timeval delay_tv;
216
217         delay = lp_parm_int(
218                 SNUM(handle->conn), "delay_inject", "pwrite_send", 0);
219         delay_tv = tevent_timeval_current_ofs(delay / 1000,
220                                               (delay * 1000) % 1000000);
221
222         req = tevent_req_create(mem_ctx, &state,
223                                 struct vfs_delay_inject_pwrite_state);
224         if (req == NULL) {
225                 return NULL;
226         }
227         *state = (struct vfs_delay_inject_pwrite_state) {
228                 .ev = ev,
229                 .handle = handle,
230                 .fsp = fsp,
231                 .data = data,
232                 .n = n,
233                 .offset = offset,
234         };
235
236         if (delay == 0) {
237                 subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
238                                                  state->ev,
239                                                  state->handle,
240                                                  state->fsp,
241                                                  state->data,
242                                                  state->n,
243                                                  state->offset);
244                 if (tevent_req_nomem(subreq, req)) {
245                         return tevent_req_post(req, ev);
246                 }
247                 tevent_req_set_callback(subreq,
248                                         vfs_delay_inject_pwrite_done,
249                                         req);
250                 return req;
251         }
252
253         subreq = tevent_wakeup_send(state, ev, delay_tv);
254         if (tevent_req_nomem(subreq, req)) {
255                 return tevent_req_post(req, ev);
256         }
257         tevent_req_set_callback(
258                 subreq, vfs_delay_inject_pwrite_wait_done, req);
259         return req;
260 }
261
262
263 static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq)
264 {
265         struct tevent_req *req = tevent_req_callback_data(
266                 subreq, struct tevent_req);
267         struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
268                 req, struct vfs_delay_inject_pwrite_state);
269         bool ok;
270
271         ok = tevent_wakeup_recv(subreq);
272         TALLOC_FREE(subreq);
273         if (!ok) {
274                 tevent_req_error(req, EIO);
275                 return;
276         }
277
278         subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
279                                          state->ev,
280                                          state->handle,
281                                          state->fsp,
282                                          state->data,
283                                          state->n,
284                                          state->offset);
285         if (tevent_req_nomem(subreq, req)) {
286                 return;
287         }
288         tevent_req_set_callback(subreq, vfs_delay_inject_pwrite_done, req);
289 }
290
291 static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq)
292 {
293         struct tevent_req *req = tevent_req_callback_data(
294                 subreq, struct tevent_req);
295         struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
296                 req, struct vfs_delay_inject_pwrite_state);
297
298         state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
299         TALLOC_FREE(subreq);
300
301         tevent_req_done(req);
302 }
303
304 static ssize_t vfs_delay_inject_pwrite_recv(struct tevent_req *req,
305                                 struct vfs_aio_state *vfs_aio_state)
306 {
307         struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
308                 req, struct vfs_delay_inject_pwrite_state);
309
310         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
311                 return -1;
312         }
313
314         *vfs_aio_state = state->vfs_aio_state;
315         return state->ret;
316 }
317
318 struct vfs_delay_inject_brl_lock_state {
319         struct vfs_delay_inject_brl_lock_state *prev, *next;
320         struct files_struct *fsp;
321         struct GUID req_guid;
322         struct timeval delay_tv;
323         struct tevent_timer *delay_te;
324 };
325
326 static struct vfs_delay_inject_brl_lock_state *brl_lock_states;
327
328 static int vfs_delay_inject_brl_lock_state_destructor(struct vfs_delay_inject_brl_lock_state *state)
329 {
330         DLIST_REMOVE(brl_lock_states, state);
331         return 0;
332 }
333
334 static void vfs_delay_inject_brl_lock_timer(struct tevent_context *ev,
335                                             struct tevent_timer *te,
336                                             struct timeval current_time,
337                                             void *private_data)
338 {
339         struct vfs_delay_inject_brl_lock_state *state =
340                 talloc_get_type_abort(private_data,
341                 struct vfs_delay_inject_brl_lock_state);
342         NTSTATUS status;
343
344         TALLOC_FREE(state->delay_te);
345
346         status = share_mode_wakeup_waiters(state->fsp->file_id);
347         if (!NT_STATUS_IS_OK(status)) {
348                 struct file_id_buf idbuf;
349                 DBG_ERR("share_mode_wakeup_waiters(%s) %s\n",
350                         file_id_str_buf(state->fsp->file_id, &idbuf),
351                         nt_errstr(status));
352         }
353 }
354
355 static NTSTATUS vfs_delay_inject_brl_lock_windows(struct vfs_handle_struct *handle,
356                                                   struct byte_range_lock *br_lck,
357                                                   struct lock_struct *plock)
358 {
359         struct files_struct *fsp = brl_fsp(br_lck);
360         TALLOC_CTX *req_mem_ctx = brl_req_mem_ctx(br_lck);
361         const struct GUID *req_guid = brl_req_guid(br_lck);
362         struct vfs_delay_inject_brl_lock_state *state = NULL;
363         bool expired;
364
365         for (state = brl_lock_states; state != NULL; state = state->next) {
366                 bool match;
367
368                 match = GUID_equal(&state->req_guid, req_guid);
369                 if (match) {
370                         break;
371                 }
372         }
373
374         if (state == NULL) {
375                 int delay;
376                 bool use_timer;
377
378                 state = talloc_zero(req_mem_ctx,
379                                     struct vfs_delay_inject_brl_lock_state);
380                 if (state == NULL) {
381                         return NT_STATUS_NO_MEMORY;
382                 }
383                 state->fsp = fsp;
384                 state->req_guid = *req_guid;
385
386                 delay = lp_parm_int(SNUM(handle->conn),
387                                     "delay_inject", "brl_lock_windows", 0);
388                 state->delay_tv = timeval_current_ofs_msec(delay);
389
390                 use_timer = lp_parm_bool(SNUM(handle->conn),
391                                     "delay_inject", "brl_lock_windows_use_timer", true);
392
393                 if (use_timer) {
394                         state->delay_te = tevent_add_timer(
395                                         global_event_context(),
396                                         state,
397                                         state->delay_tv,
398                                         vfs_delay_inject_brl_lock_timer,
399                                         state);
400                         if (state->delay_te == NULL) {
401                                 return NT_STATUS_NO_MEMORY;
402                         }
403                 }
404
405                 talloc_set_destructor(state,
406                         vfs_delay_inject_brl_lock_state_destructor);
407                 DLIST_ADD_END(brl_lock_states, state);
408         }
409
410         if (state->delay_te != NULL) {
411                 plock->context.smblctx = 0;
412                 return NT_STATUS_RETRY;
413         }
414
415         expired = timeval_expired(&state->delay_tv);
416         if (!expired) {
417                 plock->context.smblctx = UINT64_MAX;
418                 return NT_STATUS_RETRY;
419         }
420
421         TALLOC_FREE(state);
422
423         return SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock);
424 }
425
426 static bool vfs_delay_inject_brl_unlock_windows(struct vfs_handle_struct *handle,
427                                                 struct byte_range_lock *br_lck,
428                                                 const struct lock_struct *plock)
429 {
430         return SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, br_lck, plock);
431 }
432
433 static struct vfs_fn_pointers vfs_delay_inject_fns = {
434         .ntimes_fn = vfs_delay_inject_ntimes,
435         .fntimes_fn = vfs_delay_inject_fntimes,
436         .pread_send_fn = vfs_delay_inject_pread_send,
437         .pread_recv_fn = vfs_delay_inject_pread_recv,
438         .pwrite_send_fn = vfs_delay_inject_pwrite_send,
439         .pwrite_recv_fn = vfs_delay_inject_pwrite_recv,
440
441         .brl_lock_windows_fn = vfs_delay_inject_brl_lock_windows,
442         .brl_unlock_windows_fn = vfs_delay_inject_brl_unlock_windows,
443 };
444
445 static_decl_vfs;
446 NTSTATUS vfs_delay_inject_init(TALLOC_CTX *ctx)
447 {
448         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "delay_inject",
449                                 &vfs_delay_inject_fns);
450 }