diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2008-05-23 15:24:40 +0200 |
---|---|---|
committer | Jelmer Vernooij <jelmer@samba.org> | 2008-05-23 15:24:40 +0200 |
commit | 7fb26774021986a08d03db968a7826ee64ea7410 (patch) | |
tree | 272d8e4f7671b48c95c817724b41d9c27de1e282 /source4/torture/raw | |
parent | fd01b27edd5a83306f4ce567e31d43641dd003b8 (diff) | |
parent | 1186579f94d81bc633b8f20e8ad8673313c8c39b (diff) | |
download | samba-7fb26774021986a08d03db968a7826ee64ea7410.tar.gz samba-7fb26774021986a08d03db968a7826ee64ea7410.tar.bz2 samba-7fb26774021986a08d03db968a7826ee64ea7410.zip |
Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into registry
(This used to be commit e8d96b61db1cddc2d8dca45e6e9b53d5c31ee5d4)
Diffstat (limited to 'source4/torture/raw')
-rw-r--r-- | source4/torture/raw/composite.c | 4 | ||||
-rw-r--r-- | source4/torture/raw/lockbench.c | 9 | ||||
-rw-r--r-- | source4/torture/raw/lookuprate.c | 320 | ||||
-rw-r--r-- | source4/torture/raw/offline.c | 13 | ||||
-rw-r--r-- | source4/torture/raw/open.c | 10 | ||||
-rw-r--r-- | source4/torture/raw/openbench.c | 9 | ||||
-rw-r--r-- | source4/torture/raw/oplock.c | 3 | ||||
-rw-r--r-- | source4/torture/raw/raw.c | 8 | ||||
-rw-r--r-- | source4/torture/raw/samba3hide.c | 2 | ||||
-rw-r--r-- | source4/torture/raw/samba3misc.c | 2 | ||||
-rw-r--r-- | source4/torture/raw/streams.c | 95 | ||||
-rw-r--r-- | source4/torture/raw/tconrate.c | 201 |
12 files changed, 635 insertions, 41 deletions
diff --git a/source4/torture/raw/composite.c b/source4/torture/raw/composite.c index 1f31fbc515..d73ac1327e 100644 --- a/source4/torture/raw/composite.c +++ b/source4/torture/raw/composite.c @@ -296,7 +296,7 @@ static bool test_appendacl(struct smbcli_state *cli, struct torture_context *tct c[i]->async.private_data = count; } - event_ctx = talloc_reference(tctx, cli->tree->session->transport->socket->event.ctx); + event_ctx = tctx->ev; printf("waiting for completion\n"); while (*count != num_ops) { event_loop_once(event_ctx); @@ -354,7 +354,7 @@ static bool test_fsinfo(struct smbcli_state *cli, struct torture_context *tctx) printf("testing parallel queryfsinfo [Object ID] with %d ops\n", torture_numops); - event_ctx = talloc_reference(tctx, cli->tree->session->transport->socket->event.ctx); + event_ctx = tctx->ev; c = talloc_array(tctx, struct composite_context *, torture_numops); for (i=0; i<torture_numops; i++) { diff --git a/source4/torture/raw/lockbench.c b/source4/torture/raw/lockbench.c index 86030c538a..21541d003b 100644 --- a/source4/torture/raw/lockbench.c +++ b/source4/torture/raw/lockbench.c @@ -316,7 +316,6 @@ bool torture_bench_lock(struct torture_context *torture) int i; int timelimit = torture_setting_int(torture, "timelimit", 10); struct timeval tv; - struct event_context *ev = event_context_find(mem_ctx); struct benchlock_state *state; int total = 0, minops=0; struct smbcli_state *cli; @@ -333,8 +332,8 @@ bool torture_bench_lock(struct torture_context *torture) state[i].tctx = torture; state[i].mem_ctx = talloc_new(state); state[i].client_num = i; - state[i].ev = ev; - if (!torture_open_connection_ev(&cli, i, torture, ev)) { + state[i].ev = torture->ev; + if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) { return false; } talloc_steal(mem_ctx, state); @@ -375,12 +374,12 @@ bool torture_bench_lock(struct torture_context *torture) tv = timeval_current(); if (progress) { - event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state); + event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state); } printf("Running for %d seconds\n", timelimit); while (timeval_elapsed(&tv) < timelimit) { - event_loop_once(ev); + event_loop_once(torture->ev); if (lock_failed) { DEBUG(0,("locking failed\n")); diff --git a/source4/torture/raw/lookuprate.c b/source4/torture/raw/lookuprate.c new file mode 100644 index 0000000000..782cb1b31b --- /dev/null +++ b/source4/torture/raw/lookuprate.c @@ -0,0 +1,320 @@ +/* + File lookup rate test. + + Copyright (C) James Peach 2006 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "param/param.h" +#include "system/filesys.h" +#include "torture/smbtorture.h" +#include "torture/basic/proto.h" +#include "libcli/libcli.h" +#include "torture/util.h" +#include "lib/cmdline/popt_common.h" +#include "auth/credentials/credentials.h" + +#define BASEDIR "\\lookuprate" +#define MISSINGNAME BASEDIR "\\foo" + +#define FUZZ_PERCENT 10 + +#define usec_to_sec(s) ((s) / 1000000) +#define sec_to_usec(s) ((s) * 1000000) + +struct rate_record +{ + unsigned dirent_count; + unsigned querypath_persec; + unsigned findfirst_persec; +}; + +static struct rate_record records[] = +{ + { 0, 0, 0 }, /* Base (optimal) lookup rate. */ + { 100, 0, 0}, + { 1000, 0, 0}, + { 10000, 0, 0}, + { 100000, 0, 0} +}; + +typedef NTSTATUS lookup_function(struct smbcli_tree *tree, const char * path); + +/* Test whether rhs is within fuzz% of lhs. */ +static bool fuzzily_equal(unsigned lhs, unsigned rhs, int percent) +{ + double fuzz = (double)lhs * (double)percent/100.0; + + if (((double)rhs >= ((double)lhs - fuzz)) && + ((double)rhs <= ((double)lhs + fuzz))) { + return true; + } + + return false; + +} + +static NTSTATUS fill_directory(struct smbcli_tree *tree, + const char * path, unsigned count) +{ + NTSTATUS status; + char *fname = NULL; + unsigned i; + unsigned current; + + struct timeval start; + struct timeval now; + + status = smbcli_mkdir(tree, path); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + printf("filling directory %s with %u files... ", path, count); + fflush(stdout); + + current = random(); + start = timeval_current(); + + for (i = 0; i < count; ++i) { + int fnum; + + ++current; + fname = talloc_asprintf(NULL, "%s\\fill%u", + path, current); + + fnum = smbcli_open(tree, fname, O_RDONLY|O_CREAT, + OPENX_MODE_DENY_NONE); + if (fnum < 0) { + talloc_free(fname); + return smbcli_nt_error(tree); + } + + smbcli_close(tree, fnum); + talloc_free(fname); + } + + if (count) { + double rate; + now = timeval_current(); + rate = (double)count / usec_to_sec((double)usec_time_diff(&now, &start)); + printf("%u/sec\n", (unsigned)rate); + } else { + printf("done\n"); + } + + return NT_STATUS_OK; +} + +static NTSTATUS squash_lookup_error(NTSTATUS status) +{ + if (NT_STATUS_IS_OK(status)) { + return NT_STATUS_OK; + } + + /* We don't care if the file isn't there. */ + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) { + return NT_STATUS_OK; + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + return NT_STATUS_OK; + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_FILE)) { + return NT_STATUS_OK; + } + + return status; +} + +/* Look up a pathname using TRANS2_QUERY_PATH_INFORMATION. */ +static NTSTATUS querypath_lookup(struct smbcli_tree *tree, const char * path) +{ + NTSTATUS status; + time_t ftimes[3]; + size_t fsize; + uint16_t fmode; + + status = smbcli_qpathinfo(tree, path, &ftimes[0], &ftimes[1], &ftimes[2], + &fsize, &fmode); + + return squash_lookup_error(status); +} + +/* Look up a pathname using TRANS2_FIND_FIRST2. */ +static NTSTATUS findfirst_lookup(struct smbcli_tree *tree, const char * path) +{ + NTSTATUS status = NT_STATUS_OK; + + if (smbcli_list(tree, path, 0, NULL, NULL) < 0) { + status = smbcli_nt_error(tree); + } + + return squash_lookup_error(status); +} + +static NTSTATUS lookup_rate_convert(struct smbcli_tree *tree, + lookup_function lookup, const char * path, unsigned * rate) +{ + NTSTATUS status; + + struct timeval start; + struct timeval now; + unsigned count = 0; + int64_t elapsed = 0; + +#define LOOKUP_PERIOD_SEC (2) + + start = timeval_current(); + while (elapsed < sec_to_usec(LOOKUP_PERIOD_SEC)) { + + status = lookup(tree, path); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + ++count; + now = timeval_current(); + elapsed = usec_time_diff(&now, &start); + } + +#undef LOOKUP_PERIOD_SEC + + *rate = (unsigned)((double)count / (double)usec_to_sec(elapsed)); + return NT_STATUS_OK; +} + +static bool remove_working_directory(struct smbcli_tree *tree, + const char * path) +{ + int tries; + + /* Using smbcli_deltree to delete a very large number of files + * doesn't work against all servers. Work around this by + * retrying. + */ + for (tries = 0; tries < 5; ) { + int ret; + + ret = smbcli_deltree(tree, BASEDIR); + if (ret == -1) { + tries++; + printf("(%s) failed to deltree %s: %s\n", + __location__, BASEDIR, + smbcli_errstr(tree)); + continue; + } + + return true; + } + + return false; + +} + +/* Verify that looking up a file name takes constant time. + * + * This test samples the lookup rate for a non-existant filename in a + * directory, while varying the number of files in the directory. The + * lookup rate should continue to approximate the lookup rate for the + * empty directory case. + */ +bool torture_bench_lookup(struct torture_context *torture) +{ + NTSTATUS status; + bool result = false; + + int i, tries; + struct smbcli_state *cli = NULL; + + if (!torture_open_connection(&cli, torture, 0)) { + goto done; + } + + remove_working_directory(cli->tree, BASEDIR); + + for (i = 0; i < ARRAY_SIZE(records); ++i) { + printf("testing lookup rate with %u directory entries\n", + records[i].dirent_count); + + status = fill_directory(cli->tree, BASEDIR, + records[i].dirent_count); + if (!NT_STATUS_IS_OK(status)) { + printf("failed to fill directory: %s\n", nt_errstr(status)); + goto done; + } + + status = lookup_rate_convert(cli->tree, querypath_lookup, + MISSINGNAME, &records[i].querypath_persec); + if (!NT_STATUS_IS_OK(status)) { + printf("querypathinfo of %s failed: %s\n", + MISSINGNAME, nt_errstr(status)); + goto done; + } + + status = lookup_rate_convert(cli->tree, findfirst_lookup, + MISSINGNAME, &records[i].findfirst_persec); + if (!NT_STATUS_IS_OK(status)) { + printf("findfirst of %s failed: %s\n", + MISSINGNAME, nt_errstr(status)); + goto done; + } + + printf("entries = %u, querypath = %u/sec, findfirst = %u/sec\n", + records[i].dirent_count, + records[i].querypath_persec, + records[i].findfirst_persec); + + if (!remove_working_directory(cli->tree, BASEDIR)) { + goto done; + } + } + + /* Ok. We have run all our tests. Walk through the records we + * accumulated and figure out whether the lookups took constant + * time of not. + */ + for (i = 0; i < ARRAY_SIZE(records); ++i) { + if (!fuzzily_equal(records[0].querypath_persec, + records[i].querypath_persec, + FUZZ_PERCENT)) { + printf("querypath rate for %d entries differed by " + "more than %d%% from base rate\n", + records[i].dirent_count, FUZZ_PERCENT); + result = false; + } + + if (!fuzzily_equal(records[0].findfirst_persec, + records[i].findfirst_persec, + FUZZ_PERCENT)) { + printf("findfirst rate for %d entries differed by " + "more than %d%% from base rate\n", + records[i].dirent_count, FUZZ_PERCENT); + result = false; + } + } + +done: + if (cli) { + remove_working_directory(cli->tree, BASEDIR); + talloc_free(cli); + } + + return result; +} + +/* vim: set sts=8 sw=8 : */ diff --git a/source4/torture/raw/offline.c b/source4/torture/raw/offline.c index 1340692faa..9c66c3be9c 100644 --- a/source4/torture/raw/offline.c +++ b/source4/torture/raw/offline.c @@ -389,7 +389,6 @@ bool torture_test_offline(struct torture_context *torture) int i; int timelimit = torture_setting_int(torture, "timelimit", 10); struct timeval tv; - struct event_context *ev = event_context_find(mem_ctx); struct offline_state *state; struct smbcli_state *cli; bool progress; @@ -404,8 +403,8 @@ bool torture_test_offline(struct torture_context *torture) for (i=0;i<nconnections;i++) { state[i].tctx = torture; state[i].mem_ctx = talloc_new(state); - state[i].ev = ev; - if (!torture_open_connection_ev(&cli, i, torture, ev)) { + state[i].ev = torture->ev; + if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) { return false; } state[i].tree = cli->tree; @@ -418,7 +417,7 @@ bool torture_test_offline(struct torture_context *torture) for (i=nconnections;i<numstates;i++) { state[i].tctx = torture; state[i].mem_ctx = talloc_new(state); - state[i].ev = ev; + state[i].ev = torture->ev; state[i].tree = state[i % nconnections].tree; state[i].client = i; } @@ -468,12 +467,12 @@ bool torture_test_offline(struct torture_context *torture) tv = timeval_current(); if (progress) { - event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state); + event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state); } printf("Running for %d seconds\n", timelimit); while (timeval_elapsed(&tv) < timelimit) { - event_loop_once(ev); + event_loop_once(torture->ev); if (test_failed) { DEBUG(0,("test failed\n")); @@ -487,7 +486,7 @@ bool torture_test_offline(struct torture_context *torture) while (state[i].loadfile || state[i].savefile || state[i].req) { - event_loop_once(ev); + event_loop_once(torture->ev); } } diff --git a/source4/torture/raw/open.c b/source4/torture/raw/open.c index d28a8bd14e..c6ba0d2571 100644 --- a/source4/torture/raw/open.c +++ b/source4/torture/raw/open.c @@ -1350,21 +1350,19 @@ static bool test_raw_open_multi(struct torture_context *tctx) const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); int i, num_files = 3; - struct event_context *ev; int num_ok = 0; int num_collision = 0; - ev = cli_credentials_get_event_context(cmdline_credentials); clients = talloc_array(mem_ctx, struct smbcli_state *, num_files); requests = talloc_array(mem_ctx, struct smbcli_request *, num_files); ios = talloc_array(mem_ctx, union smb_open, num_files); - if ((ev == NULL) || (clients == NULL) || (requests == NULL) || + if ((tctx->ev == NULL) || (clients == NULL) || (requests == NULL) || (ios == NULL)) { DEBUG(0, ("talloc failed\n")); return false; } - if (!torture_open_connection_share(mem_ctx, &cli, tctx, host, share, ev)) { + if (!torture_open_connection_share(mem_ctx, &cli, tctx, host, share, tctx->ev)) { return false; } @@ -1372,7 +1370,7 @@ static bool test_raw_open_multi(struct torture_context *tctx) for (i=0; i<num_files; i++) { if (!torture_open_connection_share(mem_ctx, &(clients[i]), - tctx, host, share, ev)) { + tctx, host, share, tctx->ev)) { DEBUG(0, ("Could not open %d'th connection\n", i)); return false; } @@ -1441,7 +1439,7 @@ static bool test_raw_open_multi(struct torture_context *tctx) break; } - if (event_loop_once(ev) != 0) { + if (event_loop_once(tctx->ev) != 0) { DEBUG(0, ("event_loop_once failed\n")); return false; } diff --git a/source4/torture/raw/openbench.c b/source4/torture/raw/openbench.c index a5b1434a47..26b862c33f 100644 --- a/source4/torture/raw/openbench.c +++ b/source4/torture/raw/openbench.c @@ -369,7 +369,6 @@ bool torture_bench_open(struct torture_context *torture) int i; int timelimit = torture_setting_int(torture, "timelimit", 10); struct timeval tv; - struct event_context *ev = event_context_find(mem_ctx); struct benchopen_state *state; int total = 0; int total_retries = 0; @@ -387,8 +386,8 @@ bool torture_bench_open(struct torture_context *torture) state[i].tctx = torture; state[i].mem_ctx = talloc_new(state); state[i].client_num = i; - state[i].ev = ev; - if (!torture_open_connection_ev(&state[i].cli, i, torture, ev)) { + state[i].ev = torture->ev; + if (!torture_open_connection_ev(&state[i].cli, i, torture, torture->ev)) { return false; } talloc_steal(mem_ctx, state); @@ -428,13 +427,13 @@ bool torture_bench_open(struct torture_context *torture) tv = timeval_current(); if (progress) { - report_te = event_add_timed(ev, state, timeval_current_ofs(1, 0), + report_te = event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state); } printf("Running for %d seconds\n", timelimit); while (timeval_elapsed(&tv) < timelimit) { - event_loop_once(ev); + event_loop_once(torture->ev); if (open_failed) { DEBUG(0,("open failed\n")); diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c index 1927a0f027..fd8d292980 100644 --- a/source4/torture/raw/oplock.c +++ b/source4/torture/raw/oplock.c @@ -2841,13 +2841,12 @@ bool torture_bench_oplock(struct torture_context *torture) int timelimit = torture_setting_int(torture, "timelimit", 10); union smb_open io; struct timeval tv; - struct event_context *ev = event_context_find(mem_ctx); cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs); torture_comment(torture, "Opening %d connections\n", torture_nprocs); for (i=0;i<torture_nprocs;i++) { - if (!torture_open_connection_ev(&cli[i], i, torture, ev)) { + if (!torture_open_connection_ev(&cli[i], i, torture, torture->ev)) { return false; } talloc_steal(mem_ctx, cli[i]); diff --git a/source4/torture/raw/raw.c b/source4/torture/raw/raw.c index bb3dde728f..0a7fc3ebfd 100644 --- a/source4/torture/raw/raw.c +++ b/source4/torture/raw/raw.c @@ -18,10 +18,10 @@ */ #include "includes.h" -#include "torture/torture.h" #include "libcli/raw/libcliraw.h" -#include "torture/raw/proto.h" #include "torture/util.h" +#include "torture/smbtorture.h" +#include "torture/raw/proto.h" NTSTATUS torture_raw_init(void) { @@ -33,6 +33,10 @@ NTSTATUS torture_raw_init(void) torture_suite_add_simple_test(suite, "PING-PONG", torture_ping_pong); torture_suite_add_simple_test(suite, "BENCH-LOCK", torture_bench_lock); torture_suite_add_simple_test(suite, "BENCH-OPEN", torture_bench_open); + torture_suite_add_simple_test(suite, "BENCH-LOOKUP", + torture_bench_lookup); + torture_suite_add_simple_test(suite, "BENCH-TCON", + torture_bench_treeconnect); torture_suite_add_simple_test(suite, "OFFLINE", torture_test_offline); torture_suite_add_1smb_test(suite, "QFSINFO", torture_raw_qfsinfo); torture_suite_add_1smb_test(suite, "QFILEINFO", torture_raw_qfileinfo); diff --git a/source4/torture/raw/samba3hide.c b/source4/torture/raw/samba3hide.c index 814b5f57f4..1f1501045c 100644 --- a/source4/torture/raw/samba3hide.c +++ b/source4/torture/raw/samba3hide.c @@ -136,7 +136,7 @@ bool torture_samba3_hide(struct torture_context *torture) if (!torture_open_connection_share( torture, &cli, torture, torture_setting_string(torture, "host", NULL), - torture_setting_string(torture, "share", NULL), NULL)) { + torture_setting_string(torture, "share", NULL), torture->ev)) { d_printf("torture_open_connection_share failed\n"); return false; } diff --git a/source4/torture/raw/samba3misc.c b/source4/torture/raw/samba3misc.c index 15a7f6c4a3..27b4d42dd8 100644 --- a/source4/torture/raw/samba3misc.c +++ b/source4/torture/raw/samba3misc.c @@ -56,7 +56,7 @@ bool torture_samba3_checkfsp(struct torture_context *torture) if (!torture_open_connection_share( torture, &cli, torture, torture_setting_string(torture, "host", NULL), - torture_setting_string(torture, "share", NULL), NULL)) { + torture_setting_string(torture, "share", NULL), torture->ev)) { d_printf("torture_open_connection_share failed\n"); ret = false; goto done; diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c index 1dab36c28b..8b2d327653 100644 --- a/source4/torture/raw/streams.c +++ b/source4/torture/raw/streams.c @@ -135,6 +135,11 @@ static bool check_stream_list(struct smbcli_state *cli, const char *fname, goto fail; } + if (num_exp == 0) { + ret = true; + goto fail; + } + exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp)); if (exp_sort == NULL) { @@ -170,7 +175,81 @@ static bool check_stream_list(struct smbcli_state *cli, const char *fname, } /* - test basic io on streams + test bahavior of streams on directories +*/ +static bool test_stream_dir(struct torture_context *tctx, + struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + union smb_open io; + const char *fname = BASEDIR "\\stream.txt"; + const char *sname1; + bool ret = true; + const char *basedir_data; + + basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", BASEDIR); + sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One"); + + printf("(%s) opening non-existant directory stream\n", __location__); + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; + io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = 0; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = sname1; + status = smb_raw_open(cli->tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY); + + printf("(%s) opening basedir stream\n", __location__); + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; + io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; + io.ntcreatex.in.share_access = 0; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = basedir_data; + status = smb_raw_open(cli->tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY); + + printf("(%s) opening basedir ::$DATA stream\n", __location__); + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.flags = 0x10; + io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.file_attr = 0; + io.ntcreatex.in.share_access = 0; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = basedir_data; + status = smb_raw_open(cli->tree, mem_ctx, &io); + if (torture_setting_bool(tctx, "samba3", false)) { + CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); + } else { + CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY); + } + + printf("(%s) list the streams on the basedir\n", __location__); + ret &= check_stream_list(cli, BASEDIR, 0, NULL); +done: + return ret; +} + +/* + test basic behavior of streams on directories */ static bool test_stream_io(struct torture_context *tctx, struct smbcli_state *cli, TALLOC_CTX *mem_ctx) @@ -191,12 +270,12 @@ static bool test_stream_io(struct torture_context *tctx, sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One"); sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "Second Stream"); - printf("(%s) opening non-existant directory stream\n", __location__); + printf("(%s) creating a stream on a non-existant file\n", __location__); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; - io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.ntcreatex.in.create_options = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; io.ntcreatex.in.share_access = 0; io.ntcreatex.in.alloc_size = 0; @@ -205,12 +284,6 @@ static bool test_stream_io(struct torture_context *tctx, io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.fname = sname1; status = smb_raw_open(cli->tree, mem_ctx, &io); - CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY); - - printf("(%s) creating a stream on a non-existant file\n", __location__); - io.ntcreatex.in.create_options = 0; - io.ntcreatex.in.fname = sname1; - status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); fnum = io.ntcreatex.out.file.fnum; @@ -423,7 +496,7 @@ static bool test_stream_delete(struct torture_context *tctx, sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One"); - printf("(%s) opening non-existant directory stream\n", __location__); + printf("(%s) opening non-existant file stream\n", __location__); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; @@ -559,6 +632,8 @@ bool torture_raw_streams(struct torture_context *torture, return false; } + ret &= test_stream_dir(torture, cli, torture); + smb_raw_exit(cli->session); ret &= test_stream_io(torture, cli, torture); smb_raw_exit(cli->session); ret &= test_stream_sharemodes(torture, cli, torture); diff --git a/source4/torture/raw/tconrate.c b/source4/torture/raw/tconrate.c new file mode 100644 index 0000000000..6f0ba0d617 --- /dev/null +++ b/source4/torture/raw/tconrate.c @@ -0,0 +1,201 @@ +/* + SMB tree connection rate test + + Copyright (C) 2006-2007 James Peach + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/libcli.h" +#include "libcli/resolve/resolve.h" +#include "torture/smbtorture.h" +#include "lib/cmdline/popt_common.h" +#include "param/param.h" + +#include "system/filesys.h" +#include "system/shmem.h" + +#define TIME_LIMIT_SECS 30 +#define usec_to_sec(s) ((s) / 1000000) +#define sec_to_usec(s) ((s) * 1000000) + +/* Map a shared memory buffer of at least nelem counters. */ +static void * map_count_buffer(unsigned nelem, size_t elemsz) +{ + void * buf; + size_t bufsz; + size_t pagesz = getpagesize(); + + bufsz = nelem * elemsz; + bufsz = (bufsz + pagesz) % pagesz; /* round up to pagesz */ + +#ifdef MAP_ANON + /* BSD */ + buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, + -1 /* fd */, 0 /* offset */); +#else + buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, + open("/dev/zero", O_RDWR), 0 /* offset */); +#endif + + if (buf == MAP_FAILED) { + printf("failed to map count buffer: %s\n", + strerror(errno)); + return NULL; + } + + return buf; + +} + +static int fork_tcon_client(struct torture_context *tctx, + int *tcon_count, unsigned tcon_timelimit, + const char *host, const char *share) +{ + pid_t child; + struct smbcli_state *cli; + struct timeval end; + struct timeval now; + struct smbcli_options options; + + lp_smbcli_options(tctx->lp_ctx, &options); + + child = fork(); + if (child == -1) { + printf("failed to fork child: %s\n,", strerror(errno)); + return -1; + } else if (child != 0) { + /* Parent, just return. */ + return 0; + } + + /* Child. Just make as many connections as possible within the + * time limit. Don't bother synchronising the child start times + * because it's probably not work the effort, and a bit of startup + * jitter is probably a more realistic test. + */ + + + end = timeval_current(); + now = timeval_current(); + end.tv_sec += tcon_timelimit; + *tcon_count = 0; + + while (timeval_compare(&now, &end) == -1) { + NTSTATUS status; + + status = smbcli_full_connection(NULL, &cli, + host, lp_smb_ports(tctx->lp_ctx), share, + NULL, cmdline_credentials, + lp_resolve_context(tctx->lp_ctx), + tctx->ev, &options); + + if (!NT_STATUS_IS_OK(status)) { + printf("failed to connect to //%s/%s: %s\n", + host, share, nt_errstr(status)); + goto done; + } + + smbcli_tdis(cli); + + *tcon_count = *tcon_count + 1; + now = timeval_current(); + } + +done: + exit(0); +} + +static bool children_remain(void) +{ + /* Reap as many children as possible. */ + for (;;) { + pid_t ret = waitpid(-1, NULL, WNOHANG); + if (ret == 0) { + /* no children ready */ + return true; + } + if (ret == -1) { + /* no children left. maybe */ + return errno == ECHILD ? false : true; + } + } + + /* notreached */ + return false; +} + +static double rate_convert_secs(unsigned count, + const struct timeval *start, const struct timeval *end) +{ + return (double)count / + usec_to_sec((double)usec_time_diff(end, start)); +} + +/* Test the rate at which the server will accept connections. */ +bool torture_bench_treeconnect(struct torture_context *tctx) +{ + const char *host = torture_setting_string(tctx, "host", NULL); + const char *share = torture_setting_string(tctx, "share", NULL); + + int timelimit = torture_setting_int(tctx, "timelimit", + TIME_LIMIT_SECS); + int nprocs = torture_setting_int(tctx, "nprocs", 4); + + int *curr_counts = map_count_buffer(nprocs, sizeof(int)); + int *last_counts = talloc_array(NULL, int, nprocs); + + struct timeval now, last, start; + int i, delta; + + torture_assert(tctx, nprocs > 0, "bad proc count"); + torture_assert(tctx, timelimit > 0, "bad timelimit"); + torture_assert(tctx, curr_counts, "allocation failure"); + torture_assert(tctx, last_counts, "allocation failure"); + + start = last = timeval_current(); + for (i = 0; i < nprocs; ++i) { + fork_tcon_client(tctx, &curr_counts[i], timelimit, host, share); + } + + while (children_remain()) { + + sleep(1); + now = timeval_current(); + + for (i = 0, delta = 0; i < nprocs; ++i) { + delta += curr_counts[i] - last_counts[i]; + } + + printf("%u connections/sec\n", + (unsigned)rate_convert_secs(delta, &last, &now)); + + memcpy(last_counts, curr_counts, nprocs * sizeof(int)); + last = timeval_current(); + } + + now = timeval_current(); + + for (i = 0, delta = 0; i < nprocs; ++i) { + delta += curr_counts[i]; + } + + printf("TOTAL: %u connections/sec over %u secs\n", + (unsigned)rate_convert_secs(delta, &start, &now), + timelimit); + return true; +} + +/* vim: set sts=8 sw=8 : */ |