From 7fc8086e11497c96be72859a510f72cb3c4104d5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 10 Mar 2009 10:56:33 +0100 Subject: s3:libsmb: fix a lot of cli_push() bugs There were the following problems: 1.) if window_size was a multiple of the chunk_size, we silently dropped the last truncated chunk. 2.) if window_size was 0 pushed only the first chunk to the server and silently dropped the rest. 3.) we had only transferred state->num_reqs writes, even if there would be more data to send. metze --- source3/libsmb/clireadwrite.c | 202 ++++++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 95 deletions(-) (limited to 'source3/libsmb/clireadwrite.c') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 9d17ff86a5..764ef631f2 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -915,9 +915,15 @@ static NTSTATUS cli_writeall_recv(struct async_req *req) return async_req_simple_recv_ntstatus(req); } -struct cli_push_state { - struct async_req *req; +struct cli_push_write_state { + struct async_req *req;/* This is the main request! Not the subreq */ + uint32_t idx; + off_t ofs; + uint8_t *buf; + size_t size; +}; +struct cli_push_state { struct event_context *ev; struct cli_state *cli; uint16_t fnum; @@ -928,24 +934,72 @@ struct cli_push_state { size_t (*source)(uint8_t *buf, size_t n, void *priv); void *priv; - size_t chunk_size; - - size_t sent; bool eof; + size_t chunk_size; + off_t next_offset; + /* * Outstanding requests */ - int num_reqs; - struct async_req **reqs; - - int pending; - - uint8_t *buf; + uint32_t pending; + uint32_t num_reqs; + struct cli_push_write_state **reqs; }; static void cli_push_written(struct async_req *req); +static bool cli_push_write_setup(struct async_req *req, + struct cli_push_state *state, + uint32_t idx) +{ + struct cli_push_write_state *substate; + struct async_req *subreq; + + substate = talloc(state->reqs, struct cli_push_write_state); + if (!substate) { + return false; + } + substate->req = req; + substate->idx = idx; + substate->ofs = state->next_offset; + substate->buf = talloc_array(substate, uint8_t, state->chunk_size); + if (!substate->buf) { + talloc_free(substate); + return false; + } + substate->size = state->source(substate->buf, + state->chunk_size, + state->priv); + if (substate->size < state->chunk_size) { + state->eof = true; + } + if (substate->size == 0) { + /* nothing to send */ + talloc_free(substate); + return true; + } + + subreq = cli_writeall_send(substate, + state->ev, state->cli, + state->fnum, state->mode, + substate->buf, + substate->ofs, + substate->size); + if (!subreq) { + talloc_free(substate); + return false; + } + subreq->async.fn = cli_push_written; + subreq->async.priv = substate; + + state->reqs[idx] = substate; + state->pending += 1; + state->next_offset += substate->size; + + return true; +} + struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, uint16_t fnum, uint16_t mode, @@ -954,16 +1008,14 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, void *priv), void *priv) { - struct async_req *result; + struct async_req *req; struct cli_push_state *state; - int i; + uint32_t i; - if (!async_req_setup(mem_ctx, &result, &state, + if (!async_req_setup(mem_ctx, &req, &state, struct cli_push_state)) { return NULL; } - state->req = result; - state->cli = cli; state->ev = ev; state->fnum = fnum; @@ -972,124 +1024,84 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, state->source = source; state->priv = priv; state->eof = false; - state->sent = 0; state->pending = 0; + state->next_offset = start_offset; state->chunk_size = cli_write_max_bufsize(cli, mode); - state->num_reqs = MAX(window_size/state->chunk_size, 1); + if (window_size == 0) { + window_size = cli->max_mux * state->chunk_size; + } + state->num_reqs = window_size/state->chunk_size; + if ((window_size % state->chunk_size) > 0) { + state->num_reqs += 1; + } state->num_reqs = MIN(state->num_reqs, cli->max_mux); + state->num_reqs = MAX(state->num_reqs, 1); - state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *, + state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_push_write_state *, state->num_reqs); if (state->reqs == NULL) { goto failed; } - state->buf = TALLOC_ARRAY( - state, uint8_t, state->chunk_size * state->num_reqs); - if (state->buf == NULL) { - goto failed; - } - for (i=0; inum_reqs; i++) { - size_t to_write; - uint8_t *buf = state->buf + i*state->chunk_size; - - to_write = state->source(buf, state->chunk_size, state->priv); - if (to_write == 0) { - state->eof = true; - break; - } - - state->reqs[i] = cli_writeall_send( - state->reqs, state->ev, state->cli, state->fnum, - state->mode, buf, state->start_offset + state->sent, - to_write); - if (state->reqs[i] == NULL) { + if (!cli_push_write_setup(req, state, i)) { goto failed; } - state->reqs[i]->async.fn = cli_push_written; - state->reqs[i]->async.priv = state; - - state->sent += to_write; - state->pending += 1; + if (state->eof) { + state->num_reqs = i+1; + break; + } } - if (i == 0) { - if (!async_post_ntstatus(result, ev, NT_STATUS_OK)) { + if (state->pending == 0) { + if (!async_post_ntstatus(req, ev, NT_STATUS_OK)) { goto failed; } - return result; + return req; } - return result; + return req; failed: - TALLOC_FREE(result); + TALLOC_FREE(req); return NULL; } -static void cli_push_written(struct async_req *req) +static void cli_push_written(struct async_req *subreq) { + struct cli_push_write_state *substate = talloc_get_type_abort( + subreq->async.priv, struct cli_push_write_state); + struct async_req *req = substate->req; struct cli_push_state *state = talloc_get_type_abort( - req->async.priv, struct cli_push_state); + req->private_data, struct cli_push_state); NTSTATUS status; - int i; - uint8_t *buf; - size_t to_write; - - for (i=0; inum_reqs; i++) { - if (state->reqs[i] == req) { - break; - } - } - - if (i == state->num_reqs) { - async_req_nterror(state->req, NT_STATUS_INTERNAL_ERROR); - return; - } - - status = cli_writeall_recv(req); - TALLOC_FREE(state->reqs[i]); - req = NULL; - if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(state->req, status); - return; - } + uint32_t idx = substate->idx; + state->reqs[idx] = NULL; state->pending -= 1; - if (state->pending == 0) { - async_req_done(state->req); - return; - } - if (state->eof) { + status = cli_writeall_recv(subreq); + TALLOC_FREE(subreq); + TALLOC_FREE(substate); + if (!NT_STATUS_IS_OK(status)) { + async_req_nterror(req, status); return; } - buf = state->buf + i * state->chunk_size; - - to_write = state->source(buf, state->chunk_size, state->priv); - if (to_write == 0) { - state->eof = true; - return; + if (!state->eof) { + if (!cli_push_write_setup(req, state, idx)) { + async_req_nomem(NULL, req); + return; + } } - state->reqs[i] = cli_writeall_send( - state->reqs, state->ev, state->cli, state->fnum, - state->mode, buf, state->start_offset + state->sent, to_write); - if (state->reqs[i] == NULL) { - async_req_nterror(state->req, NT_STATUS_NO_MEMORY); + if (state->pending == 0) { + async_req_done(req); return; } - - state->reqs[i]->async.fn = cli_push_written; - state->reqs[i]->async.priv = state; - - state->sent += to_write; - state->pending += 1; } NTSTATUS cli_push_recv(struct async_req *req) -- cgit From c2993f74af4e17790f8afbf16ba1c6884afa4ad4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 10 Mar 2009 12:32:48 +0100 Subject: s3:libsmb: only treat a return 0 as end of file metze --- source3/libsmb/clireadwrite.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'source3/libsmb/clireadwrite.c') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 764ef631f2..f2f447b4c9 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -971,10 +971,8 @@ static bool cli_push_write_setup(struct async_req *req, substate->size = state->source(substate->buf, state->chunk_size, state->priv); - if (substate->size < state->chunk_size) { - state->eof = true; - } if (substate->size == 0) { + state->eof = true; /* nothing to send */ talloc_free(substate); return true; @@ -1051,7 +1049,6 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, } if (state->eof) { - state->num_reqs = i+1; break; } } -- cgit From 9579a6f193f570e4ce2af80f4aac7c2f25ae5b22 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 10 Mar 2009 12:34:20 +0100 Subject: s3:libsmb: add an option to cli_push to let the caller provide the buffers metze --- source3/libsmb/clireadwrite.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'source3/libsmb/clireadwrite.c') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index f2f447b4c9..7e7cf0d682 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -930,8 +930,11 @@ struct cli_push_state { uint16_t mode; off_t start_offset; size_t window_size; + bool caller_buffers; - size_t (*source)(uint8_t *buf, size_t n, void *priv); + size_t (*source)(uint8_t *inbuf, size_t n, + const uint8_t **outbuf, + void *priv); void *priv; bool eof; @@ -963,13 +966,21 @@ static bool cli_push_write_setup(struct async_req *req, substate->req = req; substate->idx = idx; substate->ofs = state->next_offset; - substate->buf = talloc_array(substate, uint8_t, state->chunk_size); - if (!substate->buf) { - talloc_free(substate); - return false; + if (state->caller_buffers) { + substate->buf = NULL; + } else { + substate->buf = talloc_array(substate, uint8_t, + state->chunk_size); + if (!substate->buf) { + talloc_free(substate); + return false; + } } + + /* source function can overwrite substate->buf... */ substate->size = state->source(substate->buf, state->chunk_size, + (const uint8_t **)&substate->buf, state->priv); if (substate->size == 0) { state->eof = true; @@ -1002,7 +1013,9 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, uint16_t fnum, uint16_t mode, off_t start_offset, size_t window_size, - size_t (*source)(uint8_t *buf, size_t n, + bool caller_buffers, + size_t (*source)(uint8_t *inbuf, size_t n, + const uint8_t **outbuf, void *priv), void *priv) { @@ -1019,6 +1032,7 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, state->fnum = fnum; state->start_offset = start_offset; state->mode = mode; + state->caller_buffers = caller_buffers; state->source = source; state->priv = priv; state->eof = false; @@ -1108,7 +1122,10 @@ NTSTATUS cli_push_recv(struct async_req *req) NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, off_t start_offset, size_t window_size, - size_t (*source)(uint8_t *buf, size_t n, void *priv), + bool caller_buffers, + size_t (*source)(uint8_t *inbuf, size_t n, + const uint8_t **outbuf, + void *priv), void *priv) { TALLOC_CTX *frame = talloc_stackframe(); @@ -1129,7 +1146,7 @@ NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, } req = cli_push_send(frame, ev, cli, fnum, mode, start_offset, - window_size, source, priv); + window_size, caller_buffers, source, priv); if (req == NULL) { goto nomem; } -- cgit From 2fdbafbf5475e8936fb5bc3e3bafc7ee19a9b705 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 12 Mar 2009 09:02:02 +0100 Subject: Revert "s3:libsmb: add an option to cli_push to let the caller provide the buffers" This reverts commit 9579a6f193f570e4ce2af80f4aac7c2f25ae5b22. It's confusing to have a boolean to alter the behavior of cli_push and as the new feature isn't used yet I revert it. We can readd a extra function later. metze --- source3/libsmb/clireadwrite.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) (limited to 'source3/libsmb/clireadwrite.c') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 7e7cf0d682..f2f447b4c9 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -930,11 +930,8 @@ struct cli_push_state { uint16_t mode; off_t start_offset; size_t window_size; - bool caller_buffers; - size_t (*source)(uint8_t *inbuf, size_t n, - const uint8_t **outbuf, - void *priv); + size_t (*source)(uint8_t *buf, size_t n, void *priv); void *priv; bool eof; @@ -966,21 +963,13 @@ static bool cli_push_write_setup(struct async_req *req, substate->req = req; substate->idx = idx; substate->ofs = state->next_offset; - if (state->caller_buffers) { - substate->buf = NULL; - } else { - substate->buf = talloc_array(substate, uint8_t, - state->chunk_size); - if (!substate->buf) { - talloc_free(substate); - return false; - } + substate->buf = talloc_array(substate, uint8_t, state->chunk_size); + if (!substate->buf) { + talloc_free(substate); + return false; } - - /* source function can overwrite substate->buf... */ substate->size = state->source(substate->buf, state->chunk_size, - (const uint8_t **)&substate->buf, state->priv); if (substate->size == 0) { state->eof = true; @@ -1013,9 +1002,7 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, uint16_t fnum, uint16_t mode, off_t start_offset, size_t window_size, - bool caller_buffers, - size_t (*source)(uint8_t *inbuf, size_t n, - const uint8_t **outbuf, + size_t (*source)(uint8_t *buf, size_t n, void *priv), void *priv) { @@ -1032,7 +1019,6 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, state->fnum = fnum; state->start_offset = start_offset; state->mode = mode; - state->caller_buffers = caller_buffers; state->source = source; state->priv = priv; state->eof = false; @@ -1122,10 +1108,7 @@ NTSTATUS cli_push_recv(struct async_req *req) NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, off_t start_offset, size_t window_size, - bool caller_buffers, - size_t (*source)(uint8_t *inbuf, size_t n, - const uint8_t **outbuf, - void *priv), + size_t (*source)(uint8_t *buf, size_t n, void *priv), void *priv) { TALLOC_CTX *frame = talloc_stackframe(); @@ -1146,7 +1129,7 @@ NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, } req = cli_push_send(frame, ev, cli, fnum, mode, start_offset, - window_size, caller_buffers, source, priv); + window_size, source, priv); if (req == NULL) { goto nomem; } -- cgit