]> git.apps.os.sepia.ceph.com Git - xfstests-dev.git/commitdiff
Add CI stat/create/unlink test for multiple directory forms
authorBarry Naujok <bnaujok@sgi.com>
Tue, 24 Jun 2008 16:29:51 +0000 (16:29 +0000)
committerBarry Naujok <bnaujok@sgi.com>
Tue, 24 Jun 2008 16:29:51 +0000 (16:29 +0000)
Merge of master-melb:xfs-cmds:31347a by kenmcd.

  Add genhashnames target

src/Makefile
src/genhashnames.c [new file with mode: 0644]
src/nametest.c

index fa181657d2f9492b47934a6410285413212fab81..ee792739d63ce8e57395caaf442e7dbaef2eef9e 100644 (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)
 
diff --git a/src/genhashnames.c b/src/genhashnames.c
new file mode 100644 (file)
index 0000000..1280179
--- /dev/null
@@ -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);
+}
index 3536c9b862825fb97d684a6ebc8462523f03c2c9..1f11447546ad1a16f0a0d3b3cfd7cbd9bfbe635b 100644 (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"
 
 /*
  *
  * 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;