s3:lib: Make sure that have_rsrc is initialized
[Samba.git] / source3 / modules / vfs_delay_inject.c
blob6be9fe5729233043430bbd72ea936d4fe8256a49
1 /*
2 * Unix SMB/CIFS implementation.
3 * Samba VFS module for delay injection in VFS calls
4 * Copyright (C) Ralph Boehme 2018
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.
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.
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/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "lib/util/tevent_unix.h"
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_VFS
27 static void inject_delay(const char *vfs_func, vfs_handle_struct *handle)
29 int delay;
31 delay = lp_parm_int(SNUM(handle->conn), "delay_inject", vfs_func, 0);
32 if (delay == 0) {
33 return;
36 DBG_DEBUG("Injected delay for [%s] of [%d] ms\n", vfs_func, delay);
38 smb_msleep(delay);
41 static int vfs_delay_inject_ntimes(vfs_handle_struct *handle,
42 const struct smb_filename *smb_fname,
43 struct smb_file_time *ft)
45 inject_delay("ntimes", handle);
47 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
50 struct vfs_delay_inject_pread_state {
51 struct tevent_context *ev;
52 struct vfs_handle_struct *handle;
53 struct files_struct *fsp;
54 void *data;
55 size_t n;
56 off_t offset;
57 ssize_t ret;
58 struct vfs_aio_state vfs_aio_state;
61 static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq);
62 static void vfs_delay_inject_pread_done(struct tevent_req *subreq);
64 static struct tevent_req *vfs_delay_inject_pread_send(
65 struct vfs_handle_struct *handle,
66 TALLOC_CTX *mem_ctx,
67 struct tevent_context *ev,
68 struct files_struct *fsp,
69 void *data,
70 size_t n,
71 off_t offset)
73 struct tevent_req *req = NULL, *subreq = NULL;
74 struct vfs_delay_inject_pread_state *state = NULL;
75 int delay;
76 struct timeval delay_tv;
78 delay = lp_parm_int(
79 SNUM(handle->conn), "delay_inject", "pread_send", 0);
80 delay_tv = tevent_timeval_current_ofs(delay / 1000,
81 (delay * 1000) % 1000000);
83 req = tevent_req_create(mem_ctx, &state,
84 struct vfs_delay_inject_pread_state);
85 if (req == NULL) {
86 return NULL;
88 *state = (struct vfs_delay_inject_pread_state) {
89 .ev = ev,
90 .handle = handle,
91 .fsp = fsp,
92 .data = data,
93 .n = n,
94 .offset = offset,
97 if (delay == 0) {
98 subreq = SMB_VFS_NEXT_PREAD_SEND(state,
99 state->ev,
100 state->handle,
101 state->fsp,
102 state->data,
103 state->n,
104 state->offset);
105 if (tevent_req_nomem(subreq, req)) {
106 return tevent_req_post(req, ev);
108 tevent_req_set_callback(subreq,
109 vfs_delay_inject_pread_done,
110 req);
111 return req;
114 subreq = tevent_wakeup_send(state, ev, delay_tv);
115 if (tevent_req_nomem(subreq, req)) {
116 return tevent_req_post(req, ev);
118 tevent_req_set_callback(subreq, vfs_delay_inject_pread_wait_done, req);
119 return req;
123 static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq)
125 struct tevent_req *req = tevent_req_callback_data(
126 subreq, struct tevent_req);
127 struct vfs_delay_inject_pread_state *state = tevent_req_data(
128 req, struct vfs_delay_inject_pread_state);
129 bool ok;
131 ok = tevent_wakeup_recv(subreq);
132 TALLOC_FREE(subreq);
133 if (!ok) {
134 tevent_req_error(req, EIO);
135 return;
138 subreq = SMB_VFS_NEXT_PREAD_SEND(state,
139 state->ev,
140 state->handle,
141 state->fsp,
142 state->data,
143 state->n,
144 state->offset);
145 if (tevent_req_nomem(subreq, req)) {
146 return;
148 tevent_req_set_callback(subreq, vfs_delay_inject_pread_done, req);
151 static void vfs_delay_inject_pread_done(struct tevent_req *subreq)
153 struct tevent_req *req = tevent_req_callback_data(
154 subreq, struct tevent_req);
155 struct vfs_delay_inject_pread_state *state = tevent_req_data(
156 req, struct vfs_delay_inject_pread_state);
158 state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
159 TALLOC_FREE(subreq);
161 tevent_req_done(req);
164 static ssize_t vfs_delay_inject_pread_recv(struct tevent_req *req,
165 struct vfs_aio_state *vfs_aio_state)
167 struct vfs_delay_inject_pread_state *state = tevent_req_data(
168 req, struct vfs_delay_inject_pread_state);
170 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
171 return -1;
174 *vfs_aio_state = state->vfs_aio_state;
175 return state->ret;
178 struct vfs_delay_inject_pwrite_state {
179 struct tevent_context *ev;
180 struct vfs_handle_struct *handle;
181 struct files_struct *fsp;
182 const void *data;
183 size_t n;
184 off_t offset;
185 ssize_t ret;
186 struct vfs_aio_state vfs_aio_state;
189 static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq);
190 static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq);
192 static struct tevent_req *vfs_delay_inject_pwrite_send(
193 struct vfs_handle_struct *handle,
194 TALLOC_CTX *mem_ctx,
195 struct tevent_context *ev,
196 struct files_struct *fsp,
197 const void *data,
198 size_t n,
199 off_t offset)
201 struct tevent_req *req = NULL, *subreq = NULL;
202 struct vfs_delay_inject_pwrite_state *state = NULL;
203 int delay;
204 struct timeval delay_tv;
206 delay = lp_parm_int(
207 SNUM(handle->conn), "delay_inject", "pwrite_send", 0);
208 delay_tv = tevent_timeval_current_ofs(delay / 1000,
209 (delay * 1000) % 1000000);
211 req = tevent_req_create(mem_ctx, &state,
212 struct vfs_delay_inject_pwrite_state);
213 if (req == NULL) {
214 return NULL;
216 *state = (struct vfs_delay_inject_pwrite_state) {
217 .ev = ev,
218 .handle = handle,
219 .fsp = fsp,
220 .data = data,
221 .n = n,
222 .offset = offset,
225 if (delay == 0) {
226 subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
227 state->ev,
228 state->handle,
229 state->fsp,
230 state->data,
231 state->n,
232 state->offset);
233 if (tevent_req_nomem(subreq, req)) {
234 return tevent_req_post(req, ev);
236 tevent_req_set_callback(subreq,
237 vfs_delay_inject_pwrite_done,
238 req);
239 return req;
242 subreq = tevent_wakeup_send(state, ev, delay_tv);
243 if (tevent_req_nomem(subreq, req)) {
244 return tevent_req_post(req, ev);
246 tevent_req_set_callback(
247 subreq, vfs_delay_inject_pwrite_wait_done, req);
248 return req;
252 static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq)
254 struct tevent_req *req = tevent_req_callback_data(
255 subreq, struct tevent_req);
256 struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
257 req, struct vfs_delay_inject_pwrite_state);
258 bool ok;
260 ok = tevent_wakeup_recv(subreq);
261 TALLOC_FREE(subreq);
262 if (!ok) {
263 tevent_req_error(req, EIO);
264 return;
267 subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
268 state->ev,
269 state->handle,
270 state->fsp,
271 state->data,
272 state->n,
273 state->offset);
274 if (tevent_req_nomem(subreq, req)) {
275 return;
277 tevent_req_set_callback(subreq, vfs_delay_inject_pwrite_done, req);
280 static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq)
282 struct tevent_req *req = tevent_req_callback_data(
283 subreq, struct tevent_req);
284 struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
285 req, struct vfs_delay_inject_pwrite_state);
287 state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
288 TALLOC_FREE(subreq);
290 tevent_req_done(req);
293 static ssize_t vfs_delay_inject_pwrite_recv(struct tevent_req *req,
294 struct vfs_aio_state *vfs_aio_state)
296 struct vfs_delay_inject_pwrite_state *state = tevent_req_data(
297 req, struct vfs_delay_inject_pwrite_state);
299 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
300 return -1;
303 *vfs_aio_state = state->vfs_aio_state;
304 return state->ret;
307 struct vfs_delay_inject_brl_lock_state {
308 struct vfs_delay_inject_brl_lock_state *prev, *next;
309 struct files_struct *fsp;
310 struct GUID req_guid;
311 struct timeval delay_tv;
312 struct tevent_timer *delay_te;
315 static struct vfs_delay_inject_brl_lock_state *brl_lock_states;
317 static int vfs_delay_inject_brl_lock_state_destructor(struct vfs_delay_inject_brl_lock_state *state)
319 DLIST_REMOVE(brl_lock_states, state);
320 return 0;
323 static void vfs_delay_inject_brl_lock_timer(struct tevent_context *ev,
324 struct tevent_timer *te,
325 struct timeval current_time,
326 void *private_data)
328 struct vfs_delay_inject_brl_lock_state *state =
329 talloc_get_type_abort(private_data,
330 struct vfs_delay_inject_brl_lock_state);
331 NTSTATUS status;
333 TALLOC_FREE(state->delay_te);
335 status = share_mode_wakeup_waiters(state->fsp->file_id);
336 if (!NT_STATUS_IS_OK(status)) {
337 struct file_id_buf idbuf;
338 DBG_ERR("share_mode_wakeup_waiters(%s) %s\n",
339 file_id_str_buf(state->fsp->file_id, &idbuf),
340 nt_errstr(status));
344 static NTSTATUS vfs_delay_inject_brl_lock_windows(struct vfs_handle_struct *handle,
345 struct byte_range_lock *br_lck,
346 struct lock_struct *plock)
348 struct files_struct *fsp = brl_fsp(br_lck);
349 TALLOC_CTX *req_mem_ctx = brl_req_mem_ctx(br_lck);
350 const struct GUID *req_guid = brl_req_guid(br_lck);
351 struct vfs_delay_inject_brl_lock_state *state = NULL;
352 bool expired;
354 for (state = brl_lock_states; state != NULL; state = state->next) {
355 bool match;
357 match = GUID_equal(&state->req_guid, req_guid);
358 if (match) {
359 break;
363 if (state == NULL) {
364 int delay;
365 bool use_timer;
367 state = talloc_zero(req_mem_ctx,
368 struct vfs_delay_inject_brl_lock_state);
369 if (state == NULL) {
370 return NT_STATUS_NO_MEMORY;
372 state->fsp = fsp;
373 state->req_guid = *req_guid;
375 delay = lp_parm_int(SNUM(handle->conn),
376 "delay_inject", "brl_lock_windows", 0);
377 state->delay_tv = timeval_current_ofs_msec(delay);
379 use_timer = lp_parm_bool(SNUM(handle->conn),
380 "delay_inject", "brl_lock_windows_use_timer", true);
382 if (use_timer) {
383 state->delay_te = tevent_add_timer(
384 global_event_context(),
385 state,
386 state->delay_tv,
387 vfs_delay_inject_brl_lock_timer,
388 state);
389 if (state->delay_te == NULL) {
390 return NT_STATUS_NO_MEMORY;
394 talloc_set_destructor(state,
395 vfs_delay_inject_brl_lock_state_destructor);
396 DLIST_ADD_END(brl_lock_states, state);
399 if (state->delay_te != NULL) {
400 plock->context.smblctx = 0;
401 return NT_STATUS_RETRY;
404 expired = timeval_expired(&state->delay_tv);
405 if (!expired) {
406 plock->context.smblctx = UINT64_MAX;
407 return NT_STATUS_RETRY;
410 TALLOC_FREE(state);
412 return SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock);
415 static bool vfs_delay_inject_brl_unlock_windows(struct vfs_handle_struct *handle,
416 struct byte_range_lock *br_lck,
417 const struct lock_struct *plock)
419 return SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, br_lck, plock);
422 static struct vfs_fn_pointers vfs_delay_inject_fns = {
423 .ntimes_fn = vfs_delay_inject_ntimes,
424 .pread_send_fn = vfs_delay_inject_pread_send,
425 .pread_recv_fn = vfs_delay_inject_pread_recv,
426 .pwrite_send_fn = vfs_delay_inject_pwrite_send,
427 .pwrite_recv_fn = vfs_delay_inject_pwrite_recv,
429 .brl_lock_windows_fn = vfs_delay_inject_brl_lock_windows,
430 .brl_unlock_windows_fn = vfs_delay_inject_brl_unlock_windows,
433 static_decl_vfs;
434 NTSTATUS vfs_delay_inject_init(TALLOC_CTX *ctx)
436 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "delay_inject",
437 &vfs_delay_inject_fns);