summaryrefslogtreecommitdiff
path: root/source4/torture/raw
diff options
context:
space:
mode:
Diffstat (limited to 'source4/torture/raw')
-rw-r--r--source4/torture/raw/composite.c4
-rw-r--r--source4/torture/raw/lockbench.c9
-rw-r--r--source4/torture/raw/lookuprate.c320
-rw-r--r--source4/torture/raw/offline.c13
-rw-r--r--source4/torture/raw/open.c10
-rw-r--r--source4/torture/raw/openbench.c9
-rw-r--r--source4/torture/raw/oplock.c3
-rw-r--r--source4/torture/raw/raw.c8
-rw-r--r--source4/torture/raw/samba3hide.c2
-rw-r--r--source4/torture/raw/samba3misc.c2
-rw-r--r--source4/torture/raw/streams.c95
-rw-r--r--source4/torture/raw/tconrate.c201
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 : */