diff options
author | Andrew Bartlett <abartlet@samba.org> | 2009-03-11 07:58:42 +1100 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2009-03-11 07:58:42 +1100 |
commit | 3d0a727f575942b767e396b694f6529259528a17 (patch) | |
tree | 8ea6acdfe1b043abe06a0f3d78dcbc1b55d6f146 /source3 | |
parent | c218d3e1173355acf025471a10b4b6425b9c086b (diff) | |
parent | 3d280639c4652d6cd35577e333bcd46c2517754c (diff) | |
download | samba-3d0a727f575942b767e396b694f6529259528a17.tar.gz samba-3d0a727f575942b767e396b694f6529259528a17.tar.bz2 samba-3d0a727f575942b767e396b694f6529259528a17.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba into wspp-schema
Diffstat (limited to 'source3')
-rw-r--r-- | source3/Makefile.in | 5 | ||||
-rw-r--r-- | source3/client/client.c | 10 | ||||
-rw-r--r-- | source3/configure.in | 3 | ||||
-rw-r--r-- | source3/include/proto.h | 9 | ||||
-rw-r--r-- | source3/lib/messages.c | 18 | ||||
-rw-r--r-- | source3/libsmb/clireadwrite.c | 224 | ||||
-rw-r--r-- | source3/modules/vfs_preopen.c | 456 | ||||
-rw-r--r-- | source3/torture/torture.c | 8 |
8 files changed, 622 insertions, 111 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 6aabcf0c8d..76fd91a31e 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -667,6 +667,7 @@ VFS_READAHEAD_OBJ = modules/vfs_readahead.o VFS_TSMSM_OBJ = modules/vfs_tsmsm.o VFS_FILEID_OBJ = modules/vfs_fileid.o VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o +VFS_PREOPEN_OBJ = modules/vfs_preopen.o VFS_SYNCOPS_OBJ = modules/vfs_syncops.o VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o @@ -2567,6 +2568,10 @@ bin/aio_fork.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_AIO_FORK_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_AIO_FORK_OBJ) +bin/preopen.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_PREOPEN_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_PREOPEN_OBJ) + bin/acl_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ACL_XATTR_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_ACL_XATTR_OBJ) diff --git a/source3/client/client.c b/source3/client/client.c index aaa9e35d96..67a2458a94 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -220,7 +220,9 @@ struct push_state { SMB_OFF_T nread; }; -static size_t push_source(uint8_t *buf, size_t n, void *priv) +static size_t push_source(uint8_t *inbuf, size_t n, + const uint8_t **outbuf, + void *priv) { struct push_state *state = (struct push_state *)priv; int result; @@ -229,7 +231,7 @@ static size_t push_source(uint8_t *buf, size_t n, void *priv) return 0; } - result = readfile(buf, n, state->f); + result = readfile(inbuf, n, state->f); state->nread += result; return result; } @@ -1681,8 +1683,8 @@ static int do_put(const char *rname, const char *lname, bool reput) state.f = f; state.nread = 0; - status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source, - &state); + status = cli_push(targetcli, fnum, 0, 0, io_bufsize, + false, push_source, &state); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status)); } diff --git a/source3/configure.in b/source3/configure.in index e48ff34554..2af1545d58 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -417,7 +417,7 @@ dnl These have to be built static: default_static_modules="pdb_smbpasswd pdb_tdbsam pdb_wbc_sam rpc_lsarpc rpc_samr rpc_winreg rpc_initshutdown rpc_dssetup rpc_wkssvc rpc_svcctl rpc_ntsvcs rpc_netlogon rpc_netdfs rpc_srvsvc rpc_spoolss2 rpc_eventlog auth_sam auth_unix auth_winbind auth_wbc auth_server auth_domain auth_builtin auth_netlogond vfs_default nss_info_template" dnl These are preferably build shared, and static if dlopen() is not available -default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer" +default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer vfs_preopen" if test "x$developer" = xyes; then default_static_modules="$default_static_modules rpc_rpcecho" @@ -6185,6 +6185,7 @@ SMB_MODULE(vfs_readahead, \$(VFS_READAHEAD_OBJ), "bin/readahead.$SHLIBEXT", VFS) SMB_MODULE(vfs_tsmsm, \$(VFS_TSMSM_OBJ), "bin/tsmsm.$SHLIBEXT", VFS) SMB_MODULE(vfs_fileid, \$(VFS_FILEID_OBJ), "bin/fileid.$SHLIBEXT", VFS) SMB_MODULE(vfs_aio_fork, \$(VFS_AIO_FORK_OBJ), "bin/aio_fork.$SHLIBEXT", VFS) +SMB_MODULE(vfs_preopen, \$(VFS_PREOPEN_OBJ), "bin/preopen.$SHLIBEXT", VFS) SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS) SMB_MODULE(vfs_zfsacl, \$(VFS_ZFSACL_OBJ), "bin/zfsacl.$SHLIBEXT", VFS) SMB_MODULE(vfs_notify_fam, \$(VFS_NOTIFY_FAM_OBJ), "bin/notify_fam.$SHLIBEXT", VFS) diff --git a/source3/include/proto.h b/source3/include/proto.h index a1cafb6837..794a006a68 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2790,13 +2790,18 @@ 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); 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); /* The following definitions come from libsmb/clisecdesc.c */ diff --git a/source3/lib/messages.c b/source3/lib/messages.c index e4b20c7493..5e11dd4e25 100644 --- a/source3/lib/messages.c +++ b/source3/lib/messages.c @@ -286,7 +286,15 @@ NTSTATUS messaging_register(struct messaging_context *msg_ctx, */ for (cb = msg_ctx->callbacks; cb != NULL; cb = cb->next) { - if (cb->msg_type == msg_type) { + /* we allow a second registration of the same message + type if it has a different private pointer. This is + needed in, for example, the internal notify code, + which creates a new notify context for each tree + connect, and expects to receive messages to each of + them. */ + if (cb->msg_type == msg_type && private_data == cb->private_data) { + DEBUG(5,("Overriding messaging pointer for type %u - private_data=%p\n", + (unsigned)msg_type, private_data)); cb->fn = fn; cb->private_data = private_data; return NT_STATUS_OK; @@ -317,6 +325,8 @@ void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type, next = cb->next; if ((cb->msg_type == msg_type) && (cb->private_data == private_data)) { + DEBUG(5,("Deregistering messaging pointer for type %u - private_data=%p\n", + (unsigned)msg_type, private_data)); DLIST_REMOVE(ctx->callbacks, cb); TALLOC_FREE(cb); } @@ -362,7 +372,11 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx, if (cb->msg_type == rec->msg_type) { cb->fn(msg_ctx, cb->private_data, rec->msg_type, rec->src, &rec->buf); - return; + /* we continue looking for matching messages + after finding one. This matters for + subsystems like the internal notify code + which register more than one handler for + the same message type */ } } return; diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 9d17ff86a5..7e7cf0d682 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -915,181 +915,204 @@ 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; 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; - 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; + 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; + /* 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, 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) { - 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; state->start_offset = start_offset; state->mode = mode; + state->caller_buffers = caller_buffers; 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; i<state->num_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) { + 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; i<state->num_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) @@ -1099,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(); @@ -1120,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; } diff --git a/source3/modules/vfs_preopen.c b/source3/modules/vfs_preopen.c new file mode 100644 index 0000000000..25b9e7f3e4 --- /dev/null +++ b/source3/modules/vfs_preopen.c @@ -0,0 +1,456 @@ +/* + * Force a readahead of files by opening them and reading the first bytes + * + * Copyright (C) Volker Lendecke 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" + +struct preopen_state; + +struct preopen_helper { + struct preopen_state *state; + struct fd_event *fde; + pid_t pid; + int fd; + bool busy; +}; + +struct preopen_state { + int num_helpers; + struct preopen_helper *helpers; + + size_t to_read; /* How many bytes to read in children? */ + int queue_max; + + char *template_fname; /* Filename to be sent to children */ + size_t number_start; /* start offset into "template_fname" */ + int num_digits; /* How many digits is the number long? */ + + int fnum_sent; /* last fname sent to children */ + + int fnum_queue_end; /* last fname to be sent, based on + * last open call + preopen:queuelen + */ + + name_compare_entry *preopen_names; +}; + +static void preopen_helper_destroy(struct preopen_helper *c) +{ + int status; + close(c->fd); + c->fd = -1; + kill(c->pid, SIGKILL); + waitpid(c->pid, &status, 0); + c->busy = true; +} + +static void preopen_queue_run(struct preopen_state *state) +{ + char *pdelimiter; + char delimiter; + + pdelimiter = state->template_fname + state->number_start + + state->num_digits; + delimiter = *pdelimiter; + + while (state->fnum_sent < state->fnum_queue_end) { + + ssize_t written; + size_t to_write; + int helper; + + for (helper=0; helper<state->num_helpers; helper++) { + if (state->helpers[helper].busy) { + continue; + } + break; + } + if (helper == state->num_helpers) { + /* everyone is busy */ + return; + } + + snprintf(state->template_fname + state->number_start, + state->num_digits + 1, + "%.*lu", state->num_digits, + (long unsigned int)(state->fnum_sent + 1)); + *pdelimiter = delimiter; + + to_write = talloc_get_size(state->template_fname); + written = write_data(state->helpers[helper].fd, + state->template_fname, to_write); + state->helpers[helper].busy = true; + + if (written != to_write) { + preopen_helper_destroy(&state->helpers[helper]); + } + state->fnum_sent += 1; + } +} + +static void preopen_helper_readable(struct event_context *ev, + struct fd_event *fde, uint16_t flags, + void *priv) +{ + struct preopen_helper *helper = (struct preopen_helper *)priv; + struct preopen_state *state = helper->state; + ssize_t nread; + char c; + + if ((flags & EVENT_FD_READ) == 0) { + return; + } + + nread = read(helper->fd, &c, 1); + if (nread <= 0) { + preopen_helper_destroy(helper); + return; + } + + helper->busy = false; + + preopen_queue_run(state); +} + +static int preopen_helpers_destructor(struct preopen_state *c) +{ + int i; + + for (i=0; i<c->num_helpers; i++) { + if (c->helpers[i].fd == -1) { + continue; + } + preopen_helper_destroy(&c->helpers[i]); + } + + return 0; +} + +static bool preopen_helper_open_one(int sock_fd, char **pnamebuf, + size_t to_read, void *filebuf) +{ + char *namebuf = *pnamebuf; + ssize_t nwritten, nread; + char c = 0; + int fd; + + nread = 0; + + while ((nread == 0) || (namebuf[nread-1] != '\0')) { + ssize_t thistime; + + thistime = read(sock_fd, namebuf + nread, + talloc_get_size(namebuf) - nread); + if (thistime <= 0) { + return false; + } + + nread += thistime; + + if (nread == talloc_get_size(namebuf)) { + namebuf = TALLOC_REALLOC_ARRAY( + NULL, namebuf, char, + talloc_get_size(namebuf) * 2); + if (namebuf == NULL) { + return false; + } + *pnamebuf = namebuf; + } + } + + fd = open(namebuf, O_RDONLY); + if (fd == -1) { + goto done; + } + nread = read(fd, filebuf, to_read); + close(fd); + + done: + nwritten = write(sock_fd, &c, 1); + return true; +} + +static bool preopen_helper(int fd, size_t to_read) +{ + char *namebuf; + void *readbuf; + + namebuf = TALLOC_ARRAY(NULL, char, 1024); + if (namebuf == NULL) { + return false; + } + + readbuf = talloc_size(NULL, to_read); + if (readbuf == NULL) { + TALLOC_FREE(namebuf); + return false; + } + + while (preopen_helper_open_one(fd, &namebuf, to_read, readbuf)) { + ; + } + + TALLOC_FREE(readbuf); + TALLOC_FREE(namebuf); + return false; +} + +static NTSTATUS preopen_init_helper(struct preopen_helper *h) +{ + int fdpair[2]; + NTSTATUS status; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) { + status = map_nt_error_from_unix(errno); + DEBUG(10, ("socketpair() failed: %s\n", strerror(errno))); + return status; + } + + h->pid = sys_fork(); + + if (h->pid == -1) { + return map_nt_error_from_unix(errno); + } + + if (h->pid == 0) { + close(fdpair[0]); + preopen_helper(fdpair[1], h->state->to_read); + exit(0); + } + close(fdpair[1]); + h->fd = fdpair[0]; + h->fde = event_add_fd(smbd_event_context(), h->state, h->fd, + EVENT_FD_READ, preopen_helper_readable, h); + if (h->fde == NULL) { + close(h->fd); + h->fd = -1; + return NT_STATUS_NO_MEMORY; + } + h->busy = false; + return NT_STATUS_OK; +} + +static NTSTATUS preopen_init_helpers(TALLOC_CTX *mem_ctx, size_t to_read, + int num_helpers, int queue_max, + struct preopen_state **presult) +{ + struct preopen_state *result; + int i; + + result = talloc(mem_ctx, struct preopen_state); + if (result == NULL) { + return NT_STATUS_NO_MEMORY; + } + + result->num_helpers = num_helpers; + result->helpers = TALLOC_ARRAY(result, struct preopen_helper, + num_helpers); + if (result->helpers == NULL) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + result->to_read = to_read; + result->queue_max = queue_max; + result->template_fname = NULL; + result->fnum_sent = 0; + + for (i=0; i<num_helpers; i++) { + result->helpers[i].state = result; + result->helpers[i].fd = -1; + } + + talloc_set_destructor(result, preopen_helpers_destructor); + + for (i=0; i<num_helpers; i++) { + preopen_init_helper(&result->helpers[i]); + } + + *presult = result; + return NT_STATUS_OK; +} + +static void preopen_free_helpers(void **ptr) +{ + TALLOC_FREE(*ptr); +} + +static struct preopen_state *preopen_state_get(vfs_handle_struct *handle) +{ + struct preopen_state *state; + NTSTATUS status; + const char *namelist; + + if (SMB_VFS_HANDLE_TEST_DATA(handle)) { + SMB_VFS_HANDLE_GET_DATA(handle, state, struct preopen_state, + return NULL); + return state; + } + + namelist = lp_parm_const_string(SNUM(handle->conn), "preopen", "names", + NULL); + + if (namelist == NULL) { + return NULL; + } + + status = preopen_init_helpers( + NULL, + lp_parm_int(SNUM(handle->conn), "preopen", "num_bytes", 1), + lp_parm_int(SNUM(handle->conn), "preopen", "helpers", 1), + lp_parm_int(SNUM(handle->conn), "preopen", "queuelen", 10), + &state); + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + + set_namearray(&state->preopen_names, (char *)namelist); + + if (state->preopen_names == NULL) { + TALLOC_FREE(state); + return NULL; + } + + if (!SMB_VFS_HANDLE_TEST_DATA(handle)) { + SMB_VFS_HANDLE_SET_DATA(handle, state, preopen_free_helpers, + struct preopen_state, return NULL); + } + + return state; +} + +static bool preopen_parse_fname(const char *fname, unsigned long *pnum, + size_t *pstart_idx, int *pnum_digits) +{ + const char *p, *q; + unsigned long num; + + p = strrchr_m(fname, '/'); + if (p == NULL) { + p = fname; + } + + p += 1; + while (p[0] != '\0') { + if (isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2])) { + break; + } + p += 1; + } + if (*p == '\0') { + /* no digits around */ + return false; + } + + num = strtoul(p, (char **)&q, 10); + + if (num+1 < num) { + /* overflow */ + return false; + } + + *pnum = num; + *pstart_idx = (p - fname); + *pnum_digits = (q - p); + return true; +} + +static int preopen_open(vfs_handle_struct *handle, const char *fname, + files_struct *fsp, int flags, mode_t mode) +{ + struct preopen_state *state; + int res; + unsigned long num; + + DEBUG(10, ("preopen_open called on %s\n", fname)); + + state = preopen_state_get(handle); + if (state == NULL) { + return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); + } + + res = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); + if (res == -1) { + return -1; + } + + if (flags != O_RDONLY) { + return res; + } + + if (!is_in_path(fname, state->preopen_names, true)) { + DEBUG(10, ("%s does not match the preopen:names list\n", + fname)); + return res; + } + + TALLOC_FREE(state->template_fname); + state->template_fname = talloc_asprintf( + state, "%s/%s", fsp->conn->connectpath, fname); + + if (state->template_fname == NULL) { + return res; + } + + if (!preopen_parse_fname(state->template_fname, &num, + &state->number_start, &state->num_digits)) { + TALLOC_FREE(state->template_fname); + return res; + } + + if (num > state->fnum_sent) { + /* + * Helpers were too slow, there's no point in reading + * files in helpers that we already read in the + * parent. + */ + state->fnum_sent = num; + } + + if ((state->fnum_queue_end != 0) /* Something was started earlier */ + && (num < (state->fnum_queue_end - state->queue_max))) { + /* + * "num" is before the queue we announced. This means + * a new run is started. + */ + state->fnum_sent = num; + } + + state->fnum_queue_end = num + state->queue_max; + + preopen_queue_run(state); + + return res; +} + +/* VFS operations structure */ + +static vfs_op_tuple preopen_ops[] = { + {SMB_VFS_OP(preopen_open), SMB_VFS_OP_OPEN, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_preopen_init(void); +NTSTATUS vfs_preopen_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, + "preopen", preopen_ops); +} diff --git a/source3/torture/torture.c b/source3/torture/torture.c index db89b05603..a563557d5f 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -5004,7 +5004,9 @@ static bool run_chain1(int dummy) return True; } -static size_t null_source(uint8_t *buf, size_t n, void *priv) +static size_t null_source(uint8_t *inbuf, size_t n, + const uint8_t *outbuf, + void *priv) { size_t *to_pull = (size_t *)priv; size_t thistime = *to_pull; @@ -5014,7 +5016,7 @@ static size_t null_source(uint8_t *buf, size_t n, void *priv) return 0; } - memset(buf, 0, thistime); + memset(inbuf, 0, thistime); *to_pull -= thistime; return thistime; } @@ -5057,7 +5059,7 @@ static bool run_windows_write(int dummy) } status = cli_push(cli1, fnum, 0, i * torture_blocksize, torture_blocksize, - null_source, &to_pull); + false, null_source, &to_pull); if (!NT_STATUS_IS_OK(status)) { printf("cli_push returned: %s\n", nt_errstr(status)); goto fail; |