Add CI stat/create/unlink test for multiple directory forms

Merge of master-melb:xfs-cmds:31347a by kenmcd.

  Add genhashnames target
This commit is contained in:
Barry Naujok
2008-06-24 16:29:51 +00:00
parent 36763daef8
commit 2c8dbd49c8
3 changed files with 226 additions and 20 deletions
+4 -1
View File
@@ -10,7 +10,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
mmapcat append_reader append_writer dirperf metaperf \
devzero feature alloc fault fstest t_access_root \
godown resvtest writemod makeextents itrash \
multi_open_unlink dmiperf unwritten_sync
multi_open_unlink dmiperf unwritten_sync genhashnames
LINUX_TARGETS = loggen xfsctl bstat t_mtab getdevicesize \
preallo_rw_pattern_reader preallo_rw_pattern_writer ftrunc trunc \
@@ -52,6 +52,9 @@ truncfile: truncfile.o $(LIBTEST)
dbtest: dbtest.o $(LIBTEST)
$(LINKTEST) $(LIBTEST) $(LIBGDBM) $(LDLIBS)
genhashnames: genhashnames.o
$(LINKTEST)
nametest: nametest.o $(LIBTEST)
$(LINKTEST) $(LIBTEST) $(LDLIBS)
+179
View File
@@ -0,0 +1,179 @@
/*
* Creates a bunch of files in the specified directory with the same
* hashvalue on-disk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <xfs/libxfs.h>
#define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
/*
* Implement a simple hash on a character string.
* Rotate the hash value by 7 bits, then XOR each character in.
* This is implemented with some source-level loop unrolling.
*/
static uint32_t xfs_da_hashname(const char *name, int namelen)
{
uint32_t hash;
/*
* Do four characters at a time as long as we can.
*/
for (hash = 0; namelen >= 4; namelen -= 4, name += 4)
hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
(name[3] << 0) ^ rol32(hash, 7 * 4);
/*
* Now do the rest of the characters.
*/
switch (namelen) {
case 3:
return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
rol32(hash, 7 * 3);
case 2:
return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
case 1:
return (name[0] << 0) ^ rol32(hash, 7 * 1);
default: /* case 0: */
return hash;
}
}
static int is_invalid_char(char c)
{
return (c <= ' ' || c > '~' || c == '/' || (c >= 'A' && c <= 'Z'));
}
static char random_char(void)
{
char c;
/* get a character of "0"-"9" or "a"-"z" */
c = lrand48() % 36;
return (c >= 10) ? c + 87 : c + 48;
}
static int generate_names(const char *path, long amount, uint32_t desired_hash)
{
char **names;
char fullpath[PATH_MAX];
char *filename;
long count;
long i;
uint32_t base_hash;
uint32_t hash;
names = malloc(amount * sizeof(char *));
if (!names) {
fprintf(stderr, "genhashnames: malloc(%lu) failed!\n",
amount * sizeof(char *));
return 1;
}
strcpy(fullpath, path);
filename = fullpath + strlen(fullpath);
if (filename[-1] != '/')
*filename++ = '/';
for (count = 0; count < amount; count++) {
for (;;) {
base_hash = 0;
for (i = 0; i < 6; i++) {
filename[i] = random_char();
base_hash = filename[i] ^ rol32(base_hash, 7);
}
while (i < 200) {
filename[i] = random_char();
base_hash = filename[i] ^ rol32(base_hash, 7);
i++;
hash = rol32(base_hash, 3) ^ desired_hash;
filename[i] = (hash >> 28) |
(random_char() & 0xf0);
if (is_invalid_char(filename[i]))
continue;
filename[i + 1] = (hash >> 21) & 0x7f;
if (is_invalid_char(filename[i + 1]))
continue;
filename[i + 2] = (hash >> 14) & 0x7f;
if (is_invalid_char(filename[i + 2]))
continue;
filename[i + 3] = (hash >> 7) & 0x7f;
if (is_invalid_char(filename[i + 3]))
continue;
filename[i + 4] = (hash ^ (filename[i] >> 4))
& 0x7f;
if (is_invalid_char(filename[i + 4]))
continue;
break;
}
if (i < NAME_MAX)
break;
}
filename[i + 5] = '\0';
if (xfs_da_hashname(filename, i + 5) != desired_hash) {
fprintf(stderr, "genhashnames: Hash mismatch!\n");
return 1;
}
for (i = 0; i < count; i++) {
if (strcmp(fullpath, names[i]) == 0)
break;
}
if (i == count) {
names[count] = strdup(fullpath);
puts(fullpath);
} else
count--;
}
return 0;
}
static void usage(void)
{
fprintf(stderr, "Usage: genhashnames <directory> <amount> "
"[seed] [hashvalue]\n");
exit(1);
}
int main(int argc, char **argv)
{
long seed;
uint32_t desired_hash;
if (argc < 3 || argc > 5)
usage();
if (argc >= 4)
seed = strtol(argv[3], NULL, 0);
else {
struct timeval tv;
gettimeofday(&tv, NULL);
seed = tv.tv_usec / 1000 + (tv.tv_sec % 1000) * 1000;
}
srand48(seed);
/*
* always generate hash from random so if hash is specified, random
* sequence is the same as a randomly generated hash of the same value.
*/
desired_hash = (uint32_t)mrand48();
if (argc >= 5)
desired_hash = (uint32_t)strtoul(argv[4], NULL, 0);
fprintf(stderr, "seed = %ld, hash = 0x%08x\n", seed, desired_hash);
return generate_names(argv[1], strtol(argv[2], NULL, 0), desired_hash);
}
+43 -19
View File
@@ -15,7 +15,7 @@
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "global.h"
/*
@@ -25,21 +25,21 @@
*
* Given an input file of a list of filenames (one per line)
* It does a number of iterations of operations
* chosen pseudo-randomly in certain percentages:
* creating (open),
* deleting (unlink) and
* chosen pseudo-randomly in certain percentages:
* creating (open),
* deleting (unlink) and
* looking up (stat)
* on a pseudo-randomly chosen filename (from input file).
* on a pseudo-randomly chosen filename (from input file).
*
* The percentage thresholds for operation selection change
* every <number-of-names> iterations.
* every <number-of-names> iterations.
* e.g.
* If had 100 names then:
* iterations:
* 1-100: pct_remove = 33; pct_create = 33;
* 1-100: pct_remove = 33; pct_create = 33;
* 101-200: pct_remove = 60; pct_create = 20;
* 201-300: pct_remove = 20; pct_create = 60;
* 301-400: pct_remove = 33; pct_create = 33;
* 301-400: pct_remove = 33; pct_create = 33;
* 401-500: pct_remove = 60; pct_create = 20;
* 501-600: pct_remove = 20; pct_create = 60;
* etc...
@@ -53,7 +53,7 @@
*
* The operation is done and any error codes are
* verified considering whether file exists (info.exists)
* or not. The stat(3) call also compares inode number.
* or not. The stat(3) call also compares inode number.
*/
@@ -72,6 +72,7 @@ int good_adds, good_rms, good_looks, good_tot; /* ops that suceeded */
int bad_adds, bad_rms, bad_looks, bad_tot; /* ops that failed */
int verbose;
int mixcase;
int auto_lookup(struct info *);
int auto_create(struct info *);
@@ -82,7 +83,7 @@ void usage(void);
void
usage(void)
{
printf("usage: nametest [-l srcfile] [-i iterations] [-s seed] [-z] [-v]\n");
printf("usage: nametest [-l srcfile] [-i iterations] [-s seed] [-z] [-v] [-c]\n");
exit(1);
}
@@ -96,17 +97,18 @@ main(int argc, char *argv[])
struct info *ip;
int seed, linedots;
linedots = zeroout = verbose = 0;
linedots = zeroout = verbose = mixcase = 0;
seed = (int)time(NULL) % 1000;
iterations = 100000;
sourcefile = "input";
while ((ch = getopt(argc, argv, "l:i:s:zv")) != EOF) {
while ((ch = getopt(argc, argv, "l:i:s:zvc")) != EOF) {
switch (ch) {
case 'l': sourcefile = optarg; break;
case 's': seed = atoi(optarg); break;
case 'i': iterations = atoi(optarg); break;
case 'z': zeroout++; break;
case 'v': verbose++; break;
case 'c': mixcase++; break;
default: usage(); break;
}
}
@@ -137,8 +139,8 @@ main(int argc, char *argv[])
* Allocate space for the info table and fill it in.
*/
/*
* Add up number of lines in file
/*
* Add up number of lines in file
* and replace '\n' by '\0'
*/
totalnames = 0;
@@ -152,14 +154,14 @@ main(int argc, char *argv[])
printf("no names found in input file\n");
return 1;
}
table = (struct info *)calloc(totalnames+1, sizeof(struct info));
if (table == NULL) {
perror("calloc");
return 1;
}
/*
* Copy over names from file (in <table_data>) into name fields
* Copy over names from file (in <table_data>) into name fields
* of info structures in <table>.
*/
ip = table;
@@ -303,13 +305,35 @@ main(int argc, char *argv[])
return 0;
}
char *get_name(struct info *ip)
{
static char path[PATH_MAX];
int i;
char *p;
if (!mixcase)
return ip->name;
/* pick a random character to change case in path */
strcpy(path, ip->name);
p = strrchr(path, '/');
if (!p)
p = path;
p += random() % strlen(p);
if (islower(*p))
*p = toupper(*p);
else
*p = tolower(*p);
return path;
}
int
auto_lookup(struct info *ip)
{
struct stat64 statb;
int retval;
retval = stat64(ip->name, &statb);
retval = stat64(get_name(ip), &statb);
if (retval >= 0) {
good_looks++;
retval = 0;
@@ -352,7 +376,7 @@ auto_create(struct info *ip)
struct stat64 statb;
int retval;
retval = open(ip->name, O_RDWR|O_EXCL|O_CREAT, 0666);
retval = open(get_name(ip), O_RDWR|O_EXCL|O_CREAT, 0666);
if (retval >= 0) {
close(retval);
good_adds++;
@@ -400,7 +424,7 @@ auto_remove(struct info *ip)
{
int retval;
retval = unlink(ip->name);
retval = unlink(get_name(ip));
if (retval >= 0) {
good_rms++;
retval = 0;