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/>.
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"
27 #define DBGC_CLASS DBGC_VFS
29 static void inject_delay(const char *vfs_func
, vfs_handle_struct
*handle
)
33 delay
= lp_parm_int(SNUM(handle
->conn
), "delay_inject", vfs_func
, 0);
38 DBG_DEBUG("Injected delay for [%s] of [%d] ms\n", vfs_func
, delay
);
43 static int vfs_delay_inject_fntimes(vfs_handle_struct
*handle
,
45 struct smb_file_time
*ft
)
47 inject_delay("fntimes", handle
);
49 return SMB_VFS_NEXT_FNTIMES(handle
, fsp
, ft
);
52 struct vfs_delay_inject_pread_state
{
53 struct tevent_context
*ev
;
54 struct vfs_handle_struct
*handle
;
55 struct files_struct
*fsp
;
60 struct vfs_aio_state vfs_aio_state
;
63 static void vfs_delay_inject_pread_wait_done(struct tevent_req
*subreq
);
64 static void vfs_delay_inject_pread_done(struct tevent_req
*subreq
);
66 static struct tevent_req
*vfs_delay_inject_pread_send(
67 struct vfs_handle_struct
*handle
,
69 struct tevent_context
*ev
,
70 struct files_struct
*fsp
,
75 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
76 struct vfs_delay_inject_pread_state
*state
= NULL
;
78 struct timeval delay_tv
;
81 SNUM(handle
->conn
), "delay_inject", "pread_send", 0);
82 delay_tv
= tevent_timeval_current_ofs(delay
/ 1000,
83 (delay
* 1000) % 1000000);
85 req
= tevent_req_create(mem_ctx
, &state
,
86 struct vfs_delay_inject_pread_state
);
90 *state
= (struct vfs_delay_inject_pread_state
) {
100 subreq
= SMB_VFS_NEXT_PREAD_SEND(state
,
107 if (tevent_req_nomem(subreq
, req
)) {
108 return tevent_req_post(req
, ev
);
110 tevent_req_set_callback(subreq
,
111 vfs_delay_inject_pread_done
,
116 subreq
= tevent_wakeup_send(state
, ev
, delay_tv
);
117 if (tevent_req_nomem(subreq
, req
)) {
118 return tevent_req_post(req
, ev
);
120 tevent_req_set_callback(subreq
, vfs_delay_inject_pread_wait_done
, req
);
125 static void vfs_delay_inject_pread_wait_done(struct tevent_req
*subreq
)
127 struct tevent_req
*req
= tevent_req_callback_data(
128 subreq
, struct tevent_req
);
129 struct vfs_delay_inject_pread_state
*state
= tevent_req_data(
130 req
, struct vfs_delay_inject_pread_state
);
133 ok
= tevent_wakeup_recv(subreq
);
136 tevent_req_error(req
, EIO
);
140 subreq
= SMB_VFS_NEXT_PREAD_SEND(state
,
147 if (tevent_req_nomem(subreq
, req
)) {
150 tevent_req_set_callback(subreq
, vfs_delay_inject_pread_done
, req
);
153 static void vfs_delay_inject_pread_done(struct tevent_req
*subreq
)
155 struct tevent_req
*req
= tevent_req_callback_data(
156 subreq
, struct tevent_req
);
157 struct vfs_delay_inject_pread_state
*state
= tevent_req_data(
158 req
, struct vfs_delay_inject_pread_state
);
160 state
->ret
= SMB_VFS_PREAD_RECV(subreq
, &state
->vfs_aio_state
);
163 tevent_req_done(req
);
166 static ssize_t
vfs_delay_inject_pread_recv(struct tevent_req
*req
,
167 struct vfs_aio_state
*vfs_aio_state
)
169 struct vfs_delay_inject_pread_state
*state
= tevent_req_data(
170 req
, struct vfs_delay_inject_pread_state
);
172 if (tevent_req_is_unix_error(req
, &vfs_aio_state
->error
)) {
176 *vfs_aio_state
= state
->vfs_aio_state
;
180 struct vfs_delay_inject_pwrite_state
{
181 struct tevent_context
*ev
;
182 struct vfs_handle_struct
*handle
;
183 struct files_struct
*fsp
;
188 struct vfs_aio_state vfs_aio_state
;
191 static void vfs_delay_inject_pwrite_wait_done(struct tevent_req
*subreq
);
192 static void vfs_delay_inject_pwrite_done(struct tevent_req
*subreq
);
194 static struct tevent_req
*vfs_delay_inject_pwrite_send(
195 struct vfs_handle_struct
*handle
,
197 struct tevent_context
*ev
,
198 struct files_struct
*fsp
,
203 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
204 struct vfs_delay_inject_pwrite_state
*state
= NULL
;
206 struct timeval delay_tv
;
209 SNUM(handle
->conn
), "delay_inject", "pwrite_send", 0);
210 delay_tv
= tevent_timeval_current_ofs(delay
/ 1000,
211 (delay
* 1000) % 1000000);
213 req
= tevent_req_create(mem_ctx
, &state
,
214 struct vfs_delay_inject_pwrite_state
);
218 *state
= (struct vfs_delay_inject_pwrite_state
) {
228 subreq
= SMB_VFS_NEXT_PWRITE_SEND(state
,
235 if (tevent_req_nomem(subreq
, req
)) {
236 return tevent_req_post(req
, ev
);
238 tevent_req_set_callback(subreq
,
239 vfs_delay_inject_pwrite_done
,
244 subreq
= tevent_wakeup_send(state
, ev
, delay_tv
);
245 if (tevent_req_nomem(subreq
, req
)) {
246 return tevent_req_post(req
, ev
);
248 tevent_req_set_callback(
249 subreq
, vfs_delay_inject_pwrite_wait_done
, req
);
254 static void vfs_delay_inject_pwrite_wait_done(struct tevent_req
*subreq
)
256 struct tevent_req
*req
= tevent_req_callback_data(
257 subreq
, struct tevent_req
);
258 struct vfs_delay_inject_pwrite_state
*state
= tevent_req_data(
259 req
, struct vfs_delay_inject_pwrite_state
);
262 ok
= tevent_wakeup_recv(subreq
);
265 tevent_req_error(req
, EIO
);
269 subreq
= SMB_VFS_NEXT_PWRITE_SEND(state
,
276 if (tevent_req_nomem(subreq
, req
)) {
279 tevent_req_set_callback(subreq
, vfs_delay_inject_pwrite_done
, req
);
282 static void vfs_delay_inject_pwrite_done(struct tevent_req
*subreq
)
284 struct tevent_req
*req
= tevent_req_callback_data(
285 subreq
, struct tevent_req
);
286 struct vfs_delay_inject_pwrite_state
*state
= tevent_req_data(
287 req
, struct vfs_delay_inject_pwrite_state
);
289 state
->ret
= SMB_VFS_PWRITE_RECV(subreq
, &state
->vfs_aio_state
);
292 tevent_req_done(req
);
295 static ssize_t
vfs_delay_inject_pwrite_recv(struct tevent_req
*req
,
296 struct vfs_aio_state
*vfs_aio_state
)
298 struct vfs_delay_inject_pwrite_state
*state
= tevent_req_data(
299 req
, struct vfs_delay_inject_pwrite_state
);
301 if (tevent_req_is_unix_error(req
, &vfs_aio_state
->error
)) {
305 *vfs_aio_state
= state
->vfs_aio_state
;
309 struct vfs_delay_inject_brl_lock_state
{
310 struct vfs_delay_inject_brl_lock_state
*prev
, *next
;
311 struct files_struct
*fsp
;
312 struct GUID req_guid
;
313 struct timeval delay_tv
;
314 struct tevent_timer
*delay_te
;
317 static struct vfs_delay_inject_brl_lock_state
*brl_lock_states
;
319 static int vfs_delay_inject_brl_lock_state_destructor(struct vfs_delay_inject_brl_lock_state
*state
)
321 DLIST_REMOVE(brl_lock_states
, state
);
325 static void vfs_delay_inject_brl_lock_timer(struct tevent_context
*ev
,
326 struct tevent_timer
*te
,
327 struct timeval current_time
,
330 struct vfs_delay_inject_brl_lock_state
*state
=
331 talloc_get_type_abort(private_data
,
332 struct vfs_delay_inject_brl_lock_state
);
335 TALLOC_FREE(state
->delay_te
);
337 status
= share_mode_wakeup_waiters(state
->fsp
->file_id
);
338 if (!NT_STATUS_IS_OK(status
)) {
339 struct file_id_buf idbuf
;
340 DBG_ERR("share_mode_wakeup_waiters(%s) %s\n",
341 file_id_str_buf(state
->fsp
->file_id
, &idbuf
),
346 static NTSTATUS
vfs_delay_inject_brl_lock_windows(struct vfs_handle_struct
*handle
,
347 struct byte_range_lock
*br_lck
,
348 struct lock_struct
*plock
)
350 struct files_struct
*fsp
= brl_fsp(br_lck
);
351 TALLOC_CTX
*req_mem_ctx
= brl_req_mem_ctx(br_lck
);
352 const struct GUID
*req_guid
= brl_req_guid(br_lck
);
353 struct vfs_delay_inject_brl_lock_state
*state
= NULL
;
356 for (state
= brl_lock_states
; state
!= NULL
; state
= state
->next
) {
359 match
= GUID_equal(&state
->req_guid
, req_guid
);
369 state
= talloc_zero(req_mem_ctx
,
370 struct vfs_delay_inject_brl_lock_state
);
372 return NT_STATUS_NO_MEMORY
;
375 state
->req_guid
= *req_guid
;
377 delay
= lp_parm_int(SNUM(handle
->conn
),
378 "delay_inject", "brl_lock_windows", 0);
379 state
->delay_tv
= timeval_current_ofs_msec(delay
);
381 use_timer
= lp_parm_bool(SNUM(handle
->conn
),
382 "delay_inject", "brl_lock_windows_use_timer", true);
385 state
->delay_te
= tevent_add_timer(
386 global_event_context(),
389 vfs_delay_inject_brl_lock_timer
,
391 if (state
->delay_te
== NULL
) {
392 return NT_STATUS_NO_MEMORY
;
396 talloc_set_destructor(state
,
397 vfs_delay_inject_brl_lock_state_destructor
);
398 DLIST_ADD_END(brl_lock_states
, state
);
401 if (state
->delay_te
!= NULL
) {
402 plock
->context
.smblctx
= 0;
403 return NT_STATUS_RETRY
;
406 expired
= timeval_expired(&state
->delay_tv
);
408 plock
->context
.smblctx
= UINT64_MAX
;
409 return NT_STATUS_RETRY
;
414 return SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle
, br_lck
, plock
);
417 static bool vfs_delay_inject_brl_unlock_windows(struct vfs_handle_struct
*handle
,
418 struct byte_range_lock
*br_lck
,
419 const struct lock_struct
*plock
)
421 return SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle
, br_lck
, plock
);
424 static struct vfs_fn_pointers vfs_delay_inject_fns
= {
425 .fntimes_fn
= vfs_delay_inject_fntimes
,
426 .pread_send_fn
= vfs_delay_inject_pread_send
,
427 .pread_recv_fn
= vfs_delay_inject_pread_recv
,
428 .pwrite_send_fn
= vfs_delay_inject_pwrite_send
,
429 .pwrite_recv_fn
= vfs_delay_inject_pwrite_recv
,
431 .brl_lock_windows_fn
= vfs_delay_inject_brl_lock_windows
,
432 .brl_unlock_windows_fn
= vfs_delay_inject_brl_unlock_windows
,
436 NTSTATUS
vfs_delay_inject_init(TALLOC_CTX
*ctx
)
438 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "delay_inject",
439 &vfs_delay_inject_fns
);