xfs
[Top] [All Lists]

[PATCH, RFC] xfstests: add d_type checking to fsstress

To: xfs-oss <xfs@xxxxxxxxxxx>
Subject: [PATCH, RFC] xfstests: add d_type checking to fsstress
From: Eric Sandeen <sandeen@xxxxxxxxxx>
Date: Mon, 16 Sep 2013 16:55:28 -0500
Delivered-to: xfs@xxxxxxxxxxx
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20130801 Thunderbird/17.0.8
This patch adds a "-D" switch to fsstress so that every time
we call readdir, we stat the dentry & compare it's st_mode
to the d_type.

If -D is specified only once, it ignores DT_UNKNOWN.  If specified
twice, it considers DT_UNKNOWN to be an error.

It skips paths of "./." and "./.." so that we only look at files
newly created within the filesystem.

This could be used in an xfstest; it's noisy on a failures so
would break expected output.

Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx>
---

fsstress doesn't usually do validation, but it's such a handy
framework for creating a ton of random files, this seems like
an ok place to put it.  What do folks think?


diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index 5d5611f..711ea9a 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -246,6 +246,7 @@ int         rtpct;
 unsigned long  seed = 0;
 ino_t          top_ino;
 int            verbose = 0;
+int            verify_d_type = 0;
 sig_atomic_t   should_stop = 0;
 char           *execute_cmd = NULL;
 int            execute_freq = 1;
@@ -315,7 +316,7 @@ int main(int argc, char **argv)
        int             nousage = 0;
        xfs_error_injection_t           err_inj;
        struct sigaction action;
-       const char      *allopts = "d:e:f:i:m:M:n:o:p:rs:S:vwx:X:zH";
+       const char      *allopts = "d:De:f:i:m:M:n:o:p:rs:S:vwx:X:zH";
 
        errrange = errtag = 0;
        umask(0);
@@ -327,6 +328,9 @@ int main(int argc, char **argv)
                case 'd':
                        dirname = optarg;
                        break;
+               case 'D':
+                       verify_d_type++;
+                       break;
                case 'e':
                        sscanf(optarg, "%d", &errtag);
                        if (errtag < 0) {
@@ -1491,6 +1495,7 @@ usage(void)
        printf("          [-p nproc][-r len][-s seed][-v][-w][-x 
cmd][-z][-S][-X ncmd]\n");
        printf("where\n");
        printf("   -d dir           specifies the base directory for 
operations\n");
+       printf("   -D               verify d_type in any readdir operations, 2x 
to disallow DT_UNKNOWN\n");
        printf("   -e errtg         specifies error injection stuff\n");
        printf("   -f op_name=freq  changes the frequency of option name to 
freq\n");
        printf("                    the valid operation names are:\n");
@@ -2338,12 +2343,71 @@ getattr_f(int opno, long r)
        close(fd);
 }
 
+void test_d_type(int opno, pathname_t *f, struct dirent64 *de)
+{
+       struct stat64 sb;
+       char path[PATH_MAX];
+
+       snprintf(path, PATH_MAX, "%s/%s", f->path, de->d_name);
+
+       /* Don't check ./. or ./.. */
+       if (!strncmp(path, "./.", 3))
+               return;
+
+       if (lstat64(path, &sb)) {
+               printf("%d/%d: getdents - can't stat %s\n",
+                       procid, opno, path);
+       } else {
+               int bad_d_type = 0;
+
+               switch (de->d_type) {
+                       case DT_BLK:
+                               if (!S_ISBLK(sb.st_mode))
+                                       bad_d_type++;
+                               break;
+                       case DT_CHR:
+                               if (!S_ISCHR(sb.st_mode))
+                                       bad_d_type++;
+                               break;
+                       case DT_DIR:
+                               if (!S_ISDIR(sb.st_mode))
+                                       bad_d_type++;
+                               break;
+                       case DT_FIFO:
+                               if (!S_ISFIFO(sb.st_mode))
+                                       bad_d_type++;
+                               break;
+                       case DT_LNK:
+                               if (!S_ISLNK(sb.st_mode))
+                                       bad_d_type++;
+                               break;
+                       case DT_REG:
+                               if (!S_ISREG(sb.st_mode))
+                                       bad_d_type++;
+                               break;
+                       case DT_SOCK:
+                               if (!S_ISSOCK(sb.st_mode))
+                                       bad_d_type++;
+                               break;
+                       case DT_UNKNOWN:
+                               if (verify_d_type > 1)
+                                       bad_d_type++;
+                       break;
+               }
+               if (bad_d_type)
+                       printf("%d/%d: getdents - bad d_type %d for %s\n",
+                               procid, opno, de->d_type, path);
+                       
+       }
+}
+
 void
 getdents_f(int opno, long r)
 {
        DIR             *dir;
        pathname_t      f;
        int             v;
+       struct dirent64 *de;
 
        init_pathname(&f);
        if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
@@ -2357,8 +2421,11 @@ getdents_f(int opno, long r)
                free_pathname(&f);
                return;
        }
-       while (readdir64(dir) != NULL)
+       while ((de = readdir64(dir)) != NULL) {
+               if (verify_d_type)
+                       test_d_type(opno, &f, de);
                continue;
+       }
        if (v)
                printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
        free_pathname(&f);


<Prev in Thread] Current Thread [Next in Thread>