From 27fb50fd22deaabc70e2951574c532fb827e3c02 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 28 Oct 2018 19:28:42 +0100 Subject: [PATCH] vfs_delay_inject: implement pread_send and pwrite_send Bug: https://bugzilla.samba.org/show_bug.cgi?id=13667 Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit 35f9bc06722fb07143c832442d784beb204bd367) --- source3/modules/vfs_delay_inject.c | 262 +++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) diff --git a/source3/modules/vfs_delay_inject.c b/source3/modules/vfs_delay_inject.c index 21fea9b10f4..d561fadb03b 100644 --- a/source3/modules/vfs_delay_inject.c +++ b/source3/modules/vfs_delay_inject.c @@ -19,6 +19,7 @@ #include "includes.h" #include "smbd/smbd.h" +#include "lib/util/tevent_unix.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS @@ -46,8 +47,269 @@ static int vfs_delay_inject_ntimes(vfs_handle_struct *handle, return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft); } +struct vfs_delay_inject_pread_state { + struct tevent_context *ev; + struct vfs_handle_struct *handle; + struct files_struct *fsp; + void *data; + size_t n; + off_t offset; + ssize_t ret; + struct vfs_aio_state vfs_aio_state; +}; + +static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq); +static void vfs_delay_inject_pread_done(struct tevent_req *subreq); + +static struct tevent_req *vfs_delay_inject_pread_send( + struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + void *data, + size_t n, + off_t offset) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct vfs_delay_inject_pread_state *state = NULL; + int delay; + struct timeval delay_tv; + + delay = lp_parm_int( + SNUM(handle->conn), "delay_inject", "pread_send", 0); + delay_tv = tevent_timeval_current_ofs(delay / 1000, + (delay * 1000) % 1000000); + + req = tevent_req_create(mem_ctx, &state, + struct vfs_delay_inject_pread_state); + if (req == NULL) { + return NULL; + } + *state = (struct vfs_delay_inject_pread_state) { + .ev = ev, + .handle = handle, + .fsp = fsp, + .data = data, + .n = n, + .offset = offset, + }; + + if (delay == 0) { + subreq = SMB_VFS_NEXT_PREAD_SEND(state, + state->ev, + state->handle, + state->fsp, + state->data, + state->n, + state->offset); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, + vfs_delay_inject_pread_done, + req); + return req; + } + + subreq = tevent_wakeup_send(state, ev, delay_tv); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, vfs_delay_inject_pread_wait_done, req); + return req; +} + + +static void vfs_delay_inject_pread_wait_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct vfs_delay_inject_pread_state *state = tevent_req_data( + req, struct vfs_delay_inject_pread_state); + bool ok; + + ok = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + tevent_req_error(req, EIO); + return; + } + + subreq = SMB_VFS_NEXT_PREAD_SEND(state, + state->ev, + state->handle, + state->fsp, + state->data, + state->n, + state->offset); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, vfs_delay_inject_pread_done, req); +} + +static void vfs_delay_inject_pread_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct vfs_delay_inject_pread_state *state = tevent_req_data( + req, struct vfs_delay_inject_pread_state); + + state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + + tevent_req_done(req); +} + +static ssize_t vfs_delay_inject_pread_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct vfs_delay_inject_pread_state *state = tevent_req_data( + req, struct vfs_delay_inject_pread_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + +struct vfs_delay_inject_pwrite_state { + struct tevent_context *ev; + struct vfs_handle_struct *handle; + struct files_struct *fsp; + const void *data; + size_t n; + off_t offset; + ssize_t ret; + struct vfs_aio_state vfs_aio_state; +}; + +static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq); +static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq); + +static struct tevent_req *vfs_delay_inject_pwrite_send( + struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + const void *data, + size_t n, + off_t offset) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct vfs_delay_inject_pwrite_state *state = NULL; + int delay; + struct timeval delay_tv; + + delay = lp_parm_int( + SNUM(handle->conn), "delay_inject", "pwrite_send", 0); + delay_tv = tevent_timeval_current_ofs(delay / 1000, + (delay * 1000) % 1000000); + + req = tevent_req_create(mem_ctx, &state, + struct vfs_delay_inject_pwrite_state); + if (req == NULL) { + return NULL; + } + *state = (struct vfs_delay_inject_pwrite_state) { + .ev = ev, + .handle = handle, + .fsp = fsp, + .data = data, + .n = n, + .offset = offset, + }; + + if (delay == 0) { + subreq = SMB_VFS_NEXT_PWRITE_SEND(state, + state->ev, + state->handle, + state->fsp, + state->data, + state->n, + state->offset); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, + vfs_delay_inject_pwrite_done, + req); + return req; + } + + subreq = tevent_wakeup_send(state, ev, delay_tv); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback( + subreq, vfs_delay_inject_pwrite_wait_done, req); + return req; +} + + +static void vfs_delay_inject_pwrite_wait_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct vfs_delay_inject_pwrite_state *state = tevent_req_data( + req, struct vfs_delay_inject_pwrite_state); + bool ok; + + ok = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + tevent_req_error(req, EIO); + return; + } + + subreq = SMB_VFS_NEXT_PWRITE_SEND(state, + state->ev, + state->handle, + state->fsp, + state->data, + state->n, + state->offset); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, vfs_delay_inject_pwrite_done, req); +} + +static void vfs_delay_inject_pwrite_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct vfs_delay_inject_pwrite_state *state = tevent_req_data( + req, struct vfs_delay_inject_pwrite_state); + + state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + + tevent_req_done(req); +} + +static ssize_t vfs_delay_inject_pwrite_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct vfs_delay_inject_pwrite_state *state = tevent_req_data( + req, struct vfs_delay_inject_pwrite_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + static struct vfs_fn_pointers vfs_delay_inject_fns = { .ntimes_fn = vfs_delay_inject_ntimes, + .pread_send_fn = vfs_delay_inject_pread_send, + .pread_recv_fn = vfs_delay_inject_pread_recv, + .pwrite_send_fn = vfs_delay_inject_pwrite_send, + .pwrite_recv_fn = vfs_delay_inject_pwrite_recv, }; static_decl_vfs; -- 2.47.2