Merge of master-melb:xfs-cmds:31347a by kenmcd.
Add genhashnames target
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 \
dbtest: dbtest.o $(LIBTEST)
$(LINKTEST) $(LIBTEST) $(LIBGDBM) $(LDLIBS)
+genhashnames: genhashnames.o
+ $(LINKTEST)
+
nametest: nametest.o $(LIBTEST)
$(LINKTEST) $(LIBTEST) $(LDLIBS)
--- /dev/null
+/*
+ * 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);
+}
* 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"
/*
*
* 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...
*
* 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.
*/
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 *);
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);
}
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;
}
}
* 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;
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;
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;
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++;
{
int retval;
- retval = unlink(ip->name);
+ retval = unlink(get_name(ip));
if (retval >= 0) {
good_rms++;
retval = 0;